Skip to main content

Atomic Loop

The heart of MonoTerm’s flicker-free rendering - inspired by Ink app patterns.
╔═══════════════════════════════════════════════════════════════════════════════╗
║                                                                               ║
║                         ATOMIC LOOP                                           ║
║                                                                               ║
║        "Virtual Synchronized Rendering for Terminals"                         ║
║                                                                               ║
╚═══════════════════════════════════════════════════════════════════════════════╝

The Origin Story

╔═══════════════════════════════════════════════════════════════════════════════╗
║  HOW IT ALL STARTED                                                           ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║                                                                               ║
║   One day, we noticed something interesting about Ink apps...                 ║
║                                                                               ║
║   Ink = React for terminal UIs (npm, jest progress bars, etc.)                ║
║                                                                               ║
║   They do something clever:                                                   ║
║                                                                               ║
║   1. Hide cursor                                                              ║
║   2. Draw everything                                                          ║
║   3. Show cursor                                                              ║
║                                                                               ║
║   This means: Cursor visibility = Frame boundaries!                           ║
║                                                                               ║
╚═══════════════════════════════════════════════════════════════════════════════╝

The Ink Pattern

┌─────────────────────────────────────────────────────────────────────────────────┐
│  INK APP CURSOR PATTERN                                                          │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   Time ──────────────────────────────────────────────────────────────────▶      │
│                                                                                  │
│   Cursor                                                                         │
│   State:   VISIBLE ─┐                     ┌─ VISIBLE ─┐                         │
│                     │                     │           │                         │
│                     └─ HIDDEN ────────────┘           └─ HIDDEN ───▶           │
│                         │                                 │                     │
│                         │                                 │                     │
│                    Frame 1 Content               Frame 2 Content               │
│                                                                                  │
│   ════════════════════════════════════════════════════════════════════════════  │
│                                                                                  │
│   Sequence:                                                                      │
│                                                                                  │
│     ┌─────────────────────────────────────────────────────────────────┐        │
│     │  CSI ?25l          (cursor hide)    │  "I'm about to draw"     │        │
│     │  ... draw content ...               │  Frame content           │        │
│     │  CSI ?25h          (cursor show)    │  "I'm done drawing"      │        │
│     └─────────────────────────────────────────────────────────────────┘        │
│                                                                                  │
│   CSI ?25l = ESC [ ? 2 5 l = Hide cursor                                        │
│   CSI ?25h = ESC [ ? 2 5 h = Show cursor                                        │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
Think of it like a painter: They cover the canvas (hide cursor), paint the picture (draw content), then reveal the canvas (show cursor). You never see the painting in progress.

How MonoTerm Uses This

┌─────────────────────────────────────────────────────────────────────────────────┐
│  ATOMIC LOOP: FROM OBSERVATION TO IMPLEMENTATION                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   OBSERVATION:                                                                   │
│   ────────────                                                                   │
│   Programs that draw UI (npm, yarn, vitest, jest) all use cursor hide/show      │
│   to prevent flicker.                                                            │
│                                                                                  │
│   INSIGHT:                                                                       │
│   ────────                                                                       │
│   We can detect these boundaries without any protocol changes!                   │
│                                                                                  │
│   IMPLEMENTATION:                                                                │
│   ──────────────                                                                 │
│                                                                                  │
│   ┌────────────────────────────────────────────────────────────────────┐       │
│   │                                                                    │       │
│   │   Incoming bytes                                                   │       │
│   │         │                                                          │       │
│   │         ▼                                                          │       │
│   │   ┌───────────────────┐                                           │       │
│   │   │ Detect CSI ?25l   │──▶ Start buffering                        │       │
│   │   │ (cursor hide)     │                                           │       │
│   │   └───────────────────┘                                           │       │
│   │         │                                                          │       │
│   │         ▼                                                          │       │
│   │   ┌───────────────────┐                                           │       │
│   │   │ Buffer content    │   (don't render yet)                      │       │
│   │   │ ...               │                                           │       │
│   │   └───────────────────┘                                           │       │
│   │         │                                                          │       │
│   │         ▼                                                          │       │
│   │   ┌───────────────────┐                                           │       │
│   │   │ Detect CSI ?25h   │──▶ Flush buffer to screen!                │       │
│   │   │ (cursor show)     │                                           │       │
│   │   └───────────────────┘                                           │       │
│   │                                                                    │       │
│   └────────────────────────────────────────────────────────────────────┘       │
│                                                                                  │
│   RESULT:                                                                        │
│   ───────                                                                        │
│   Complete frames, no partial updates, no flicker!                               │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Virtual Synchronized Rendering

Why “Virtual”? Because we’re creating synchronization without explicit protocol support.
┌─────────────────────────────────────────────────────────────────────────────────┐
│  REAL vs VIRTUAL SYNCHRONIZATION                                                 │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   REAL (Hardware/Protocol)                                                       │
│   ────────────────────────                                                       │
│   GPU waits for display's vertical blank (vsync)                                │
│   Requires hardware support                                                      │
│                                                                                  │
│   ┌──────────┐      vsync      ┌──────────┐                                    │
│   │   GPU    │────────────────▶│ Display  │                                    │
│   └──────────┘                 └──────────┘                                    │
│                                                                                  │
│                                                                                  │
│   VIRTUAL (MonoTerm)                                                            │
│   ──────────────────                                                            │
│   Backend waits for application's "frame boundaries"                            │
│   No hardware needed - just pattern detection                                   │
│                                                                                  │
│   ┌──────────┐  cursor hide/show  ┌──────────┐                                 │
│   │ Backend  │───────────────────▶│ Frontend │                                 │
│   └──────────┘    (detected)      └──────────┘                                 │
│                                                                                  │
│   Same smooth result, different mechanism!                                       │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Multiple Detection Methods

The Atomic Loop doesn’t rely on just one method. It has a priority hierarchy.
┌─────────────────────────────────────────────────────────────────────────────────┐
│  SYNC DETECTION HIERARCHY (Priority Order)                                       │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   Priority 1: BSU/ESU (Explicit Protocol)                                       │
│   ═══════════════════════════════════════                                       │
│                                                                                  │
│   ┌─────────────────────────────────────────────────────────────┐              │
│   │  ESC[?2026h ──────── content ──────── ESC[?2026l            │              │
│   │  (Begin Sync)                        (End Sync)             │              │
│   │                                                             │              │
│   │  Most reliable. Modern apps use this.                       │              │
│   └─────────────────────────────────────────────────────────────┘              │
│                                                                                  │
│                                                                                  │
│   Priority 2: Cursor Hide/Show (Ink Pattern)                                    │
│   ═══════════════════════════════════════════                                   │
│                                                                                  │
│   ┌─────────────────────────────────────────────────────────────┐              │
│   │  CSI ?25l ──────── content ──────── CSI ?25h                │              │
│   │  (Hide)                              (Show)                 │              │
│   │                                                             │              │
│   │  Works with npm, yarn, vitest, jest, etc.                   │              │
│   └─────────────────────────────────────────────────────────────┘              │
│                                                                                  │
│                                                                                  │
│   Priority 3: Screen Clear (Implicit Sync)                                      │
│   ════════════════════════════════════════                                      │
│                                                                                  │
│   ┌─────────────────────────────────────────────────────────────┐              │
│   │  Clear screen detected ──── wait 8ms ──── assume complete   │              │
│   │                                                             │              │
│   │  Fallback for apps that don't use cursor patterns.          │              │
│   └─────────────────────────────────────────────────────────────┘              │
│                                                                                  │
│                                                                                  │
│   Priority 4: Incomplete Sequence                                               │
│   ═══════════════════════════════                                               │
│                                                                                  │
│   ┌─────────────────────────────────────────────────────────────┐              │
│   │  ESC [ 3 1 ...    (incomplete escape sequence)              │              │
│   │        │                                                    │              │
│   │        └── Wait for completion, don't render partial        │              │
│   └─────────────────────────────────────────────────────────────┘              │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Suppression Rules

Higher priority methods suppress lower ones.
┌─────────────────────────────────────────────────────────────────────────────────┐
│  SYNC SUPPRESSION DIAGRAM                                                        │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│                       ┌───────────────────┐                                     │
│                       │     BSU Active    │                                     │
│                       │  (Highest Priority)│                                    │
│                       └─────────┬─────────┘                                     │
│                                 │                                                │
│                                 │ Suppresses                                    │
│                                 ▼                                                │
│                       ┌───────────────────┐                                     │
│                       │  Cursor Pattern   │                                     │
│                       │   (Medium)        │                                     │
│                       └─────────┬─────────┘                                     │
│                                 │                                                │
│                                 │ Suppresses                                    │
│                                 ▼                                                │
│                       ┌───────────────────┐                                     │
│                       │  Implicit Sync    │                                     │
│                       │   (Lowest)        │                                     │
│                       └───────────────────┘                                     │
│                                                                                  │
│   ════════════════════════════════════════════════════════════════════════════  │
│                                                                                  │
│   Example: BSU active, cursor hide detected                                      │
│                                                                                  │
│   ┌────────────────────────────────────────────────────────────────┐           │
│   │  ESC[?2026h  (BSU starts)                                      │           │
│   │       │                                                        │           │
│   │       ▼                                                        │           │
│   │  CSI ?25l    (cursor hide - IGNORED, BSU already active)       │           │
│   │       │                                                        │           │
│   │       ▼                                                        │           │
│   │  ... content ...                                               │           │
│   │       │                                                        │           │
│   │       ▼                                                        │           │
│   │  CSI ?25h    (cursor show - IGNORED, BSU still active)         │           │
│   │       │                                                        │           │
│   │       ▼                                                        │           │
│   │  ESC[?2026l  (ESU ends - NOW we flush!)                        │           │
│   │                                                                │           │
│   └────────────────────────────────────────────────────────────────┘           │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Timeout Recovery

What if a cursor hide is never followed by cursor show?
┌─────────────────────────────────────────────────────────────────────────────────┐
│  TIMEOUT RECOVERY MECHANISM                                                      │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   Problem: "Lost" cursor show signal                                            │
│   ─────────────────────────────────                                             │
│                                                                                  │
│   ┌──────────────────────────────────────────────────────────────┐             │
│   │  CSI ?25l  (cursor hide)                                     │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  ... content ...                                             │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  [Program crashes / loses connection / forgets]              │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  CSI ?25h never comes!                                       │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  Screen frozen forever? ❌                                   │             │
│   └──────────────────────────────────────────────────────────────┘             │
│                                                                                  │
│   Solution: Tick Timeout                                                        │
│   ─────────────────────                                                         │
│                                                                                  │
│   ┌──────────────────────────────────────────────────────────────┐             │
│   │  CSI ?25l  (cursor hide, start timer)                        │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  ... content ...                                             │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  [16ms passes with no cursor show]                           │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  TIMEOUT! Force flush buffered content.                      │             │
│   │       │                                                      │             │
│   │       ▼                                                      │             │
│   │  Screen updates, not frozen. ✅                              │             │
│   └──────────────────────────────────────────────────────────────┘             │
│                                                                                  │
│   16ms = ~1 frame at 60Hz, reasonable wait time                                 │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Before and After

╔═══════════════════════════════════════════════════════════════════════════════╗
║  BEFORE: WITHOUT ATOMIC LOOP                                                  ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║                                                                               ║
║   npm install                                                                 ║
║   ─────────────                                                               ║
║                                                                               ║
║   Screen update 1:  ⠋ Installing...                                           ║
║   Screen update 2:  ⠙ Insta                         (partial!)                ║
║   Screen update 3:  ⠹ Installing d                  (partial!)                ║
║   Screen update 4:  ⠸ Installing dependencies       (finally!)                ║
║                                                                               ║
║   4 updates, flickering, ugly                                                 ║
║                                                                               ║
╚═══════════════════════════════════════════════════════════════════════════════╝

╔═══════════════════════════════════════════════════════════════════════════════╗
║  AFTER: WITH ATOMIC LOOP                                                      ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║                                                                               ║
║   npm install                                                                 ║
║   ─────────────                                                               ║
║                                                                               ║
║   Screen update 1:  ⠋ Installing dependencies...                              ║
║   Screen update 2:  ⠙ Installing dependencies...                              ║
║   Screen update 3:  ⠹ Installing dependencies...                              ║
║   Screen update 4:  ⠸ Installing dependencies...                              ║
║                                                                               ║
║   4 updates, each complete, smooth animation                                  ║
║                                                                               ║
╚═══════════════════════════════════════════════════════════════════════════════╝

Summary

┌─────────────────────────────────────────────────────────────────────────────────┐
│  ATOMIC LOOP SUMMARY                                                             │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│   WHAT: Detects complete frame boundaries                                        │
│                                                                                  │
│   HOW:                                                                           │
│   ┌────────────────────────────────────────────────────────────────────┐       │
│   │  1. BSU/ESU        (explicit protocol)        ← Most reliable     │       │
│   │  2. Cursor pattern (Ink apps)                 ← Most common       │       │
│   │  3. Implicit sync  (screen clear + timeout)   ← Fallback          │       │
│   │  4. Incomplete seq (wait for completion)      ← Safety net        │       │
│   └────────────────────────────────────────────────────────────────────┘       │
│                                                                                  │
│   WHY:                                                                           │
│   ┌────────────────────────────────────────────────────────────────────┐       │
│   │  • No partial renders                                             │       │
│   │  • No screen tearing                                              │       │
│   │  • Works with existing programs (no changes needed)               │       │
│   │  • "Virtual vsync" for terminals                                  │       │
│   └────────────────────────────────────────────────────────────────────┘       │
│                                                                                  │
│   ORIGIN: Inspired by Ink app cursor hide/show pattern                          │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘
It just works. You don’t need to configure anything. The Atomic Loop automatically detects frame boundaries from your existing terminal programs.

Next Steps