(* Kitty Graphics Protocol Demo - Matching kgp/examples/demo *) module K = Kgp (* Helper: Generate a solid color RGBA image *) let solid_color_rgba ~width ~height ~r ~g ~b ~a = let pixels = Bytes.create (width * height * 4) in for i = 0 to (width * height) - 1 do let idx = i * 4 in Bytes.set pixels idx (Char.chr r); Bytes.set pixels (idx + 1) (Char.chr g); Bytes.set pixels (idx + 2) (Char.chr b); Bytes.set pixels (idx + 3) (Char.chr a) done; Bytes.to_string pixels (* Helper: Generate a solid color RGB image (no alpha) *) let solid_color_rgb ~width ~height ~r ~g ~b = let pixels = Bytes.create (width * height * 3) in for i = 0 to (width * height) - 1 do let idx = i * 3 in Bytes.set pixels idx (Char.chr r); Bytes.set pixels (idx + 1) (Char.chr g); Bytes.set pixels (idx + 2) (Char.chr b) done; Bytes.to_string pixels (* Helper: Generate a gradient RGBA image *) let gradient_rgba ~width ~height = let pixels = Bytes.create (width * height * 4) in for y = 0 to height - 1 do for x = 0 to width - 1 do let idx = (y * width + x) * 4 in let r = 255 * x / width in let b = 255 * (width - x) / width in Bytes.set pixels idx (Char.chr r); Bytes.set pixels (idx + 1) (Char.chr 128); Bytes.set pixels (idx + 2) (Char.chr b); Bytes.set pixels (idx + 3) '\xff' done done; Bytes.to_string pixels (* Helper: Read a file *) let read_file filename = let ic = open_in_bin filename in let n = in_channel_length ic in let s = really_input_string ic n in close_in ic; s let send cmd ~data = print_string (K.Command.to_string cmd ~data); flush stdout let wait_for_enter () = print_string "Press Enter to continue..."; flush stdout; let _ = read_line () in print_newline () let clear_screen () = print_string "\x1b[2J\x1b[H"; for _ = 1 to 5 do print_newline () done; flush stdout let () = let reader = stdin in ignore reader; clear_screen (); print_endline "Kitty Graphics Protocol - OCaml Demo"; print_endline "====================================="; print_newline (); print_endline "Press Enter to proceed through each demo..."; print_newline (); (* Demo 1: Basic formats - PNG *) clear_screen (); print_endline "Demo 1: Image Formats - PNG format"; (* Read sf.png and display a small portion as demo *) (try let png_data = read_file "sf.png" in send (K.Command.transmit_and_display ~image_id:1 ~format:`Png ~quiet:`Errors_only ~placement:(K.Placement.make ~columns:15 ~rows:8 ()) ()) ~data:png_data; print_endline "sf.png displayed using PNG format" with _ -> (* Fallback: red square as RGBA *) let red_data = solid_color_rgba ~width:100 ~height:100 ~r:255 ~g:0 ~b:0 ~a:255 in send (K.Command.transmit_and_display ~image_id:1 ~format:`Rgba32 ~width:100 ~height:100 ~quiet:`Errors_only ()) ~data:red_data; print_endline "Red square displayed (sf.png not found)"); print_newline (); wait_for_enter (); (* Demo 2: Basic formats - RGBA *) clear_screen (); print_endline "Demo 2: Image Formats - RGBA format (32-bit)"; let blue_data = solid_color_rgba ~width:100 ~height:100 ~r:0 ~g:0 ~b:255 ~a:255 in send (K.Command.transmit_and_display ~image_id:2 ~format:`Rgba32 ~width:100 ~height:100 ~quiet:`Errors_only ()) ~data:blue_data; print_endline "Blue square displayed using raw RGBA format"; print_newline (); wait_for_enter (); (* Demo 3: Basic formats - RGB *) clear_screen (); print_endline "Demo 3: Image Formats - RGB format (24-bit)"; let green_data = solid_color_rgb ~width:100 ~height:100 ~r:0 ~g:255 ~b:0 in send (K.Command.transmit_and_display ~image_id:3 ~format:`Rgb24 ~width:100 ~height:100 ~quiet:`Errors_only ()) ~data:green_data; print_endline "Green square displayed using raw RGB format (no alpha channel)"; print_newline (); wait_for_enter (); (* Demo 4: Compression - Note: would need zlib library for actual compression *) clear_screen (); print_endline "Demo 4: Large Image (compression requires zlib library)"; let orange_data = solid_color_rgba ~width:200 ~height:200 ~r:255 ~g:165 ~b:0 ~a:255 in send (K.Command.transmit_and_display ~image_id:4 ~format:`Rgba32 ~width:200 ~height:200 ~quiet:`Errors_only ()) ~data:orange_data; Printf.printf "Orange square (200x200) - %d bytes uncompressed\n" (String.length orange_data); print_newline (); wait_for_enter (); (* Demo 5: Load and display external PNG file *) clear_screen (); print_endline "Demo 5: Loading external PNG file (sf.png)"; (try let png_data = read_file "sf.png" in send (K.Command.transmit_and_display ~image_id:10 ~format:`Png ~quiet:`Errors_only ()) ~data:png_data; print_endline "sf.png loaded and displayed" with Sys_error msg -> Printf.printf "sf.png not found: %s\n" msg); print_newline (); wait_for_enter (); (* Demo 6: Cropping and scaling *) clear_screen (); print_endline "Demo 6: Cropping and Scaling - Display part of an image"; let gradient = gradient_rgba ~width:200 ~height:200 in send (K.Command.transmit_and_display ~image_id:20 ~format:`Rgba32 ~width:200 ~height:200 ~placement:(K.Placement.make ~source_x:50 ~source_y:50 ~source_width:100 ~source_height:100 ~columns:10 ~rows:10 ()) ~quiet:`Errors_only ()) ~data:gradient; print_endline "Cropped to center 100x100 region of a 200x200 gradient"; print_newline (); wait_for_enter (); (* Demo 7: Multiple placements *) clear_screen (); print_endline "Demo 7: Multiple Placements - One image, multiple displays"; let cyan_data = solid_color_rgba ~width:80 ~height:80 ~r:0 ~g:255 ~b:255 ~a:255 in (* Transmit once with an ID *) send (K.Command.transmit ~image_id:100 ~format:`Rgba32 ~width:80 ~height:80 ~quiet:`Errors_only ()) ~data:cyan_data; (* Create first placement *) send (K.Command.display ~image_id:100 ~placement:(K.Placement.make ~columns:10 ~rows:5 ()) ~quiet:`Errors_only ()) ~data:""; (* Create second placement *) send (K.Command.display ~image_id:100 ~placement:(K.Placement.make ~columns:5 ~rows:3 ()) ~quiet:`Errors_only ()) ~data:""; print_newline (); wait_for_enter (); (* Demo 8: Multiple placements with spacing *) clear_screen (); print_endline "Demo 8: Multiple Placements with Different Sizes"; print_newline (); print_endline "Showing same image at different sizes:"; print_newline (); (* Create a gradient square *) let grad_small = gradient_rgba ~width:100 ~height:100 in (* Transmit once *) send (K.Command.transmit ~image_id:160 ~format:`Rgba32 ~width:100 ~height:100 ~quiet:`Errors_only ()) ~data:grad_small; (* Place same image three times at different sizes *) send (K.Command.display ~image_id:160 ~placement:(K.Placement.make ~columns:5 ~rows:5 ()) ~quiet:`Errors_only ()) ~data:""; print_string " "; send (K.Command.display ~image_id:160 ~placement:(K.Placement.make ~columns:8 ~rows:8 ()) ~quiet:`Errors_only ()) ~data:""; print_string " "; send (K.Command.display ~image_id:160 ~placement:(K.Placement.make ~columns:12 ~rows:12 ()) ~quiet:`Errors_only ()) ~data:""; print_newline (); print_newline (); print_endline "Small (5x5 cells), Medium (8x8 cells), Large (12x12 cells)"; print_newline (); wait_for_enter (); (* Demo 9: Z-index layering *) clear_screen (); print_endline "Demo 9: Z-Index Layering - Images above/below text"; let bg_data = solid_color_rgba ~width:200 ~height:100 ~r:255 ~g:165 ~b:0 ~a:128 in send (K.Command.transmit_and_display ~image_id:200 ~format:`Rgba32 ~width:200 ~height:100 ~placement:(K.Placement.make ~z_index:(-1) ~cursor:`Static ()) ~quiet:`Errors_only ()) ~data:bg_data; print_endline "This orange square should appear behind the text!"; print_newline (); wait_for_enter (); (* Demo 10: Query support *) clear_screen (); print_endline "Demo 10: Query Support - Check terminal capabilities"; let query_str = K.Detect.make_query () in print_string query_str; flush stdout; print_endline "(Check if your terminal responds with OK)"; print_newline (); wait_for_enter (); (* Demo 11: Animation - color-changing square *) clear_screen (); print_endline "Demo 11: Animation - Color-changing square"; print_endline "Creating animated sequence with 4 colors..."; let width, height = 80, 80 in let image_id = 300 in (* Create base frame (red) - transmit without displaying *) let red_frame = solid_color_rgba ~width ~height ~r:255 ~g:0 ~b:0 ~a:255 in send (K.Command.transmit ~image_id ~format:`Rgba32 ~width ~height ~quiet:`Errors_only ()) ~data:red_frame; (* Add frames with composition replace *) let orange_frame = solid_color_rgba ~width ~height ~r:255 ~g:165 ~b:0 ~a:255 in send (K.Command.frame ~image_id ~format:`Rgba32 ~width ~height ~frame:(K.Frame.make ~gap_ms:100 ~composition:`Overwrite ()) ~quiet:`Errors_only ()) ~data:orange_frame; let yellow_frame = solid_color_rgba ~width ~height ~r:255 ~g:255 ~b:0 ~a:255 in send (K.Command.frame ~image_id ~format:`Rgba32 ~width ~height ~frame:(K.Frame.make ~gap_ms:100 ~composition:`Overwrite ()) ~quiet:`Errors_only ()) ~data:yellow_frame; let green_frame = solid_color_rgba ~width ~height ~r:0 ~g:255 ~b:0 ~a:255 in send (K.Command.frame ~image_id ~format:`Rgba32 ~width ~height ~frame:(K.Frame.make ~gap_ms:100 ~composition:`Overwrite ()) ~quiet:`Errors_only ()) ~data:green_frame; (* Create placement and start animation *) send (K.Command.display ~image_id ~placement:(K.Placement.make ~placement_id:1 ~cell_x_offset:0 ~cell_y_offset:0 ~cursor:`Static ()) ~quiet:`Errors_only ()) ~data:""; (* Set root frame gap - root frame has no gap by default per Kitty protocol *) send (K.Command.animate ~image_id (K.Animation.set_gap ~frame:1 ~gap_ms:100)) ~data:""; (* Start animation with infinite looping *) send (K.Command.animate ~image_id (K.Animation.set_state ~loops:1 `Run)) ~data:""; print_newline (); print_endline "Animation playing with colors: Red -> Orange -> Yellow -> Green"; print_newline (); (* Simulate movement by deleting and recreating placement at different positions *) for i = 1 to 7 do Unix.sleepf 0.4; (* Delete the current placement *) send (K.Command.delete ~quiet:`Errors_only (`By_id (image_id, Some 1))) ~data:""; (* Create new placement at next position *) send (K.Command.display ~image_id ~placement:(K.Placement.make ~placement_id:1 ~cell_x_offset:(i * 5) ~cell_y_offset:0 ~cursor:`Static ()) ~quiet:`Errors_only ()) ~data:"" done; (* Stop the animation *) send (K.Command.animate ~image_id (K.Animation.set_state `Stop)) ~data:""; print_endline "Animation stopped."; print_newline (); print_newline (); print_endline "Demo complete!"; print_newline (); print_endline "For more examples, see the library documentation."; wait_for_enter ()