Kitty Graphics Protocol in OCaml
terminal graphics ocaml
at main 3.7 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** Animation Control 7 8 Operations for controlling animation playback. The protocol supports both 9 terminal-driven and client-driven animation modes. 10 11 {2 Protocol Overview} 12 13 Animation control uses action [a=a] with various keys: 14 - [s]: Set playback state (1=stop, 2=loading, 3=run) 15 - [c]: Set current frame (1-based frame number) 16 - [r]: Target frame number for gap changes 17 - [z]: Frame gap/delay in milliseconds 18 - [v]: Loop count 19 20 {2 Terminal-Driven Animation} 21 22 The terminal automatically advances frames based on each frame's gap 23 (delay). To start terminal-driven animation: 24 25 {[ 26 (* Start infinite loop *) 27 Kgp.animate ~image_id:1 28 (Animation.set_state ~loops:1 `Run) 29 (* Run 3 times then stop *) 30 Kgp.animate ~image_id:1 31 (Animation.set_state ~loops:4 `Run) 32 (* Stop animation *) 33 Kgp.animate ~image_id:1 34 (Animation.set_state `Stop) 35 ]} 36 37 {2 Client-Driven Animation} 38 39 The client manually controls which frame is displayed: 40 41 {[ 42 (* Display specific frame *) 43 Kgp.animate ~image_id:1 (Animation.set_current_frame 5) 44 45 (* Advance to next frame in application logic *) 46 let next_frame = (current_frame mod total_frames) + 1 in 47 Kgp.animate ~image_id:1 (Animation.set_current_frame next_frame) 48 ]} 49 50 {2 Modifying Frame Timing} 51 52 Frame gaps can be changed during playback: 53 54 {[ 55 (* Slow down frame 3 *) 56 Kgp.animate ~image_id:1 57 (Animation.set_gap ~frame:3 ~gap_ms:200) 58 (* Make frame 5 instant/gapless *) 59 Kgp.animate ~image_id:1 60 (Animation.set_gap ~frame:5 ~gap_ms:(-1)) 61 ]} 62 63 {2 Loop Counting} 64 65 The [loops] parameter in {!set_state}: 66 - 0: Ignored (doesn't change loop setting) 67 - 1: Infinite loop 68 - n > 1: Loop (n-1) times, then stop *) 69 70type t = 71 [ `Set_state of Kgp_animation_state.t * int option 72 | `Set_gap of int * int 73 | `Set_current of int ] 74(** Animation control operations. 75 76 - [`Set_state (state, loops)] - Set animation playback state with optional 77 loop count. 78 - [`Set_gap (frame, gap_ms)] - Set the delay for a specific frame. 79 - [`Set_current frame] - Jump to a specific frame (1-based). *) 80 81val set_state : ?loops:int -> Kgp_animation_state.t -> t 82(** Set animation playback state. 83 84 @param loops 85 Loop count: 0 = ignored, 1 = infinite, n > 1 = (n-1) loops. Protocol key: 86 [v]. 87 @param state The target playback state. 88 89 Examples: 90 {[ 91 set_state `Run (* Run with current loop setting *) set_state ~loops:1 `Run 92 (* Run infinitely *) set_state ~loops:3 `Run 93 (* Run twice, then stop *) set_state `Stop (* Pause animation *) 94 set_state `Loading (* Run, wait for more frames at end *) 95 ]} *) 96 97val set_gap : frame:int -> gap_ms:int -> t 98(** Set the gap (delay) for a specific frame. 99 100 @param frame 1-based frame number to modify. Protocol key: [r]. 101 @param gap_ms 102 Delay in milliseconds before next frame. Negative values create gapless 103 frames (not displayed, instant skip). Protocol key: [z]. 104 105 Note: Frame 1 is the root/base image. Use 2+ for added frames. *) 106 107val set_current_frame : int -> t 108(** Make a specific frame the current displayed frame. 109 110 @param frame 1-based frame number to display. Protocol key: [c]. 111 112 Used for client-driven animation where the application controls frame 113 advancement rather than the terminal. *)