Skip to main content

Data Flow

How data travels from your shell through the Rust backend to your screen.

Complete Data Flow

╔═══════════════════════════════════════════════════════════════════════╗
║                              COMPLETE DATA FLOW                       ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║  ┌────────────────┐                                                   ║
║  │ Shell/App      │  Output: "ls\n" -> colored file listings          ║
║  │ (zsh, vim)     │                                                   ║
║  └───────┬────────┘                                                   ║
║          │                                                            ║
║          │ PTY master/slave pair                                      ║
║          ▼                                                            ║
║  ┌────────────────┐                                                   ║
║  │ pty-daemon     │  Rust daemon (sidecar binary)                     ║
║  │                │  Reads from PTY, writes to Unix socket            ║
║  └───────┬────────┘                                                   ║
║          │                                                            ║
║          │ Unix Socket (per session)                                  ║
║          ▼                                                            ║
║  ╔════════════════════════════════════════════════════════════════╗   ║
║  ║  TAURI BACKEND (Rust)                                          ║   ║
║  ║                                                                 ║   ║
║  ║  ┌───────────────┐         ┌───────────────┐                   ║   ║
║  ║  │ SessionActor  │────────▶│ GridWorker    │                   ║   ║
║  ║  │               │  spawn  │ (tokio task)  │                   ║   ║
║  ║  │ - owns state  │         │               │                   ║   ║
║  ║  │ - routes msgs │         │ loop {        │                   ║   ║
║  ║  └───────────────┘         │   recv msg    │                   ║   ║
║  ║                            │   feed data   │                   ║   ║
║  ║                            │   emit update │                   ║   ║
║  ║                            │ }             │                   ║   ║
║  ║                            └───────┬───────┘                   ║   ║
║  ║                                    │                           ║   ║
║  ║                            ┌───────▼───────┐                   ║   ║
║  ║                            │ AtomicState   │                   ║   ║
║  ║                            │               │                   ║   ║
║  ║                            │ ┌──────────┐  │                   ║   ║
║  ║                            │ │ Alacritty│  │◀── VTE Parser     ║   ║
║  ║                            │ │ Terminal │  │                   ║   ║
║  ║                            │ └──────────┘  │                   ║   ║
║  ║                            │       │       │                   ║   ║
║  ║                            │       ▼       │                   ║   ║
║  ║                            │ GridUpdate    │                   ║   ║
║  ║                            └───────┬───────┘                   ║   ║
║  ║                                    │                           ║   ║
║  ╚════════════════════════════════════╪═══════════════════════════╝   ║
║                                       │                               ║
║                                       │ Tauri emit (JSON)             ║
║                                       ▼                               ║
║  ╔════════════════════════════════════════════════════════════════╗   ║
║  ║  FRONTEND (TypeScript)                                         ║   ║
║  ║                                                                 ║   ║
║  ║  ┌───────────────────────────────────────────┐                 ║   ║
║  ║  │ GridBufferInjector                        │                 ║   ║
║  ║  │                                           │                 ║   ║
║  ║  │ listen(event) {                           │                 ║   ║
║  ║  │     inject(session, term, payload);       │                 ║   ║
║  ║  │     invoke("grid_ack", { sessionId });    │                 ║   ║
║  ║  │ }                                         │                 ║   ║
║  ║  └───────────────────────────────────────────┘                 ║   ║
║  ║                      │                                         ║   ║
║  ║                      ▼                                         ║   ║
║  ║  ┌───────────────────────────────────────────┐                 ║   ║
║  ║  │ xterm.js                                  │                 ║   ║
║  ║  │                                           │                 ║   ║
║  ║  │ Direct buffer injection                   │                 ║   ║
║  ║  │ refreshRows(start, end)                   │                 ║   ║
║  ║  └───────────────────────────────────────────┘                 ║   ║
║  ║                      │                                         ║   ║
║  ║                      ▼                                         ║   ║
║  ║  ┌───────────────────────────────────────────┐                 ║   ║
║  ║  │ WebGL Renderer                            │                 ║   ║
║  ║  │                                           │                 ║   ║
║  ║  │ GPU -> Screen                             │                 ║   ║
║  ║  └───────────────────────────────────────────┘                 ║   ║
║  ║                                                                 ║   ║
║  ╚════════════════════════════════════════════════════════════════╝   ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Step-by-Step Breakdown

