omp packages

@liuovo/pi-tools-ui0.0.10

Compact, reason-first tool output for pi with configurable layouts, live status, and diffs on demand.

liuovo Published 12 days ago MIT ~1.6K downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-tools-ui

这是基于 mikeyobrien/pi-tidy-tools 中的 pi-tidy-tools 扩展进行二次开发的独立仓库,并非上游官方项目。 原作者为 Mikey O'Brien,原始代码的 MIT 许可证及版权声明保留在 LICENSE 中。

本仓库仅提取上游的 packages/pi-tidy-tools 及其必需的 vendor/pi-tidy-core 源码快照,不包含 bots、footer、memory、subagents 等其他扩展。 初始代码来自上游提交 da148ac7f33371d9855632ea62f288ba929357d0, 对应包版本 0.4.2。目前已完成独立项目适配,后续在此基础上开发。

This is an independent derivative of pi-tidy-tools, not an official upstream release. It is published separately as @liuovo/pi-tools-ui, with its own version history. Management uses /liuovo; there is no /tidy alias or automatic migration of upstream configuration, environment variables, or integration journals.

See what your Pi agent is doing at a glance. Restyles Pi's built-in tools (read write edit bash grep find ls) into compact, configurable blocks — a two-line default plus optional one-line reasoning and result layouts — so the transcript reads like a narrative, not a wall of boxes.

Install

Targets Pi 1.1.0 (coding-agent and pi-tui), the pinned development and acceptance baseline. There are no old-host compatibility branches. Host-provided peer dependencies use "*" per Pi package guidance; this is not a promise of support for every host version.

After the first npm release, install this derivative with Pi:

pi install npm:@liuovo/pi-tools-ui

Do not enable the npm package together with a local copy or the upstream extension: they register the same tools and commands.

To develop locally, install dependencies and load this copy (Node.js 22.19.0+):

cd ~/code/me/pi-tools-ui
npm ci
pi -e ./index.ts

To keep using the local copy across sessions:

pi install ~/code/me/pi-tools-ui

Do not enable both this copy and the upstream npm extension at once: they register the same tools and commands. Local source edits take effect after /reload or a restart. To remove this copy later:

pi remove ~/code/me/pi-tools-ui

Codemode rendering needs no setup. Pi owns its execution and activation; see native codemode. /liuovo setup manages only optional FFF. Upgrading from a codemode-ownership version? Follow the breaking upgrade steps before reloading.

Before and after

The same successful read, grep, and edit calls rendered by native Pi and liuovo:

Native Pi tool cards compared with compact liuovo output

  • Line 1 — tool icon/name and the model's goal/reasoning; running calls add a live dot.
  • Line 2 — the concrete target (path/command/pattern) and a colored result summary.

Basic tools use Pi's official definitions. Reasoning is stripped before execution; write additionally captures its before/after diff inside Pi's file-mutation queue. Rendering is registered separately through registerToolRenderer(). The optional pi-fff integration can substitute FFF search execution behind the same liuovo presentation.

In action

liuovo transcript showing successful and failed tool calls

Reasoning headline

In default and reasoning modes, each wrapped tool gains a required reasoning parameter that the model fills with the goal behind the call (not a restatement of the file or command, which is already shown). result mode leaves the native tool schema unchanged and does not request reasoning.

Expand for detail (ctrl+o)

Collapsed blocks show the two-line summary. Expanding a tool (ctrl+o, app.tools.expand) appends its full output:

  • edit — the colored, line-numbered diff
  • write — the written content with line numbers
  • bash — the full (multi-line) command input, then its output
  • read/grep/… — the raw result text

Configure with /liuovo

The extension is enabled by default. Use the management command to change or inspect its startup state:

/liuovo setup
/liuovo teardown
/liuovo on
/liuovo off
/liuovo toggle
/liuovo status
/liuovo mode default
/liuovo mode reasoning
/liuovo mode result
/liuovo mode status
/liuovo icons on
/liuovo icons off
/liuovo icons status
/liuovo icons auto
/liuovo icons nerd
/liuovo icons ascii

Native codemode

Keep builtin:codemode loaded. This extension registers only its renderers; it does not register a codemode tool, invoke its factory, change its native schema/grammar, or activate it. The same renderer can display historical records even when a current tool definition is unavailable.

