Skip to main content

Data Flow: PTY to Screen

How your terminal output travels through MonoTerm’s rendering pipeline.

Complete Data Flow

┌───────────────────────────────────────────────────────────────────────┐
│                         COMPLETE DATA FLOW                            │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│   ┌────────────┐                                                      │
│   │ Shell/App  │  Output: "ls" --> colored file list                  │
│   │ (zsh, vim) │                                                      │
│   └─────┬──────┘                                                      │
│         │                                                             │
│         │ PTY (pseudo-terminal)                                       │
│         ▼                                                             │
│   ┌────────────┐                                                      │
│   │ PTY Daemon │  Rust sidecar binary                                 │
│   │            │  Reads PTY, writes to Unix Socket                    │
│   └─────┬──────┘                                                      │
│         │                                                             │
│         │ Unix Socket (per session)                                   │
│         ▼                                                             │
│   ┌───────────────────────────────────────────────────────────────┐  │
│   │  TAURI BACKEND (Rust)                                         │  │
│   │                                                                │  │
│   │  ┌─────────────┐         ┌─────────────┐                       │  │
│   │  │ SessionActor│────────→│ GridWorker  │                       │  │
│   │  │ (owns state)│  spawn  │ (Tokio task)│                       │  │
│   │  └─────────────┘         └──────┬──────┘                       │  │
│   │                                 │                              │  │
│   │                                 ▼                              │  │
│   │                          ┌─────────────┐                       │  │
│   │                          │ Alacritty   │                       │  │
│   │                          │ VTE Parser  │                       │  │
│   │                          └──────┬──────┘                       │  │
│   │                                 │                              │  │
│   │                                 ▼                              │  │
│   │                          ┌─────────────┐                       │  │
│   │                          │ Smart Diff  │                       │  │
│   │                          │ (DiffHint)  │                       │  │
│   │                          └──────┬──────┘                       │  │
│   │                                 │                              │  │
│   └───────────────────────────────────────────────────────────────┘  │
│         │                                                             │
│         │ Tauri Event (JSON)                                          │
│         ▼                                                             │
│   ┌───────────────────────────────────────────────────────────────┐  │
│   │  FRONTEND (TypeScript)                                        │  │
│   │                                                                │  │
│   │  ┌───────────────────┐                                         │  │
│   │  │ Direct Injection  │  Cells injected into xterm.js          │  │
│   │  └────────┬──────────┘                                         │  │
│   │           │                                                    │  │
│   │           ▼                                                    │  │
│   │  ┌───────────────────┐                                         │  │
│   │  │ WebGL Renderer    │  GPU-accelerated display               │  │
│   │  └───────────────────┘                                         │  │
│   │                                                                │  │
│   └───────────────────────────────────────────────────────────────┘  │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Step-by-Step Breakdown

Step 1: Your Program Runs

