> ## 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

> Pixel-perfect scrolling with trackpad detection and Bezier animation

# 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

<CardGroup cols={2}>
  <Card title="Sync Rendering" icon="bolt" href="/terminal/rendering/sync-rendering">
    Immediate render for flicker-free display
  </Card>

  <Card title="xterm.js Renderer" icon="display" href="/architecture/rendering-system/xterm-renderer">
    How xterm.js is used as display component
  </Card>
</CardGroup>