Enable codemode with Pi's tool selection, for example in your Pi settings:

{
  "defaultTools": ["+codemode"]
}

Merge this with your existing tool selection; do not replace a custom defaultTools list blindly. CLI tool selection still takes precedence. Remove stale -builtin:codemode exclusions when leaving an older managed setup. Pi's codemode.mode and codemode.inlineBudget keep their native meanings. /liuovo status reports Pi-owned; active/inactive, not plugin ownership.

FFF setup (optional)

/liuovo setup validates the installed FFF package, previews its package-entry changes, asks for confirmation, and reloads once. It never edits defaultTools or codemode extension directives. Missing FFF is not installed automatically; there is nothing to set up. Repeating setup is safe.

FFF ownership/recovery uses liuovo.pi-fff.json beside each participating settings file. UI preferences remain in liuovo.json under Pi's agent directory (normally ~/.pi/agent, respecting PI_CODING_AGENT_DIR). /liuovo teardown restores the exact managed FFF entries, not codemode settings. Run teardown before removing managed FFF or this plugin. Failed or interrupted FFF reloads retain recovery journals; reload and follow /liuovo status.

Breaking upgrade

There is deliberately no permanent migration or historical compatibility layer.

  1. Back up user/project settings.json, liuovo.codemode.json, and liuovo.pi-fff.json before switching.
  2. While the old plugin is still loaded, run its /liuovo teardown in the affected projects. This restores both codemode directives/tool selection and FFF package filters. Check all projects recorded in the old journals before retiring them. If already reloaded, temporarily use the old version for teardown, or restore the recorded directives manually from backups; do not load old and new copies together.
  3. Switch to this version on Pi 1.1.0. Ensure builtin:codemode is not excluded, remove stale -builtin:codemode, and enable it through Pi's tool selection if wanted. Confirm with /liuovo status.
  4. If using FFF, keep only @ff-labs/pi-fff@0.11.0 and run the new /liuovo setup to manage FFF alone.
  5. Remove obsolete codemode journals only after every recorded scope has been restored. The new plugin neither reads nor migrates them.

No upgrade command automatically rewrites personal Pi settings. MCP cards, sampling configuration, provider routing, and authentication remain outside this migration.

Layout modes

  • default — reasoning headline, then target and result on line two
  • reasoning — one line with the reasoning and summarized result
  • result — one line with the target and summarized result; no reasoning parameter is requested

Liuovo Tools layout modes

A successful state, layout, or icon change is saved to ~/.pi/agent/liuovo.json and reloads Pi's extensions immediately. While disabled, /liuovo remains available, but all seven tool overrides, reasoning prompts, custom tool rendering, and terminal title status are absent. Native codemode remains under Pi's control; turning presentation off does not remove its executor or change activation.

Icon visibility is a top-level JSON boolean and defaults to true when missing, malformed, unreadable, or not a boolean:

{
  "icons": false
}

/liuovo icons off persistently removes decorative icons from tool/codemode headings. It does not reserve an empty icon column. The semantic running dot, hanging detail indent, and result arrow stay visible, as do colors, names, summaries, expansion, and compact layouts. Settled success and failure use Pi's native state backgrounds without redundant inline marks. /liuovo icons on|off reloads after a change; status is read-only and repeated values do not write or reload.

Font selection is separate from visibility and never overwrites the icons boolean:

{
  "icons": true,
  "iconMode": "auto"
}
  • auto (default): uses Nerd Font glyphs in an interactive UTF-8 terminal; SSH, non-TTY output, TERM=dumb, or an explicitly non-UTF-8 locale uses ASCII.
  • nerd: forces Nerd Font glyphs. Select a patched font in your terminal's preferences; installing a font alone is not enough. Use this over SSH when your client terminal already has a Nerd Font.
  • ascii: compact text symbols such as [r], [$], and [<>]; no emoji.

Auto is an environment heuristic, not actual font detection. If you see squares, select a Nerd Font or use /liuovo icons ascii. /liuovo icons nerd|ascii|auto saves the mode and reloads only when changed; it does not turn hidden icons on. /liuovo icons status reports visibility, selected mode, and resolved mode. Malformed or missing iconMode falls back to auto. This extension neither reads nor changes pi-open-tui settings.