┌───────────────────────────────────────────────────────────────────────┐
│  STEP 1: Program generates output                                     │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│     ┌────────────────────────────────────────────────────────────┐   │
│     │                                                            │   │
│     │   $ npm install                                            │   │
│     │                                                            │   │
│     │   npm wants to show:                                       │   │
│     │                                                            │   │
│     │      "Installing packages..."                              │   │
│     │      "[########............] 45%"                          │   │
│     │                                                            │   │
│     │   This gets converted to ESCAPE CODES:                     │   │
│     │                                                            │   │
│     │      ESC[32m  = "start green color"                        │   │
│     │      ESC[0m   = "reset color"                              │   │
│     │      ESC[2K   = "clear line"                               │   │
│     │                                                            │   │
│     └────────────────────────────────────────────────────────────┘   │
│                                                                       │
│                                                                       │
│          These codes control colors, cursor position, and more.       │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Step 2: Data Travels Through PTY

┌───────────────────────────────────────────────────────────────────────┐
│  STEP 2: Data travels through PTY (pseudo-terminal)                   │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│                                                                       │
│      npm                                    MonoTerm                  │
│     ┌─────┐                                ┌─────┐                    │
│     │     │                                │     │                    │
│     │  N  │════════════════════════════════│  M  │                    │
│     │  P  │        PTY Pipe                │  O  │                    │
│     │  M  │    (like a water hose)         │  N  │                    │
│     │     │                                │  O  │                    │
│     └─────┘                                └─────┘                    │
│                                                                       │
│                                                                       │
│     The pipe can SPLIT data randomly:                                 │
│                                                                       │
│                                                                       │
│     npm sends:     "ESC[32mHelloESC[0m"                               │
│                          │                                            │
│                   ┌──────┴──────┐                                     │
│                   │   THE PIPE  │                                     │
│                   └──────┬──────┘                                     │
│                          │                                            │
│     MonoTerm gets:  "ESC[32mHel"  then  "loESC[0m"                    │
│                        │                │                             │
│                    chunk 1          chunk 2                           │
│                                                                       │
│                                                                       │
│     This splitting is RANDOM and unpredictable!                       │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Step 3: Rust Backend Processing

┌───────────────────────────────────────────────────────────────────────┐
│  STEP 3: SessionActor receives and routes data                        │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│                                                                       │
│   ┌───────────────────┐                                               │
│   │   SessionActor    │  Single owner - no locks needed!              │
│   │                   │                                               │
│   │   Owns all state  │  Actor Model pattern                          │
│   └────────┬──────────┘                                               │
│            │                                                          │
│            │ MPSC channel (lock-free message passing)                 │
│            ▼                                                          │
│   ┌───────────────────┐                                               │
│   │   GridWorker      │  Tokio async task                             │
│   │                   │                                               │
│   │   loop {          │                                               │
│   │     receive data  │                                               │
│   │     parse VTE     │                                               │
│   │     compute diff  │                                               │
│   │     emit update   │                                               │
│   │   }               │                                               │
│   └───────────────────┘                                               │
│                                                                       │
│                                                                       │
│   Why Actor Model?                                                    │
│                                                                       │
│     * No mutex contention                                             │
│     * No deadlocks possible                                           │
│     * Guaranteed ordering                                             │
│     * Easy to reason about                                            │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Step 4: VTE Parser (Alacritty)

┌───────────────────────────────────────────────────────────────────────┐
│  STEP 4: Alacritty VTE Parser interprets escape sequences             │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│                                                                       │
│   Raw bytes: [0x1b, 0x5b, 0x33, 0x32, 0x6d, 0x48, 0x65, 0x6c, ...]   │
│                                                                       │
│                          │                                            │
│                          ▼                                            │
│                 ┌───────────────────┐                                 │
│                 │   Alacritty VTE   │                                 │
│                 │                   │                                 │
│                 │   Parse escape    │                                 │
│                 │   sequences       │                                 │
│                 └────────┬──────────┘                                 │
│                          │                                            │
│                          ▼                                            │
│                                                                       │
│   Grid cells:                                                         │
│   ┌───────┬───────┬───────┬───────┬───────┐                           │
│   │   H   │   e   │   l   │   l   │   o   │                           │
│   │ green │ green │ green │ green │ green │                           │
│   └───────┴───────┴───────┴───────┴───────┘                           │
│                                                                       │
│                                                                       │
│   What Alacritty provides:                                            │
│                                                                       │
│     * Character content                                               │
│     * Foreground color                                                │
│     * Background color                                                │
│     * Text attributes (bold, underline, etc.)                         │
│     * Cursor position                                                 │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Step 5: Smart Diff Calculation

┌───────────────────────────────────────────────────────────────────────┐
│  STEP 5: DiffHint determines what changed                             │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│                                                                       │
│   Previous State                  New State                           │
│                                                                       │
│   Line 0: "$ cd project"         Line 0: "$ cd project"    SAME      │
│   Line 1: "$ npm install"        Line 1: "$ npm install"   SAME      │
│   Line 2: "Loading..."           Line 2: "Done!"           CHANGED   │
│   Line 3: ""                     Line 3: ""                SAME      │
│                                                                       │
│                                                                       │
│   Result: Partial { dirty_rows: [2] }                                 │
│                                                                       │
│                                                                       │
│   ┌───────────────────┐    ┌───────────────────┐    ┌───────────────┐ │
│   │     Full          │    │     Partial       │    │     None      │ │
│   │                   │    │                   │    │               │ │
│   │   ############    │    │   ............    │    │   ..........  │ │
│   │   ############    │    │   ..########..    │    │   ..........  │ │
│   │   ############    │    │   ............    │    │   ...._....   │ │
│   │   All rows        │    │   Dirty rows      │    │   Cursor only │ │
│   └───────────────────┘    └───────────────────┘    └───────────────┘ │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Step 6: Frontend Injection

┌───────────────────────────────────────────────────────────────────────┐
│  STEP 6: Direct Buffer Injection into xterm.js                        │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│                                                                       │
│   Tauri Event arrives with GridUpdate                                 │
│                                                                       │
│                          │                                            │
│                          ▼                                            │
│                 ┌───────────────────┐                                 │
│                 │ Buffer Injector   │                                 │
│                 │                   │                                 │
│                 │ DiffHint check    │                                 │
│                 └────────┬──────────┘                                 │
│                          │                                            │
│          ┌───────────────┼───────────────┐                            │
│          │               │               │                            │
│          ▼               ▼               ▼                            │
│     ┌────────┐      ┌────────┐      ┌────────┐                        │
│     │  Full  │      │ Partial│      │  None  │                        │
│     │        │      │        │      │        │                        │
│     │ New    │      │ Update │      │ Cursor │                        │
│     │ buffer │      │ rows   │      │ only   │                        │
│     └────────┘      └────────┘      └────────┘                        │
│                                                                       │
│                                                                       │
│   xterm.js buffer gets updated directly:                              │
│                                                                       │
│     buffer.lines[i]._data = [content, fg, bg, ...]                    │
│                                                                       │
│                          │                                            │
│                          ▼                                            │
│                 ┌───────────────────┐                                 │
│                 │ WebGL Renderer    │                                 │
│                 │                   │                                 │
│                 │ GPU-accelerated   │                                 │
│                 │ display           │                                 │
│                 └───────────────────┘                                 │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

ACK Handshake (Flow Control)

┌───────────────────────────────────────────────────────────────────────┐
│  ACK HANDSHAKE: Prevents overwhelming the frontend                    │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│                                                                       │
│        RUST BACKEND                           FRONTEND                │
│       ┌────────────┐                       ┌────────────┐             │
│       │            │     Frame 1           │            │             │
│       │            │──────────────────────→│  Display   │             │
│       │            │                       │            │             │
│       │  WAITING   │←──────────────────────│   "OK!"    │             │
│       │   ...      │     ACK received      │            │             │
│       │            │                       │            │             │
│       │            │     Frame 2           │            │             │
│       │            │──────────────────────→│  Display   │             │
│       │            │                       │            │             │
│       │            │←──────────────────────│   "OK!"    │             │
│       │            │         ACK           │            │             │
│       └────────────┘                       └────────────┘             │
│                                                                       │
│                                                                       │
│     WHY HANDSHAKE?                                                    │
│                                                                       │
│     Without ACK:                                                      │
│                                                                       │
│        Send ──→ Send ──→ Send ──→ Send ──→ Send                       │
│                                         │                             │
│                             Frontend overwhelmed!                     │
│                                                                       │
│     With ACK:                                                         │
│                                                                       │
│        Send ──→ Wait ──→ ACK ──→ Send ──→ Wait ──→ ACK                │
│                                                     │                 │
│                                        Smooth processing              │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Timing Diagram

┌───────────────────────────────────────────────────────────────────────┐
│  TIME ────────────────────────────────────────────────────────────→   │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  PTY:     ─────[data1]────────[data2]─────[data3]─────────────────    │
│                  │               │            │                       │
│                  ▼               ▼            ▼                       │
│  VTE:     ──────[*]────────────[*]──────────[*]───────────────────    │
│                                                    │                  │
│                                                    │ complete frame   │
│                                                    ▼                  │
│  Diff:    ─────────────────────────────────────────[DiffHint]─────    │
│                                                    │                  │
│                                                    │ emit             │
│                                                    ▼                  │
│  Inject:  ─────────────────────────────────────────[*]────────────    │
│                                                    │                  │
│                                                    │ ACK              │
│                                                    ▼                  │
│  Render:  ──────────────────────────────────────────────[*]───────    │
│                                                                       │
│           <──────────────────── ~50ms ───────────────────────────→    │
│           (tick interval)                                             │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Summary

┌───────────────────────────────────────────────────────────────────────┐
│                                                                       │
│                    THE COMPLETE JOURNEY                               │
│                                                                       │
│                                                                       │
│     1. BORN                    2. TRAVEL                   3. PARSE   │
│                                                                       │
│     ┌─────────┐               ═══════════               ┌─────────┐   │
│     │   vim   │               │  PTY     │               │ Alacritty│  │
│     │  says   │══════════════→│  Pipe    │══════════════→│ VTE     │   │
│     │ "Hello" │               │ (chunks) │               │ Parser  │   │
│     └─────────┘               ═══════════               └─────────┘   │
│                                                                       │
│                                                                       │
│     4. DIFF                    5. INJECT                  6. DISPLAY  │
│                                                                       │
│     ┌─────────┐               ┌─────────┐               ┌─────────┐   │
│     │ Smart   │               │ Direct  │               │ WebGL   │   │
│     │ Diff    │══════════════→│ Buffer  │══════════════→│ Render  │   │
│     │ (Rust)  │               │ Inject  │               │ (GPU)   │   │
│     └─────────┘               └─────────┘               └─────────┘   │
│                                                                       │
│                                                                       │
│                         7. ACKNOWLEDGE                                │
│                                                                       │
│                         ┌─────────────┐                               │
│                         │   Frontend  │                               │
│                         │   says      │                               │
│                         │   "Got it!" │                               │
│                         │             │                               │
│                         │  READY FOR  │                               │
│                         │    NEXT     │                               │
│                         └─────────────┘                               │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

Architecture

SessionActor (Rust) owns all state with MPSC channels for lock-free communication. Alacritty VTE parses escape sequences. WebGL renders to screen.