Documentation Index
Fetch the complete documentation index at: https://docs.monolex.ai/llms.txt
Use this file to discover all available pages before exploring further.
Smooth Scroll
MonoTerm implements pixel-level scroll accumulation for fluid scrolling experience, especially on trackpads.The Problem: Row-Based Scrolling
Traditional terminals scroll by whole rows. This creates jerky movement on trackpads that send sub-row pixel deltas.╔═══════════════════════════════════════════════════════════════════════════════╗
║ TRADITIONAL ROW-BASED SCROLLING ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Trackpad sends: deltaY = 3px, 5px, 2px, 4px, 6px... ║
║ ║
║ Row height = 20px ║
║ ║
║ ┌─────────────────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ Input: 3px 5px 2px 4px 6px (total: 20px) │ ║
║ │ │ │ │ │ │ │ ║
║ │ ▼ ▼ ▼ ▼ ▼ │ ║
║ │ Result: NONE NONE NONE NONE JUMP 1 ROW │ ║
║ │ │ ║
║ │ ────────────────────────┬──── │ ║
║ │ Nothing │ Sudden jump │ ║
║ │ │ ║
║ └─────────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ User experience: Laggy, then sudden jump ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
The Solution: Pixel Accumulation
MonoTerm accumulates sub-row pixel deltas until a full row is reached.╔═══════════════════════════════════════════════════════════════════════════════╗
║ PIXEL ACCUMULATION SCROLLING ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Trackpad sends: deltaY = 3px, 5px, 2px, 4px, 6px... ║
║ ║
║ Row height = 20px ║
║ ║
║ ┌─────────────────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ pendingY accumulator: │ ║
║ │ │ ║
║ │ Input: 3px 5px 2px 4px 6px │ ║
║ │ │ │ │ │ │ │ ║
║ │ ▼ ▼ ▼ ▼ ▼ │ ║
║ │ pendingY: 3 → 8 → 10 → 14 → 20 │ ║
║ │ │ │ │ │ │ │ ║
║ │ ▼ ▼ ▼ ▼ ▼ │ ║
║ │ Action: wait wait wait wait SCROLL 1 ROW │ ║
║ │ pendingY = 0 │ ║
║ │ │ ║
║ └─────────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ User experience: Smooth, predictable scrolling ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
State Tracking
The scroll state tracks accumulated pixel delta (pendingY), current row height, and animation status. When accumulated pixels exceed one row height, scrolling triggers and the remainder carries over.
Trackpad vs Mouse Detection
MonoTerm detects input device type and applies different scroll behavior.╔═══════════════════════════════════════════════════════════════════════════════╗
║ INPUT DEVICE DETECTION ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Detection logic: ║
║ ───────────────── ║
║ ║
║ isPrecision = Math.abs(ev.deltaY) < 10 && ║
║ ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL ║
║ ║
║ ║
║ ┌─────────────────────────────┐ ┌─────────────────────────────┐ ║
║ │ │ │ │ ║
║ │ TRACKPAD (isPrecision) │ │ MOUSE WHEEL (!isPrecision) │ ║
║ │ │ │ │ ║
║ │ deltaY: 1-9 pixels │ │ deltaY: 100+ pixels │ ║
║ │ deltaMode: PIXEL │ │ deltaMode: LINE or PAGE │ ║
║ │ │ │ │ ║
║ │ ┌───────────────────────┐ │ │ ┌───────────────────────┐ │ ║
║ │ │ Pixel accumulation │ │ │ │ Direct row scroll │ │ ║
║ │ │ + Bezier animation │ │ │ │ (traditional behavior)│ │ ║
║ │ └───────────────────────┘ │ │ └───────────────────────┘ │ ║
║ │ │ │ │ ║
║ └─────────────────────────────┘ └─────────────────────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
Bezier Animation
For smooth deceleration, MonoTerm applies easing functions to scroll animation.╔═══════════════════════════════════════════════════════════════════════════════╗
║ BEZIER EASING FUNCTIONS ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Available easing curves: ║
║ ║
║ ║
║ ease-out (default) ease-in ease-in-out ║
║ ───────────────── ──────── ─────────── ║
║ f(t) = 1 - (1-t)³ f(t) = t³ cubic-bezier ║
║ ║
║ │ xxxxxxx │ x │ xxx ║
║ │ xx │ x │ xx xx ║
║ │ x │ x │ x x ║
║ │x │ xx │ x x ║
║ │x │ xx │ x x ║
║ │x │ xx │x x║
║ └─────────── └─────────── └─────────── ║
║ ║
║ Fast start, Slow start, Smooth both ║
║ smooth stop fast end ends ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
Configuration
Users can customize scroll behavior via settings:| Setting | Default | Description |
|---|---|---|
terminalSmoothScrollDuration | 150ms | Animation duration |
terminalSmoothScrollEasing | ease-out | Easing function |
╔═══════════════════════════════════════════════════════════════════════════════╗
║ SCROLL BEHAVIOR FLOW ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Wheel Event ║
║ │ ║
║ ▼ ║
║ ┌─────────────────────┐ ║
║ │ Check alt buffer │──── YES ───▶ Direct scroll (vim/tmux mode) ║
║ └─────────┬───────────┘ ║
║ │ NO ║
║ ▼ ║
║ ┌─────────────────────┐ ║
║ │ isPrecision? │──── NO ────▶ Traditional row scroll ║
║ └─────────┬───────────┘ ║
║ │ YES (trackpad) ║
║ ▼ ║
║ ┌─────────────────────┐ ║
║ │ Add to pendingY │ ║
║ └─────────┬───────────┘ ║
║ │ ║
║ ▼ ║
║ ┌─────────────────────┐ ║
║ │ |pendingY| >= row? │──── NO ────▶ Wait for more input ║
║ └─────────┬───────────┘ ║
║ │ YES ║
║ ▼ ║
║ ┌─────────────────────┐ ║
║ │ Calculate rows │ ║
║ │ rows = pendingY/h │ ║
║ └─────────┬───────────┘ ║
║ │ ║
║ ▼ ║
║ ┌─────────────────────┐ ║
║ │ Animate scroll │ ║
║ │ (Bezier easing) │ ║
║ └─────────┬───────────┘ ║
║ │ ║
║ ▼ ║
║ ┌─────────────────────┐ ║
║ │ pendingY = remainder│ ║
║ └─────────────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
Alt Buffer Bypass
When in alternate screen mode (vim, tmux, less), smooth scroll is bypassed for native app handling.╔═══════════════════════════════════════════════════════════════════════════════╗
║ ALT BUFFER DETECTION ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ Normal buffer (shell): ║
║ ────────────────────── ║
║ ┌─────────────────────────────────────┐ ║
║ │ $ ls -la │ ║
║ │ total 48 │ ← Smooth scroll enabled ║
║ │ drwxr-xr-x 12 user staff 384 │ ║
║ │ -rw-r--r-- 1 user staff 1024 │ ║
║ └─────────────────────────────────────┘ ║
║ ║
║ ║
║ Alt buffer (vim/tmux): ║
║ ────────────────────── ║
║ ┌─────────────────────────────────────┐ ║
║ │ ~ │ ║
║ │ ~ VIM - file.txt │ ← Direct scroll to app ║
║ │ ~ │ (vim handles scrolling) ║
║ │ -- INSERT -- │ ║
║ └─────────────────────────────────────┘ ║
║ ║
║ ║
║ Detection: term.buffer.active.type === 'alternate' ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
Implementation
The wheel event handler follows the flow diagram above: check alt buffer, detect precision input, accumulate or direct scroll. The complete flow is described in the “Scroll Behavior Flow” diagram.Related Documentation
Sync Rendering
Immediate render for flicker-free display
xterm.js Renderer
How xterm.js is used as display component