vibetunnel/web/snapshot-format.md
Mario Zechner ef7a679c2b Fix binary buffer encoding to support large terminals
The binary encoding was using 16-bit unsigned integers which failed when:
- Terminal has many rows (>65k)
- Cursor is above the viewport (negative relative position)

Changes:
- Upgrade to version 2 of the binary format
- Use 32-bit integers for dimensions and positions
- Use signed integers for viewport/cursor positions
- Update header size from 16 to 32 bytes
- Update documentation to reflect new format

This fixes the issue where cursorY could be negative when the cursor
is above the visible viewport (e.g., cursorY=0, viewportY=46 results
in relative cursorY=-46).

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 02:31:15 +02:00

175 lines
No EOL
6 KiB
Markdown

# VibeTunnel Terminal Buffer Snapshot Format
This document describes the binary format used for efficient terminal buffer snapshots.
## Overview
The snapshot format is a compact binary representation of terminal buffer state, designed to minimize data transfer while preserving all terminal attributes. It consists of a header followed by a stream of encoded cells.
## Format Structure
```
┌──────────────┬─────────────────────────────────┐
│ Header │ Cell Stream │
│ (32 bytes) │ (variable, 4+ bytes/cell) │
└──────────────┴─────────────────────────────────┘
```
## Header Format (32 bytes) - Version 2
```
Offset Size Field Description
------ ---- ---------- -----------
0x00 2 Magic 0x5654 ("VT" in ASCII)
0x02 1 Version Format version (0x02 for 32-bit support)
0x03 1 Flags Reserved for future use
0x04 4 Cols Terminal width (32-bit unsigned, little-endian)
0x08 4 Rows Number of rows in this snapshot (32-bit unsigned, little-endian)
0x0C 4 ViewportY Starting line number in buffer (32-bit signed, little-endian)
0x10 4 CursorX Cursor column position (32-bit signed, little-endian)
0x14 4 CursorY Cursor row position relative to viewport (32-bit signed, little-endian)
0x18 4 Reserved Reserved for future use
```
Note: CursorY is relative to the viewport and can be negative if the cursor is above the visible area.
## Cell Format
Each cell uses a variable-length encoding:
### Basic Cell (4 bytes) - ASCII with palette colors
```
Offset Size Field Description
------ ---- ---------- -----------
0x00 1 Character UTF-8 character (ASCII range)
0x01 1 Attributes Bit flags (see below)
0x02 1 FG Color Foreground palette index (0-255)
0x03 1 BG Color Background palette index (0-255)
```
### Extended Cell (variable) - Unicode or RGB colors
```
Offset Size Field Description
------ ---- ---------- -----------
0x00 1 Header [2 bits: char_len-1][1 bit: rgb_fg][1 bit: rgb_bg][4 bits: reserved]
0x01 1 Attributes Bit flags (see below)
0x02 1-4 Character UTF-8 character (length from header)
0x?? 1/3 FG Color 1 byte palette or 3 bytes RGB
0x?? 1/3 BG Color 1 byte palette or 3 bytes RGB
```
### Attribute Flags (1 byte)
```
Bit Flag
--- ----
0 Bold
1 Italic
2 Underline
3 Dim
4 Inverse
5 Invisible
6 Strikethrough
7 Extended (if set, use extended cell format)
```
## Special Encodings
### Run-Length Encoding
For repeated cells (common with spaces), use RLE:
```
0xFF <count:1> <cell:4+>
```
This encodes up to 255 repeated cells.
### Empty Line Marker
For completely empty lines (all spaces with default attributes):
```
0xFE <count:1>
```
This encodes up to 255 empty lines.
## Color Encoding
### Palette Colors (0-255)
Standard xterm 256-color palette indices.
### RGB Colors (24-bit)
When RGB flag is set in extended cell header:
```
R (1 byte) G (1 byte) B (1 byte)
```
## API Endpoint
### Request
```
GET /api/sessions/{sessionId}/buffer?viewportY={Y}&lines={N}
```
Parameters:
- `sessionId`: Session identifier
- `viewportY`: Starting line in the terminal buffer (0-based)
- `lines`: Number of lines to return
### Response
```
Content-Type: application/octet-stream
Content-Length: {size}
[Binary data as described above]
```
## Example
For a 80x24 terminal showing "Hello" on black background:
```
Header (32 bytes):
56 54 02 00 50 00 00 00 18 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─┴─┴─┴─ Reserved
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─┴─┴─┴─ CursorY (0)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─┴─┴─┴─ CursorX (5)
│ │ │ │ │ │ │ │ │ │ │ │ └─┴─┴─┴─ ViewportY (0)
│ │ │ │ │ │ │ │ └─┴─┴─┴─ Rows (24)
│ │ │ │ └─┴─┴─┴─ Cols (80)
│ │ │ └─ Flags (0)
│ │ └─ Version (2)
└─┴─ Magic "VT"
Cells:
48 00 07 00 65 00 07 00 6C 00 07 00 6C 00 07 00 6F 00 07 00
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─ BG: black (0)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─ FG: white (7)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─ Attributes: none (0)
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─ Character: 'o'
[Continue for remaining cells...]
FF 4B 20 00 07 00 (RLE: 75 spaces)
FE 17 (23 empty lines)
```
## Implementation Notes
1. The server maintains xterm.js Terminal instances for each active session
2. Binary encoding happens on-the-fly when buffer endpoint is called
3. Client can request specific viewport regions for efficient updates
4. Format is designed to be easily parseable with minimal overhead
5. Extended format allows for future enhancements without breaking compatibility
## Performance Characteristics
- Basic ASCII terminal: ~4 bytes per cell
- With colors/attributes: ~4-7 bytes per cell
- With RLE compression: ~10-20% of original size for typical terminals
- Network transfer: ~3-8KB for full 80x24 screen (before gzip)