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