Skip to content

Recording and Playing Input Replays

The replay feature records and stores human keyboard input operations rather than terminal screen output. During playback, console2svg executes the designated command anew within a PTY, dispatching recorded keystrokes at their scheduled timestamps to recapture the resulting screen display. Unlike asciicast, which simply replays pre-captured terminal output, input replay reproduces the genuine execution of the command itself.

Platform-Independent Representation of Key Semantics

Section titled “Platform-Independent Representation of Key Semantics”

Replay files avoid storing operating system-specific internal structures, such as Windows console event structs or Unix terminal control flags. To enable reliable reproduction across diverse operating systems and keyboard layouts, keystrokes are recorded using an abstracted, platform-agnostic model.

Standard keys are normalized to descriptive names such as ArrowUp, Home, Delete, and F1 through F12, while Shift, Alt, Ctrl, and Meta (Windows or Command key) are maintained as independent modifier flags. Printable characters are preserved as Unicode strings rather than hardware scancodes, with surrogate pairs (16-bit code-unit pairs representing single Unicode characters such as emoji) treated as unified logical keys. For non-standard or raw byte sequences that fall outside the high-level key model, raw events provide direct byte storage.

Each event within a replay file specifies its timing using either an absolute time (seconds from recording onset) or a relative tick (elapsed seconds since the immediately preceding event).

Upon loading the file, events specifying absolute time retain those values directly, while relative tick values are accumulated sequentially onto the running timestamp, normalizing all operations onto a single absolute timeline. File metadata also records the total runtime (duration). Because child processes often remain idling at a shell prompt after all input has been dispatched, console2svg sets the total duration plus 1 second as a safe execution timeout ceiling to cleanly terminate the process.

Stream Chunk Resilience and Escape Sequence Detection

Section titled “Stream Chunk Resilience and Escape Sequence Detection”

During live recording of interactive sessions, raw byte streams received from the host are immediately forwarded to the child process’s PTY. Simultaneously, the parsing pass that translates inputs into the replay model employs a stateful UTF-8 decoder.

Terminal escape sequences transmitted by the keyboard can be split across operating system read boundaries (for example, when an initial ESC byte arrives in one chunk and its trailing CSI parameters arrive in the next). To handle this, incomplete escape sequences are buffered internally and combined with incoming chunks in subsequent reads. This prevents truncated control sequences from being mistakenly recorded as solitary key events (such as an isolated ESC keypress).

Synthesizing VT Byte Sequences from Key Events

Section titled “Synthesizing VT Byte Sequences from Key Events”

During playback, recorded key names and modifier combinations are synthesized back into VT byte sequences (escape sequences) understood by terminal applications.

Standard keys such as Enter, Tab, arrow keys, and function keys emit standard VT control codes. Ctrl-key combinations map to their corresponding ASCII control characters (0x01–0x1A), Alt-key chords are prefixed with an ESC byte, and printable text is encoded into UTF-8 byte arrays. Because the generated byte stream is injected directly into the identical PTY write stream used during interactive capture, the executing process cannot distinguish automated playback from human typing.

The replay stream waits asynchronously until each event reaches its scheduled timestamp before writing the corresponding bytes to the PTY.

However, if processing falls behind the target timeline due to system load or child process blocking, the scheduler dispatches subsequent events immediately without additional sleep. This enables the replay to catch up to its target timeline as quickly as possible while strictly maintaining event ordering. Furthermore, if the byte representation of an event exceeds the consumer’s read buffer capacity, the stream tracks the byte offset to deliver the event over multiple reads without losing input data.