Terminal transport layer for Milpa Live: a retained-mode TUI runtime with virtual-buffer diffing, its own ANSI painter, focus and shortcut management, and the node renderers that paint Milpa Live components in the terminal for the Milpa PHP framework.
Terminal transport layer for Milpa Live: a retained-mode TUI runtime with virtual-buffer diffing, its own ANSI painter, focus and shortcut management, and the node renderers that paint Milpa Live components in the terminal for the Milpa PHP framework.
v0.3.0 2026-07-28 01:18 UTC
This package is auto-updated.
Last update: 2026-07-28 01:18:43 UTC
The terminal surface for
milpa/live— a retained-mode runtime that diffs a virtual terminal buffer and repaints only what changed, its own ANSI painter, focus and shortcut management, and 23 node renderers.
milpa/live defines the render-target-agnostic component lifecycle (mount / handle / render,
contracts, data sources). milpa/live-tui is what makes that lifecycle reachable from a terminal:
a node tree, a layout engine that resolves it into bounds, 23 renderers that paint those bounds,
and a loop that writes only the rows that actually changed.
It is the sibling of milpa/live-web, not its
dependent. Both are transports of the same engine; neither requires the other.
composer require milpa/live-tuiWhat it is
RetainedTuiLoop — the retained-mode loop. Renders the tree into a VirtualTerminalBuffer,
diffs it against the previous frame, and writes only the changed rows. An identical frame costs
zero writes. It owns focus, key dispatch, session values, and the input buffer for the run.VirtualTerminalBuffer — a fixed grid of cells that frames composite into. Its diff() is
the whole reason this is a retained runtime rather than a redrawn one.SimpleTuiLayoutEngine — resolves a TuiNode tree into absolute bounds plus a paint order,
clipped to the viewport, so a renderer is handed the rectangle it may paint and never computes
geometry itself.data-table, select-list, settings-list, editor, text-input,
markdown, log-view, job-monitor, command-palette, progress-bar, loader,
cancellable-loader, box, badge, divider, spacer, text, image, status-bar,
milpa-logo, plus the structural and fallback ones. Each is pure: node plus bounds in, lines out.InputBuffer (partial escape sequences held across reads), Key
(modifier naming), KeyMatcher, BracketedPaste, WordNavigation, KillRing, UndoStack,
and Grapheme/TuiString for cell-accurate width.TuiComponentRenderer — renders a Live component to the terminal, the counterpart of the
HTML renderers in milpa/live-web. Same component definition, same state snapshot, different
target: this is the seam that lets one component description serve both surfaces.Width is measured in cells, never bytes. Everything goes through TuiString, which ignores
ANSI sequences and counts wide graphemes as the columns they really take. The buffer composites at
bounds without clamping, so a renderer that mismeasured would not produce a wrong string — it
would corrupt neighbouring cells.
Dispatch is on shape, never on identity. A renderer decides by the node's declared type; the
registry asks each renderer in turn and the first match wins. An unknown type resolves to null
rather than being guessed at. Nothing in this package knows which section of which application it
is drawing.
use Milpa\Live\Tui\NodeRenderers\DataTableRenderer; use Milpa\Live\ValueObjects\Tui\{TuiBounds, TuiNode, TuiRenderContext}; $frame = (new DataTableRenderer())->render( new TuiNode('routes', 'data-table', props: [ // `columns` are declarations, not labels: a list of plain strings // renders nothing. 'columns' => [ ['key' => 'method', 'label' => 'method'], ['key' => 'path', 'label' => 'path'], ], 'rows' => [ ['method' => 'GET', 'path' => '/'], ['method' => 'PUT', 'path' => '/agency/api/account'], ], ]), new TuiRenderContext(new TuiBounds(0, 0, 48, 6)), ); echo implode(PHP_EOL, $frame->lines);
And the retained core, which is what the loop is built on:
use Milpa\Live\Tui\VirtualTerminalBuffer; $previous = new VirtualTerminalBuffer(80, 24); $current = new VirtualTerminalBuffer(80, 24); $current->writeFrame($bounds, $frame); foreach ($current->diff($previous)->changes as $change) { // Only these rows ever reach the terminal. printf("\033[%d;1H%s", $change['row'] + 1, $change['line']); }What's inside
| Namespace | What it provides |
|---|---|
Milpa\Live\Tui |
RetainedTuiLoop, InteractiveTuiLoop, RetainedTuiRenderer, VirtualTerminalBuffer, SimpleTuiLayoutEngine, TuiNodeRendererRegistry, TuiAnsiPainter, StreamTerminal, FocusManager, TerminalTheme, TuiString, Grapheme, InputBuffer, Key, KeyMatcher |
Milpa\Live\Tui\NodeRenderers |
The 23 renderers, plus AbstractTuiNodeRenderer with the shared box/fit/pad helpers |
Milpa\Live\Rendering |
TuiComponentRenderer — the Live-component-to-terminal renderer |
Milpa\Live\Contracts\Tui |
TerminalInterface, VirtualTerminalBufferInterface, TuiLayoutEngineInterface, TuiNodeRendererInterface, TuiNodeRendererRegistryInterface, FocusManagerInterface, FocusableInterface, ShortcutRegistryInterface, TuiEventBusInterface, TuiStateManagerInterface, BackgroundJobManagerInterface, AutocompleteProviderInterface, TerminalThemeInterface |
Milpa\Live\ValueObjects\Tui |
TuiNode, TuiBounds, TuiFrame, TuiLayoutFrame, TuiBufferDiff, TuiRenderContext, TuiEvent, ShortcutBinding, BackgroundJob |
Every public symbol carries a DocBlock — 79 types, 240 public methods, enforced by CI.
Requirementsmilpa/core ^0.6milpa/live ^0.1No terminal extension is required. ext-pcntl is used opportunistically for SIGWINCH resize
handling and its absence only costs you live resize.
Stated plainly, because the package is 0.x and the evidence behind it is specific:
milpa/live is pinned at ^0.1, which is pre-1.0 on both sides.Full API reference: getmilpa.github.io/live-tui — generated straight from the source DocBlocks and dressed with the Milpa design system.
ContributingContributions are welcome — see CONTRIBUTING.md. Please report security issues via SECURITY.md, and note that this project follows a Code of Conduct.
LicenseApache-2.0 © Rodrigo Vicente - TeamX Agency.
Milpa is designed, built, and maintained by Rodrigo Vicente - TeamX Agency.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | milpa/live (v0.2.0) | 0 | 17.79 | 28-07-2026 |
| 2 | milpa/live-web (v0.2.0) | 0 | 18.48 | 28-07-2026 |
| 3 | milpa/auth (v0.3.0) | 0 | 10.94 | 28-07-2026 |
| 4 | milpa/orchestrator (v0.3.0) | 0 | 16.04 | 28-07-2026 |
| 5 | milpa/http-symfony (v0.1.0) | 0 | 12.31 | 28-07-2026 |
| 6 | milpa/admin (v0.1.0) | 0 | 11.16 | 28-07-2026 |
| 7 | milpa/skeleton (v0.10.0) | 0 | 20.4 | 28-07-2026 |
| 8 | seip25/lila-php (v1.59) | 0 | 38 | 28-07-2026 |
| 9 | textproc/livediff - 3.2.0 | 0 | 5 | 13-07-2026 |
| 10 | sli-ui-toolkit 3.1.11 | 0 | 5 | 20-07-2026 |