---
url: /guide/terminal-model.md
description: >-
  Understand how Termless models terminal buffers -- cells, rows, scrollback,
  and the difference between screen and buffer regions.
---

# Terminal Buffer Model

## The Buffer

A terminal maintains a buffer of character cells organized in rows and columns.

```
┌─────────────────────────┐
│ scrollback row 0        │ ─┐
│ scrollback row 1        │  │ scrollback (history)
│ ...                     │  │
│ scrollback row N        │ ─┘
├─────────────────────────┤ ← base
│ screen row 0            │ ─┐
│ screen row 1            │  │ screen (rows × cols)
│ ...                     │  │
│ screen row (rows-1)     │ ─┘
└─────────────────────────┘
```

## Regions

| Region     | What it is                                                                                               | Empty when      |
| ---------- | -------------------------------------------------------------------------------------------------------- | --------------- |
| screen     | The fixed rows × cols grid. What the terminal renders.                                                   | Never           |
| scrollback | Lines that scrolled off the top of the screen.                                                           | Alt screen mode |
| buffer     | Everything: scrollback + screen.                                                                         | Never           |
| viewport   | What's visible at the current scroll position. At bottom: same as screen. Scrolled up: shows scrollback. | Never           |

## Normal Mode vs Alt Mode

Two separate buffers, not regions within one:

* **Normal mode** (default): Primary buffer. Output scrolls, scrollback accumulates above the screen. Used by shells, build tools, inline CLI.
* **Alt mode** (`\x1b[?1049h`): Separate clean `rows × cols` buffer, no scrollback. Used by fullscreen apps (vim, htop, TUI dashboards). Entering saves normal buffer; exiting restores it.

| Region     | Normal mode           | Alt mode          |
| ---------- | --------------------- | ----------------- |
| screen     | Bottom rows × cols    | Entire alt buffer |
| scrollback | Lines above screen    | Empty             |
| buffer     | scrollback + screen   | = screen          |
| viewport   | Window at viewportTop | = screen          |

## Cross-Reference: Terminology by Terminal

### Core buffer model (well-documented internals)

| Concept          | Termless                   | Ghostty                                | Kitty                              | xterm.js                  |
| ---------------- | -------------------------- | -------------------------------------- | ---------------------------------- | ------------------------- |
| Visible area     | **screen**                 | screen (screen coordinates)            | screen (`@screen`)                 | viewport (viewportY)      |
| History above    | **scrollback**             | scrollback buffer                      | scrollback / history buffer        | scrollback                |
| Everything       | **buffer**                 | absolute buffer (absolute coordinates) | text (`@text` = screen+scrollback) | buffer (`buffer.active`)  |
| Alt screen       | **altScreen** mode         | alternate screen buffer                | secondary screen (`@alternate`)    | alternate (`buffer.type`) |
| Scroll position  | **viewport** / viewportTop | viewportY (0=bottom)                   | scrolled\_by                        | viewportY (0=bottom)      |
| Single character | **cell**                   | GhosttyCell                            | CPUCell / GPUCell                  | IBufferCell               |
| Character row    | **row**                    | row                                    | line (LineBuf)                     | line (IBufferLine)        |

### Additional terminals (implement VT100/ECMA-48 buffer model)

All modern terminals implement the same underlying buffer model (normal + alternate screen, scrollback region). The table below shows how they expose these concepts:

| Terminal             | Visible area   | Scrollback               | Alt screen       | Notes                                                               |
| -------------------- | -------------- | ------------------------ | ---------------- | ------------------------------------------------------------------- |
| **WezTerm**          | viewport       | scrollback               | alternate        | Cross-platform, xterm-compatible. Uses "viewport" for visible area. |
| **iTerm2**           | session window | scrollback buffer        | alternate screen | macOS. "Session" = a terminal instance.                             |
| **foot**             | grid/window    | scrollback               | alternate        | Wayland-native, Kitty KB. Minimalist internals.                     |
| **Alacritty**        | display/grid   | history                  | alternate        | GPU-accelerated. `grid.rs` manages the buffer.                      |
| **xterm** (classic)  | screen         | saved lines / scrollback | alternate screen | The original reference terminal. ECMA-48.                           |
| **Terminal.app**     | window         | scrollback               | alternate screen | macOS built-in. 256-color only, limited features.                   |
| **tmux**             | pane window    | history                  | alternate        | Multiplexer. Adds its own scrollback on top of terminal's.          |
| **VS Code Terminal** | (xterm.js)     | (xterm.js)               | (xterm.js)       | Embedded xterm.js — same internals.                                 |
| **Contour**          | viewport       | scrollback               | alternate        | Modern terminal with DEC 2026 sync support.                         |
| **Windows Terminal** | viewport       | scrollback               | alternate screen | Uses ConPTY + its own VT parser.                                    |