For temporary or managed environments, PI_LIUOVO overrides only whole extension enablement. It accepts on/off, true/false, yes/no, or 1/0. Unset the variable before using /liuovo on|off|toggle; /liuovo status reports when the override is active. There is no environment override for icon visibility, so /liuovo icons on|off remains available while PI_LIUOVO controls enablement. A missing, unreadable, or malformed enablement config defaults to enabled.

Terminal title status

While enabled, the extension owns the TUI terminal title:

  • Idle: π - session name - directory (the session name is omitted when unset).
  • Working: a braille spinner, updated every 120ms.
  • Waiting for input: ? while an active task opens a ctx.ui.confirm, select, input, or editor dialog; the spinner timer is paused.
  • Settled: ✓ completed, ! failed, or ⏹ cancelled.

The spinner continues through retries, automatic compaction, and queued follow-ups, pauses for the dialogs above, and ends at agent_settled. Outcomes come from Pi run/turn boundaries and agent_settled.aborted, not individual tool errors. Metadata changes preserve the current frame, and continuous work does not restart the animation. A settled marker stays until the next task or session/branch change. Session shutdown (including reload) clears the timer and restores the base title. RPC, JSON, and print modes never write titles or start animation timers.

Closing or dismissing a dialog resumes the same animation frame. A late close never restarts an already settled or reset task. Ordinary assistant questions, idle-session dialogs, and all custom UI (such as passive detail viewers) do not trigger ?; custom interfaces cannot reliably be distinguished from passive browsers. Pi coalesces nested dialogs into one outer prompt interval; a custom outer view therefore remains excluded even if it contains an input dialog.

Pi 1.1 reports cancellation through agent_settled.aborted, including retry backoff; cancellation consistently displays ⏹ without retaining old run signals. OSC 7501 program-status reporting remains Pi-owned; this extension only writes the terminal title and never emits duplicate status sequences.

This follows /liuovo on|off (and PI_LIUOVO); there is no separate title setting. /liuovo icons off does not hide these semantic status markers. Remove the standalone ~/.pi/agent/extensions/title-status.ts when migrating: loading both extensions would give two writers ownership of the same title.

Native Markdown

Markdown rendering belongs entirely to Pi. This plugin does not register Markdown transformers, rewrite links or alert blocks, or render Mermaid diagrams. Use Pi's markdown.mermaid setting (off, final, or streaming) for native diagram behavior.

Optional pi-fff execution

FFF remains an optional, separately installed package, not a dependency of liuovo. The only supported combination is Pi 1.1.0 + @ff-labs/pi-fff@0.11.0. Legacy pi-fff and historical scoped versions are not adapted. Upgrading FFF requires updating and revalidating this integration.

pi install npm:@ff-labs/pi-fff@0.11.0
# Or project scope:
# pi install -l npm:@ff-labs/pi-fff@0.11.0

Then run /liuovo setup. FFF executes public grep and find; liuovo adds reasoning and compact rendering, and the raw ffgrep/fffind names stay hidden. Native read is unchanged. Source metadata, commands, flags, autocomplete and lifecycle callbacks are forwarded once. Use FFF's tools-and-ui (default) or tools-only, not its conflicting override mode.

Current FFF still imports @sinclair/typebox; its mapping to the running Pi's shared TypeBox is intentionally retained. Old Pi package-name aliases are removed.

Status validated means the pinned package and required registration surface passed local checks; it is not a historical compatibility-matrix certification. Installation/terminal verification and drift recovery are described in docs/pi-fff.md. Run /liuovo teardown before removing either managed package.

Styling

Tool identity uses a small set of theme colors rather than a uniform toolTitle. Each tool has its own Nerd Font glyph; standalone and nested tools share the same styling.

Tools Glyph meaning Theme palette role (built-in appearance)
read / grep / find / ls Text file / search / binoculars / folder syntaxVariable (cyan)
write / edit Save / edit syntaxFunction (warm yellow)
bash Terminal syntaxKeyword (blue)
codemode Code accent (violet)

Icons and names share a color; goals use body text, targets use readable muted text, and separators recede. Counts highlight the number, not the whole phrase. Elapsed time uses an unbolded palette color, without arbitrary slow-task alarms. Errors/warnings and diff additions/deletions retain their semantic colors. Custom themes control the actual hues; no fixed light/dark RGB palette is imposed. Regenerate the HTML review from the real renderers and installed host palettes:

