Traditional terminals send the entire screen every time anything changes.
Copy
You type one character: "a"What changes?┌─────────────────────────────────────────────────────────────┐│ Line 1: ################################ (unchanged) ││ Line 2: ################################ (unchanged) ││ Line 3: ################################ (unchanged) ││ ... ││ Line 39: ################################ (unchanged) ││ Line 40: $ command_here| (ONE CHAR!) │└─────────────────────────────────────────────────────────────┘Traditional terminal sends: ALL 40 lines = ~50,000 bytesActual change: 1 character = ~25 bytesWasted: 99.95% of data!
╔═══════════════════════════════════════════════════════════════════════════════╗║ THE 2V SAFETY RULE ║╠═══════════════════════════════════════════════════════════════════════════════╣║ ║║ MonoTerm uses TWO related settings: ║║ ║║ ┌─────────────────────────────────────────────────────────────────────────┐ ║║ │ │ ║║ │ COMPARISON WINDOW = 2V (bottom 80 lines for 40-row viewport) │ ║║ │ ─────────────────────────────────────────────────────────── │ ║║ │ This is HOW MANY lines we check for changes │ ║║ │ │ ║║ │ FULL MODE TRIGGER = V (history changes more than 40 lines) │ ║║ │ ─────────────────────────────────────────────────────────── │ ║║ │ This is WHEN we give up and refresh everything │ ║║ │ │ ║║ └─────────────────────────────────────────────────────────────────────────┘ ║║ ║║ THE SAFETY RULE: ║║ ┌─────────────────────────────────────────────────────────────────────────┐ ║║ │ │ ║║ │ Full Mode Trigger < Comparison Window │ ║║ │ (V) < (2V) │ ║║ │ │ ║║ │ This ensures we ALWAYS catch all changes! │ ║║ │ │ ║║ └─────────────────────────────────────────────────────────────────────────┘ ║║ ║╠═══════════════════════════════════════════════════════════════════════════════╣║ ║║ WHY THIS MATTERS (Visual Proof): ║║ ───────────────────────────────── ║║ ║║ Imagine history grows by 30 lines (less than V=40): ║║ ║║ BEFORE AFTER ║║ ┌────────────────────────┐ ┌────────────────────────┐ ║║ │ old history │ │ old history │ ║║ │ (not compared) │ │ + 30 new lines │ ║║ │ │ │ (not compared) │ ║║ ├────────────────────────┤ ├────────────────────────┤ ║║ │ ╔══════════════════╗ │ │ ╔══════════════════╗ │ ║║ │ ║ 2V WINDOW ║ │ ───► │ ║ 2V WINDOW ║ │ ║║ │ ║ (80 lines) ║ │ │ ║ (80 lines) ║ │ ║║ │ ║ ┌────────────┐ ║ │ │ ║ ┌────────────┐ ║ │ ║║ │ ║ │ VIEWPORT │ ║ │ │ ║ │ VIEWPORT │ ║ │ ║║ │ ║ │ (40 lines) │ ║ │ │ ║ │ (40 lines) │ ║ │ ║║ │ ║ └────────────┘ ║ │ │ ║ └────────────┘ ║ │ ║║ │ ╚══════════════════╝ │ │ ╚══════════════════╝ │ ║║ └────────────────────────┘ └────────────────────────┘ ║║ ║║ ✓ 30 < 40, so we stay in Partial mode ║║ ✓ 2V window (80 lines) covers the 30-line shift ║║ ✓ All changes are detected! ║║ ║╠═══════════════════════════════════════════════════════════════════════════════╣║ ║║ What if history grows by 50 lines (more than V=40)? ║║ ║║ BEFORE AFTER ║║ ┌────────────────────────┐ ┌────────────────────────┐ ║║ │ old history │ │ old history │ ║║ │ │ │ + 50 new lines │ ║║ │ │ │ │ ║║ ├────────────────────────┤ ├────────────────────────┤ ║║ │ ╔══════════════════╗ │ │ ╔══════════════════╗│ ║║ │ ║ 2V WINDOW ║ │ ───► │ ║ 2V WINDOW ║│ ║║ │ ║ OLD POSITION ║ │ │ ║ NEW POSITION ║│ ← SHIFTED! ║║ │ ╚══════════════════╝ │ │ ╚══════════════════╝│ ║║ └────────────────────────┘ └────────────────────────┘ ║║ ║║ ✗ 50 > 40, windows don't overlap properly ║║ ✗ Fingerprint comparison might miss changes ║║ → SOLUTION: Switch to Full mode (refresh everything) ║║ ║╚═══════════════════════════════════════════════════════════════════════════════╝
The 2V window ensures that even when content shifts, we can still detect all changes. When shifts exceed our detection range, we automatically switch to Full mode for safety.
┌───────────────────────────────────────────────────────────────────────┐│ HOW MONOTERM DETECTS CHANGES │├───────────────────────────────────────────────────────────────────────┤│ ││ STEP 1: Compare fingerprints in 2V range ││ ───────────────────────────────────────── ││ ││ Old New ││ ┌─────────────┐ ┌─────────────┐ ││ │ Line 1: A │ ═══ │ Line 1: A │ → SAME ││ │ Line 2: B │ ═══ │ Line 2: B │ → SAME ││ │ Line 3: C │ ≠≠≠ │ Line 3: X │ → CHANGED! ││ │ Line 4: D │ ═══ │ Line 4: D │ → SAME ││ └─────────────┘ └─────────────┘ ││ ││ STEP 2: Decide mode ││ ─────────────────── ││ ││ ┌─────────────────────────────────────────────────────┐ ││ │ Buffer size changed? ──────────────→ FULL │ ││ │ History grew > V? ──────────────→ FULL │ ││ │ No changes? ──────────────→ NONE │ ││ │ Some changes? ──────────────→ PARTIAL │ ││ └─────────────────────────────────────────────────────┘ ││ ││ STEP 3: Send only what's needed ││ ─────────────────────────────── ││ ││ PARTIAL: Send only changed lines (Line 3 in example) ││ FULL: Send all lines in 2V range ││ NONE: Send nothing (cursor update only) ││ │└───────────────────────────────────────────────────────────────────────┘
Line 1: "Hello World"Line 2: "Hello World"Compare: H==H, e==e, l==l, l==l, o==o, ' '==' ', ...Operations: O(n) where n = line lengthFor 120-char line: 120 comparisonsFor 40 lines: 4,800 comparisons per frame
Copy
Line 1 hash: 0xA3F2B71CLine 2 hash: 0xA3F2B71CCompare: 0xA3F2B71C == 0xA3F2B71C (single CPU instruction)Operations: O(1) - just one comparison!For 40 lines: 40 comparisons per frame