### Silvery — UI framework layer

Silvery operates at a higher level (React component tree → rendered cells), not terminal emulation:

| Concept           | silvery term          | Notes                                                     |
| ----------------- | --------------------- | --------------------------------------------------------- |
| Visible area      | `board.screen`        | The rendered component tree output                        |
| Scroll position   | viewport offset       | In ScrollbackView, VirtualView, VirtualList               |
| Single character  | cell                  | In the output buffer                                      |
| Alt screen        | fullscreen mode       | `render(<App />, { fullscreen: true })`                   |
| Coordinate system | `(x, y)` column-first | CSS/DOM convention — different from Termless `(row, col)` |

### Standards

| Standard                                                                                           | Relevance                                                                              |
| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| [ECMA-48 / ISO 6429](https://ecma-international.org/publications-and-standards/standards/ecma-48/) | CSI/OSC sequences — the foundation. Defines SGR, cursor control, screen modes.         |
| [XTerm Control Sequences](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)                 | De facto terminal standard. Extends ECMA-48 with mouse, paste, true color, alt screen. |
| `smcup`/`rmcup` (terminfo)                                                                         | Enter/exit alternate screen — `\x1b[?1049h` / `\x1b[?1049l`.                           |
| [DEC 2026](https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036)              | Synchronized output — batch rendering to prevent tearing.                              |
| [Kitty Keyboard Protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/)                      | Unambiguous key identification. Supported by Ghostty, Kitty, WezTerm, foot.            |
| [OSC 8 Hyperlinks](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)             | Clickable hyperlinks in terminal output.                                               |

See also the [silvery terminal matrix](https://silvery.dev/reference/terminal-matrix) for the full capability matrix (colors, keyboard protocol, graphics, clipboard) across all terminals.

## Coordinate Systems

* **Termless**: `(row, col)` — row-first, 0-based. Matches terminal tradition (ANSI sequences are row-first: `\x1b[row;colH`).
* **Ghostty**: 4 coordinate systems (viewport, screen, scrollback, absolute), all row-first.
* **xterm.js**: `(y, x)` — row-first internally (`IBufferLine`).
* **Silvery**: `(x, y)` — column-first, matching CSS/DOM convention (`left`, `top`).

Silvery keeps `(x, y)` because it's a React-like UI framework where CSS conventions are natural. Termless keeps `(row, col)` because it's a terminal emulator library. Don't unify — each is correct for its domain.

## Cell

A cell holds one character with attributes:

* text, fg (Color), bg (Color)
* bold, faint, italic, underline, strikethrough, inverse, wide

## Migration: §9 naming (2026-07)

The full renamed vocabulary is `Terminal` (read contract, was `TerminalReadable`), `TestTerminal` (harness), `Region` / `Row` (was `RegionView` / `RowView`), `Color` (was `RGB`), `Cursor` `{col,row}` (was `CursorState` `{x,y}`), `RawOutput` (was `OutputView`), and `TextMatch` `{text,row,col,cells}` (was `TextPosition`). Those old type names are gone — they were pure aliases with no behavior of their own, so there was nothing to keep working.

A smaller set of old **fields and methods** still works as a deprecated back-compat mirror, because dropping them would change runtime behavior for any caller still using the old shape, not just its name:

| Old (deprecated)                                | New                                        | Notes                                                                                                                            |
| ----------------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `CellView`                                      | `Cell`                                     | Accessors return `Cell`; position comes from the query. `cell()`/`cellAt()` still populate the extra `row`/`col` for back-compat |
| `Cursor.x` / `Cursor.y`                         | `Cursor.col` / `Cursor.row`                | Kept required during the migration window                                                                                        |
| `term.out`                                      | `term.output`                              |                                                                                                                                  |
| `getLine` / `getLines(): Cell[][]`              | `getRow` / `getRows`                       | row = cells (text lines keep `getLines`)                                                                                         |
| `viewportOffset` / `totalLines` / `screenLines` | `viewportTop` / `totalRows` / `screenRows` | Kept required during the migration window                                                                                        |
| `find` / `findAll`                              | `findText` / `findAllText`                 | return `TextMatch`                                                                                                               |
| `MouseOptions.button: 0\|1\|2`                  | `"left"\|"middle"\|"right"`                | numbers still accepted                                                                                                           |
| `UnderlineStyle: false`                         | `"none"`                                   | `false` still accepted                                                                                                           |

Kept unchanged: `waitFor`; `Region.getText()`/`getLines(): string[]`; the `buffer`/`screen`/`viewport`/`scrollback` regions; `Recording` `commands`/`io`.