COLORTERM=truecolor npx tsx docs/visual-preview.ts > /tmp/liuovo-visual.html
COLORTERM=truecolor npx tsx docs/visual-preview.ts --ansi dark

The HTML preview needs a Nerd Font (e.g. Maple Mono NF CN) for its glyphs. The older screenshots above illustrate layout features, not the current icon palette.

  • Paths collapse $HOME → ~
  • edit shows +adds/-dels; text write shows line count; bash shows status + elapsed time
  • grep shows N matches in M files; find/ls show file or entry counts
  • Tool blocks use Pi's outputPad on both sides (default 1; 0 is supported). Narrow screens reduce padding to retain content. Reused components update padding without stale cached layout.
  • Every line fits the live terminal width (ANSI-aware); compact headlines keep tool identity and prioritize results over long descriptions
  • Pi's native pending/success/error backgrounds remain, without its larger padding or extra blank rows
  • Execution time starts at tool_execution_start, excluding streamed arguments; tool cards share one 1-second redraw ticker, and historical cards start no timers

Foregrounds and diffs use Pi's semantic theme colors; pending/success/error backgrounds remain native. system, light, dark, and custom themes apply to running and settled cards. Individual edit/write diffs and nested output previews remain available by expanding the corresponding tool card.

Codemode parent/child cards

Whenever enabled, liuovo renders native codemode as one compact inline card: a one-line parent heading followed by indented child tools, matching the basic tools' goal/target hierarchy. Siblings with the same tool name and non-empty reasoning share one heading even when other tools intervene. Groups follow first occurrence; calls within a group retain their original order. This is a grouped overview, not a chronological execution log. Each call keeps its own target/result row, including repeated reads of the same file. There is no bottom status widget or separate /liuovo calls screen. Ctrl+O expands the whole card, including the children's bounded output/diff previews. Script source and script output appear last, only when expanded.

codemode 修正配置并验证  ·  3 calls · 1 error · 8s
  edit 修正超时配置
    src/config.ts → +2/-1
  read 确认配置内容
    src/config.ts → 24 lines
  bash 验证修改是否通过测试
    npm test → exit 1 in 8s

The parent title comes from an explicit // reasoning: <goal> comment at the start of the script (after an optional first // @options: line). The model is instructed to include this comment; without it the title falls back to “执行工具脚本”. The native schema and raw-JavaScript grammar are unchanged. Children use their existing reasoning and target fields. Icons follow /liuovo icons; the goal/target hierarchy is the same in all liuovo modes. Heading sharing applies while running, after completion, and when expanded. Different reasons, tools, or parents start a new heading. Descendants stay with their own parent call, not with a same-reason call in another branch. Missing reasons do not cause grouping. Grouping only changes presentation; execution and persisted call order are unchanged. Expansion retains each call's own output and diff below its result row. The parent separates its overview with a muted dot; child target/result rows keep an arrow. No borders, tree connectors, extra blank rows, or per-metric icons are added. On narrow screens, parent failures precede less important call totals. Completed cards omit zero running/error counts; failures remain visible in the parent summary and the failed child's result line. A successful script can still contain failed children, so its native background may be green with red child status text.

The plugin registers only a codemode renderer, leaving the native executor, loadout preparation, exposure, settings, script storage, sandbox, permissions, output protection and usage accounting with Pi. Script reasoning guidance is added to before_agent_start prompt sections only when codemode is selected. It never modifies the native definition's prompt metadata.

Native models.classify() and models.generateImages() calls show their model reference, live status, duration and reported cost. These are model calls, not JSON-argument tool calls: they do not produce false incomplete-record warnings. Usage stays owned by Pi and is never added a second time by the renderer. No synthetic messages or UI-only output are sent to the model. Nested edit/write results retain their per-call diff previews inside the codemode card.

The observer retains at most 256 calls including parents per batch. The card shows the first eight calls when collapsed and up to 256 records when expanded. The preview limit is applied before grouping, so later same-reason calls cannot push an earlier error or another tool out of the preview. Shared headings do not change the call count or this preview limit. Reasoning, targets and summaries are capped at 240 characters; each child output preview is capped at 2,048 characters/24 lines, with a 32,768-character preview budget per batch. Expanded script source and output each have an 8,192-character/80-line display cap. Omitted data is marked, and supplied full-output paths remain visible when expanded.