Step 1: Shell Output

╔═══════════════════════════════════════════════════════════════════════╗
║  STEP 1: Shell/Application Output                                     ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║  User types: ls                                                       ║
║  Shell outputs: ESC[34mfile.txtESC[0m                                 ║
║                 ~~~~~~          ~~~~~~                                ║
║                 blue fg         reset                                 ║
║                                                                       ║
║  PTY master receives raw bytes as the output stream                   ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Step 2: GridWorker Event Loop

╔═══════════════════════════════════════════════════════════════════════╗
║  STEP 2: GridWorker Event Loop                                        ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║  The GridWorker runs as a Tokio async task:                           ║
║                                                                       ║
║  ┌───────────────────────────────────────────────────────────────┐    ║
║  │                                                               │    ║
║  │   loop {                                                      │    ║
║  │       select! {                                               │    ║
║  │           // Receive PTY data                                 │    ║
║  │           Data(data) = grid_rx.recv() => {                    │    ║
║  │               state.feed(&data);  // Feed to VTE              │    ║
║  │           }                                                   │    ║
║  │                                                               │    ║
║  │           // Check timeouts                                   │    ║
║  │           _ = tick_interval.tick() => {                       │    ║
║  │               state.tick();                                   │    ║
║  │                                                               │    ║
║  │               // Pull update if ready                         │    ║
║  │               if let Some(update) = state.pull() {            │    ║
║  │                   app.emit(&event_name, &update);             │    ║
║  │               }                                               │    ║
║  │           }                                                   │    ║
║  │                                                               │    ║
║  │           // Receive ACK                                      │    ║
║  │           Ack = grid_rx.recv() => {                           │    ║
║  │               state.ack();                                    │    ║
║  │           }                                                   │    ║
║  │       }                                                       │    ║
║  │   }                                                           │    ║
║  │                                                               │    ║
║  └───────────────────────────────────────────────────────────────┘    ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Step 3: VTE Processing

╔═══════════════════════════════════════════════════════════════════════╗
║  STEP 3: VTE Processing with Priority Detection                       ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║   Incoming data goes through priority-based sync detection:           ║
║                                                                       ║
║   ┌───────────────────────────────────────────────────────────────┐   ║
║   │                                                               │   ║
║   │   1. Accumulate in input stream                               │   ║
║   │                                                               │   ║
║   │   2. Check for incomplete ANSI sequence                       │   ║
║   │      -> If incomplete, wait for more data                     │   ║
║   │                                                               │   ║
║   │   3. Process complete data:                                   │   ║
║   │                                                               │   ║
║   │      Priority 1: BSU (Begin Synchronized Update)              │   ║
║   │      -> If detected, enter syncing mode                       │   ║
║   │                                                               │   ║
║   │      Priority 2: Cursor Hide (TUI pattern)                    │   ║
║   │      -> If detected, wait for cursor show                     │   ║
║   │                                                               │   ║
║   │      Priority 3: Implicit sync (erase pattern)                │   ║
║   │      -> If detected, wait briefly                             │   ║
║   │                                                               │   ║
║   │   4. Process through Alacritty VTE Parser                     │   ║
║   │      -> Escape sequences interpreted                          │   ║
║   │      -> Grid updated with cell data                           │   ║
║   │                                                               │   ║
║   │   5. Mark pending data available                              │   ║
║   │                                                               │   ║
║   └───────────────────────────────────────────────────────────────┘   ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Step 4: Build GridUpdate

╔═══════════════════════════════════════════════════════════════════════╗
║  STEP 4: Build GridUpdate                                             ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║   The pull() method checks all gates:                                 ║
║                                                                       ║
║   ┌───────────────────────────────────────────────────────────────┐   ║
║   │                                                               │   ║
║   │   if waiting_ack { return None; }        // Gate 1            │   ║
║   │   if syncing { return None; }            // Gate 2            │   ║
║   │   if cursor_hidden { return None; }      // Gate 3            │   ║
║   │   if implicit_syncing { return None; }   // Gate 4            │   ║
║   │   if !pending_data { return None; }      // Gate 5            │   ║
║   │                                                               │   ║
║   │   // All gates passed -> Build and return update              │   ║
║   │   waiting_ack = true;                                         │   ║
║   │   pending_data = false;                                       │   ║
║   │   return Some(build_update());                                │   ║
║   │                                                               │   ║
║   └───────────────────────────────────────────────────────────────┘   ║
║                                                                       ║
║   build_update() creates:                                             ║
║                                                                       ║
║   ┌───────────────────────────────────────────────────────────────┐   ║
║   │                                                               │   ║
║   │   GridUpdate {                                                │   ║
║   │       lines: Vec<LineData>,    // All line content            │   ║
║   │       ybase: usize,            // Scrollback size             │   ║
║   │       total_rows: u16,         // Total line count            │   ║
║   │       diff_hint: DiffHint,     // Full/Partial/None           │   ║
║   │       cursor_row: u16,         // Cursor position             │   ║
║   │       cursor_col: u16,                                        │   ║
║   │   }                                                           │   ║
║   │                                                               │   ║
║   └───────────────────────────────────────────────────────────────┘   ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Step 5: Cell Conversion

╔═══════════════════════════════════════════════════════════════════════╗
║  STEP 5: Alacritty Cell -> xterm.js Cell                              ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║   Alacritty Cell:                                 xterm.js Cell:      ║
║   ┌─────────────────────────┐                   ┌──────────────────┐  ║
║   │  c: char      = 'f'     │                   │ content: u32     │  ║
║   │  fg: Color    = Blue    │      convert      │ (width+codepoint)│  ║
║   │  bg: Color    = Default │      ──────▶      │                  │  ║
║   │  flags: Flags = NONE    │                   │ fg: u32          │  ║
║   └─────────────────────────┘                   │ (mode+color)     │  ║
║                                                 │                  │  ║
║                                                 │ bg: u32          │  ║
║                                                 │ (mode+color)     │  ║
║                                                 └──────────────────┘  ║
║                                                                       ║
║   Content Format (32-bit):                                            ║
║   ┌──────────────────────────────────────────────────────────┐        ║
║   │ [31:24]  │ [23:22]  │    [21]     │     [20:0]           │        ║
║   │ reserved │  width   │ is_combined │    codepoint         │        ║
║   └──────────────────────────────────────────────────────────┘        ║
║                                                                       ║
║   Color Format (32-bit):                                              ║
║   ┌──────────────────────────────────────────────────────────┐        ║
║   │ [31:26]  │ [25:24]  │           [23:0]                   │        ║
║   │  flags   │   mode   │     color value                    │        ║
║   └──────────────────────────────────────────────────────────┘        ║
║                                                                       ║
║   Mode: 0=Default, 1=P16, 2=P256, 3=RGB                               ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Step 6: Frontend Injection

╔═══════════════════════════════════════════════════════════════════════╗
║  STEP 6: GridBufferInjector.inject()                                  ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║   ┌───────────────────────────────────────────────────────────────┐   ║
║   │                                                               │   ║
║   │   1. Epoch validation (reject stale updates)                  │   ║
║   │      -> If update is old, skip it                             │   ║
║   │                                                               │   ║
║   │   2. Ensure xterm.js buffer is sized correctly                │   ║
║   │      -> Resize if needed                                      │   ║
║   │                                                               │   ║
║   │   3. Inject cells directly into buffer                        │   ║
║   │      -> For each line:                                        │   ║
║   │         For each cell:                                        │   ║
║   │           data[offset]     = content                          │   ║
║   │           data[offset + 1] = fg                               │   ║
║   │           data[offset + 2] = bg                               │   ║
║   │                                                               │   ║
║   │   4. Set buffer state (ybase, ydisp)                          │   ║
║   │                                                               │   ║
║   │   5. Update scroll area                                       │   ║
║   │                                                               │   ║
║   │   6. Trigger render based on DiffHint:                        │   ║
║   │      -> Full: refreshRows(0, rows - 1)                        │   ║
║   │      -> Partial: refreshRows(minDirty, maxDirty)              │   ║
║   │      -> None: skip refresh                                    │   ║
║   │                                                               │   ║
║   └───────────────────────────────────────────────────────────────┘   ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Timing Diagram

╔═══════════════════════════════════════════════════════════════════════╗
║  TIME ->                                                              ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║  PTY:     ─────[data1]────────[data2]─────[data3]─────────────        ║
║                  │               │            │                       ║
║                  ▼               ▼            ▼                       ║
║  feed():  ──────[*]────────────[*]──────────[*]─────────────────      ║
║                                                    │                  ║
║                                                    │ complete frame   ║
║                                                    ▼                  ║
║  VTE:     ────────────────────────────────────────[parse]─────────    ║
║                                                    │                  ║
║                                                    ▼                  ║
║  pull():  ────────────────────────────────────────[GridUpdate]───     ║
║                                                    │                  ║
║                                                    │ emit             ║
║                                                    ▼                  ║
║  inject():─────────────────────────────────────────[*]────────────    ║
║                                                    │                  ║
║                                                    │ ACK              ║
║                                                    ▼                  ║
║  ack():   ─────────────────────────────────────────────────[*]───     ║
║                                                                       ║
║  render:  ──────────────────────────────────────────────────────[*]─  ║
║                                                                       ║
║           ◀─────────────────── ~50ms (tick interval) ───────────────▶ ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Error Recovery

╔═══════════════════════════════════════════════════════════════════════╗
║  ERROR RECOVERY                                                       ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║   1. VTE Panic Recovery                                               ║
║   ──────────────────────                                              ║
║   If Alacritty parser panics, catch and reset:                        ║
║   - Increment panic counter                                           ║
║   - Create fresh processor                                            ║
║   - Continue processing                                               ║
║                                                                       ║
║   2. ACK Timeout                                                      ║
║   ──────────────                                                      ║
║   If ACK not received within 1 second:                                ║
║   - Force continue (don't block forever)                              ║
║   - Reset waiting_ack flag                                            ║
║   - Resume normal operation                                           ║
║                                                                       ║
║   3. Epoch Validation                                                 ║
║   ───────────────────                                                 ║
║   If update epoch is older than current:                              ║
║   - Reject the stale update                                           ║
║   - Don't apply to buffer                                             ║
║   - Don't send ACK                                                    ║
║                                                                       ║
║   4. Skip Invalid Frame                                               ║
║   ──────────────────────                                              ║
║   If DiffHint is 'Skip':                                              ║
║   - Don't apply to buffer                                             ║
║   - Don't send ACK                                                    ║
║   - Wait for valid frame                                              ║
║                                                                       ║
╚═══════════════════════════════════════════════════════════════════════╝

Summary

╔═════════════════════════════════════════════════════════════════════╗
║                                                                     ║
║   DATA FLOW SUMMARY                                                 ║
║                                                                     ║
║   ┌───────────────────────────────────────────────────────────────┐ ║
║   │                                                               │ ║
║   │   Shell Output                                                │ ║
║   │        │                                                      │ ║
║   │        ▼                                                      │ ║
║   │   PTY Daemon (Rust sidecar)                                   │ ║
║   │        │                                                      │ ║
║   │        │ Unix Socket                                          │ ║
║   │        ▼                                                      │ ║
║   │   SessionActor -> GridWorker                                  │ ║
║   │        │                                                      │ ║
║   │        ▼                                                      │ ║
║   │   AtomicState (Alacritty VTE)                                 │ ║
║   │        │                                                      │ ║
║   │        │ Five sync gates                                      │ ║
║   │        ▼                                                      │ ║
║   │   GridUpdate (JSON emit)                                      │ ║
║   │        │                                                      │ ║
║   │        ▼                                                      │ ║
║   │   GridBufferInjector                                          │ ║
║   │        │                                                      │ ║
║   │        │ Direct buffer injection                              │ ║
║   │        ▼                                                      │ ║
║   │   xterm.js + WebGL                                            │ ║
║   │        │                                                      │ ║
║   │        ▼                                                      │ ║
║   │   Your Screen                                                 │ ║
║   │                                                               │ ║
║   └───────────────────────────────────────────────────────────────┘ ║
║                                                                     ║
║   Key Technologies:                                                 ║
║   - Rust + Tokio (async processing)                                 ║
║   - Alacritty (VTE parsing)                                         ║
║   - MPSC channels (lock-free communication)                         ║
║   - Tauri (IPC)                                                     ║
║   - xterm.js + WebGL (GPU rendering)                                ║
║                                                                     ║
╚═════════════════════════════════════════════════════════════════════╝

MonoTerm: Shell to Screen in Microseconds