Kitty Graphics Protocol in OCaml
terminal graphics ocaml
at main 3.0 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(* Tiny animation test - no chunking needed *) 7(* Uses 20x20 images which are ~1067 bytes base64 (well under 4096) *) 8 9module K = Kgp 10 11let solid_color_rgba ~width ~height ~r ~g ~b ~a = 12 let pixels = Bytes.create (width * height * 4) in 13 for i = 0 to (width * height) - 1 do 14 let idx = i * 4 in 15 Bytes.set pixels idx (Char.chr r); 16 Bytes.set pixels (idx + 1) (Char.chr g); 17 Bytes.set pixels (idx + 2) (Char.chr b); 18 Bytes.set pixels (idx + 3) (Char.chr a) 19 done; 20 Bytes.to_string pixels 21 22let send cmd ~data = 23 print_string (K.to_string cmd ~data); 24 flush stdout 25 26let () = 27 (* Use 20x20 to avoid chunking: 20*20*4 = 1600 bytes, base64 ~2134 bytes *) 28 let width, height = (20, 20) in 29 let image_id = 999 in 30 31 (* Clear any existing images *) 32 send (K.delete ~free:true ~quiet:`Errors_only `All_visible) ~data:""; 33 34 (* Step 1: Transmit base frame (red) *) 35 let red_frame = solid_color_rgba ~width ~height ~r:255 ~g:0 ~b:0 ~a:255 in 36 send 37 (K.transmit ~image_id ~format:`Rgba32 ~width ~height ~quiet:`Errors_only ()) 38 ~data:red_frame; 39 40 (* Step 2: Add frame (orange) with 100ms gap *) 41 let orange_frame = 42 solid_color_rgba ~width ~height ~r:255 ~g:165 ~b:0 ~a:255 43 in 44 send 45 (K.frame ~image_id ~format:`Rgba32 ~width ~height 46 ~frame:(K.Frame.make ~gap_ms:100 ~composition:`Overwrite ()) 47 ~quiet:`Errors_only ()) 48 ~data:orange_frame; 49 50 (* Step 3: Add frame (yellow) *) 51 let yellow_frame = 52 solid_color_rgba ~width ~height ~r:255 ~g:255 ~b:0 ~a:255 53 in 54 send 55 (K.frame ~image_id ~format:`Rgba32 ~width ~height 56 ~frame:(K.Frame.make ~gap_ms:100 ~composition:`Overwrite ()) 57 ~quiet:`Errors_only ()) 58 ~data:yellow_frame; 59 60 (* Step 4: Add frame (green) *) 61 let green_frame = solid_color_rgba ~width ~height ~r:0 ~g:255 ~b:0 ~a:255 in 62 send 63 (K.frame ~image_id ~format:`Rgba32 ~width ~height 64 ~frame:(K.Frame.make ~gap_ms:100 ~composition:`Overwrite ()) 65 ~quiet:`Errors_only ()) 66 ~data:green_frame; 67 68 (* Step 5: Create placement *) 69 send 70 (K.display ~image_id 71 ~placement: 72 (K.Placement.make ~placement_id:1 ~cell_x_offset:0 ~cell_y_offset:0 73 ~cursor:`Static ()) 74 ~quiet:`Errors_only ()) 75 ~data:""; 76 77 (* Step 6: Start animation *) 78 send (K.animate ~image_id (K.Animation.set_state ~loops:1 `Run)) ~data:""; 79 80 print_endline ""; 81 print_endline "Tiny animation (20x20) - Red -> Orange -> Yellow -> Green"; 82 print_endline "This uses no chunking. Press Enter to stop..."; 83 flush stdout; 84 let _ = read_line () in 85 86 (* Stop animation *) 87 send (K.animate ~image_id (K.Animation.set_state `Stop)) ~data:""; 88 89 (* Clean up *) 90 send (K.delete ~free:true ~quiet:`Errors_only `All_visible) ~data:""; 91 print_endline "Done."