Versioned raw display records are stored in result details, independently for each parent card, so previous cards survive subsequent turns, reloads and theme changes. Old native records remain readable; missing child output is labeled Output not recorded, and missing hierarchy is not inferred. Session/branch changes clear live state. Unfinished children become incomplete/cancelled, and late authoritative completion events replace inferred closure without accepting duplicate ends. RPC/JSON/print modes never open terminal widgets or overlays.

Structured results

Bash summaries prefer structured exit codes and truncation information. Final durations come from Pi's durationMs render context and nested execution-end events, not plugin wall-clock metadata. Reloads keep the recorded duration; missing durations are not fabricated. Live estimates retain the shared ticker. Expanded cards show the full-output path when supplied. Only bounded summary metadata is copied into display details: the programmatic output is not duplicated into cards. Pi 1.1.0 passes only content/details to result renderers, so the bounded shell metadata copy remains necessary. Tools without these fields keep the text-based fallback. Tool output schemas, results, errors, and usage remain owned by the source tool.

Image generation

generate_image now calls Pi's native ctx.modelRegistry.generateImages(). Authentication and the model catalog belong to Pi: sign in with /login or use the provider's normal environment variables. The tool saves every returned image under .fleet/images/pi/ in the session working directory, and returns paths plus structured { provider, model, images } data, never base64. Reported usage is forwarded once, including errors after a paid generation.

Defaults: provider openrouter, model google/gemini-2.5-flash-image. Override with PI_LIUOVO_IMAGE_PROVIDER / PI_LIUOVO_IMAGE_MODEL, or per call:

const saved = await tools.generate_image({
  prompt: "A watercolor fox in the snow",
  provider: "openrouter",
  model: "google/gemini-2.5-flash-image",
});
text(saved);

Use models.getAvailableOfType("image") in codemode to discover models with configured credentials. For inline image display or input-image editing, use native models.generateImages() and image(block) directly; that API does not save images to disk. The codemode card displays model-call metadata while Pi handles inline image blocks.

Breaking change: the private grok-build provider registry/auth-cache reader and aspect/resolution/count arguments are removed. Pi's provider-neutral image API does not guarantee those sizing/count controls; describe preferences in the prompt, or use a provider extension for provider-specific controls. A private grok-build login is not automatically migrated to Pi credentials. PI_LIUOVO_FLEET_DIR and PI_LIUOVO_BOTS_NAME still control the output root. Cancellation is forwarded to Pi; incomplete files are cleaned up on errors.

Scope

The seven basic tools and the official codemode parent card are restyled. Direct MCP / third-party calls keep their own renderers; when invoked inside codemode, their observed activity is summarized within that parent card. The plugin does not replace foreign executors or implement model routing or classifier decisions. It also owns terminal title status while enabled. It does not provide a /diff command, bind ctrl+shift+o, or keep a task-level change history. For repository-wide changes use Git; individual tool diffs remain available via expansion. Markdown is left untouched.

Troubleshooting

Symptom Fix
/liuovo on|off|toggle appears to have no effect The PI_LIUOVO environment variable overrides the config file. Unset it first; /liuovo status reports when the override is active.
Setup completed but pi-fff is not managed keeps appearing Upgrade and rerun /liuovo setup. Already-filtered extensions: [] packages now retain their ownership journal across reload. Do not suppress the warning or fabricate a sidecar.
codemode is unavailable/inactive Restore native builtin:codemode loading, remove stale -builtin:codemode, then enable it through Pi tool selection. New /liuovo setup does not activate it.
/liuovo status reports recovery-pending An interrupted setup/teardown awaits Pi's reload. Run /reload; the next startup finalizes the transition at a safe boundary.
Status reports unsafe partial registration; reload required Tool ownership is unknown after a replay failure. Run /reload before trusting any read/grep/find claim.
PIFFF_VERSION_UNSUPPORTED Install the pinned @ff-labs/pi-fff@0.11.0, or re-audit the adapter before changing versions.
Removed pi-fff or liuovo without running teardown Follow the manual restoration steps in docs/pi-fff.md.

Local development

From this repository root, quick-test the extension:

pi -e ./index.ts

Or install the local package through ~/.pi/agent/settings.json:

{
  "packages": ["/absolute/path/to/pi-tools-ui"]
}

Develop

Run from this repository root; no sibling repository or workspace is needed:

npm ci
npm test
npm run check
npm run test:pack

Development dependencies and host acceptance tests are pinned to Pi 1.1.0. Run the offline host smoke with npm run test:host-smoke, or select an installed Pi 1.1.0 package explicitly:

PI_TOOLS_UI_HOST_ROOT=/path/to/node_modules/@earendil-works/pi-coding-agent \
  npm run test:host-smoke
npm run test:pi-fff-installed
npm run test:pi-fff-tui
PI_FFF_TUI_MODE=regular npm run test:pi-fff-tui

The host smoke uses isolated temporary settings, a scripted model stream, stubbed image providers and disabled fetch; no model charges. It checks native codemode ownership/activation, unchanged settings after setup/teardown without FFF, renderer resolution, nested calls, exactly-once usage, write diffs, shell metadata, replay and HTML export, native mode/inlineBudget/output limits, nested cancellation, theme invalidation, title lifecycles, native duration and padding, image read/show/save, async tool guidance, and text/console boundaries. See Pi 1.1 upgrade notes for the scope retained after syncing v0.0.9.

FFF installed/TUI tests use the one pinned combination and temporary directories. They require npm access; the PTY test also needs util-linux script(1). The installed test covers user/project/combined scope. Neither the unit tests nor a successful PTY smoke substitutes for a visual check in your actual terminal.

Optional quality gates: npm run test:coverage and npm run test:mutation. The pi-fff installed/TUI checks need registry access and install their fixtures in temporary directories. The vendored core is checked in directly, not regenerated from a sibling package.

发布到 npm

本项目使用 bumpp 管理版本号、Git 提交和标签, 再由 npm publish 发布 @liuovo/pi-tools-ui。 publishConfig.access 已设为 public,不需要购买 npm 私有包服务。 GitHub 仓库是否私有与 npm 包可见性无关:发布后,打包的源码、README 和图片均公开可下载。

发版开发环境请使用 Node.js ^22.18.0 || ^24.11.0 || >=26.0.0 中同时满足本包要求的版本; 推荐 Node.js 24.11+。这是 bumpp 的开发依赖要求,不改变扩展本身的 Node.js 22.19.0+ 要求。

首次配置后,先提交这些修改并推送到 main,确保工作区干净且已配置 origin。 在自己的终端登录 npm(不要把密码、Token 或验证码写入仓库):

npm login --registry=https://registry.npmjs.org/
npm whoami --registry=https://registry.npmjs.org/ # 应为 liuovo
npm run release

在交互菜单中选择目标版本;此次 Pi 1.0.2 改造是破坏性更新,应先完成上面的切换步骤。 上游 0.4.2 仅表示代码来源,不作为本包版本。修改源码和运行验收本身不会提交或发布包。

确认后会依次:

  1. 通过 preversion 执行类型检查、测试和解包加载检查。
  2. 同步更新 package.json 和 package-lock.json。
  3. 创建 chore: release vX.Y.Z 提交和 vX.Y.Z 标签,并推送到 GitHub。
  4. 执行 npm publish;prepublishOnly 会再次检查最终版本的包,随后按 npm 提示完成身份验证。

取消 bumpp 确认不会发布。bumpp 不生成 changelog 或 GitHub Release;CHANGELOG.md 的 Unreleased 节记录二开变更,后面的旧版本记录来自上游。 提交标签和 npm 发布不是原子操作:如果推送成功但 npm 发布失败,先确认该版本尚未发布, 解决身份验证等问题后运行 npm publish 重试即可,不要再次运行 npm run release 升版本。

只检查、不发布:

npm run release:check
npm publish --dry-run

Regenerating screenshots

docs/comparison.png, docs/demo.png, and docs/modes.png are generated from real renderer output (no hand-typed ANSI). docs/demo.png shows icons-off output at normal and narrow widths: the scripts run the built-in tools, render them through the actual extension (or native Pi cards for the comparison), and screenshot the result via headless Chrome.

bash docs/comparison.sh # native vs liuovo comparison
bash docs/demo.sh       # full liuovo transcript
bash docs/modes.sh      # layout-mode comparison

All three generators require Google Chrome/Chromium and ImageMagick.