Links
AI / Agents
gdtest-termshow
A demo package showing the termshow terminal recording feature
Installation
pip install gdtest-termshowGet Started
- API Reference — Full API documentation
- User Guide — Guides and tutorials
Source files
demos/
getting-started.termshow
{"version": 1, "format": "termshow", "term": {"cols": 80, "rows": 20, "type": "xterm-256color"}, "title": "Getting Started"}
[0.5, "o", "\u001b[32m\u001b[1m$\u001b[0m "]
[0.08, "o", "p"]
[0.06, "o", "i"]
[0.07, "o", "p"]
[0.1, "o", " "]
[0.07, "o", "i"]
[0.06, "o", "n"]
[0.08, "o", "s"]
[0.06, "o", "t"]
[0.07, "o", "a"]
[0.06, "o", "l"]
[0.08, "o", "l"]
[0.1, "o", " "]
[0.07, "o", "m"]
[0.06, "o", "y"]
[0.08, "o", "-"]
[0.06, "o", "t"]
[0.07, "o", "o"]
[0.06, "o", "o"]
[0.08, "o", "l"]
[0.6, "o", "\r\n"]
[0.3, "o", "\u001b[2K\u001b[33mCollecting my-tool...\u001b[0m\r\n"]
[0.8, "o", "\u001b[2K\u001b[33mDownloading my_tool-1.0.0-py3-none-any.whl (12 kB)\u001b[0m\r\n"]
[0.5, "o", "\u001b[2K\u001b[32mSuccessfully installed my-tool-1.0.0\u001b[0m\r\n"]
[1.0, "m", "Installation complete"]
[0.8, "o", "\u001b[32m\u001b[1m$\u001b[0m "]
[0.08, "o", "m"]
[0.06, "o", "y"]
[0.08, "o", "-"]
[0.06, "o", "t"]
[0.07, "o", "o"]
[0.06, "o", "o"]
[0.08, "o", "l"]
[0.1, "o", " "]
[0.07, "o", "i"]
[0.06, "o", "n"]
[0.08, "o", "i"]
[0.06, "o", "t"]
[0.6, "o", "\r\n"]
[0.2, "o", "\u001b[36m\u001b[1m\u2728 Initializing new project...\u001b[0m\r\n"]
[0.5, "o", "\r\n"]
[0.1, "o", " \u001b[1mProject name:\u001b[0m my-awesome-project\r\n"]
[0.1, "o", " \u001b[1mTemplate:\u001b[0m default\r\n"]
[0.1, "o", " \u001b[1mDirectory:\u001b[0m ./my-awesome-project/\r\n"]
[0.3, "o", "\r\n"]
[0.2, "o", "\u001b[32m\u2714 Project created successfully!\u001b[0m\r\n"]
[1.0, "m", "Project initialized"]
[0.8, "o", "\u001b[32m\u001b[1m$\u001b[0m "]
[0.08, "o", "m"]
[0.06, "o", "y"]
[0.08, "o", "-"]
[0.06, "o", "t"]
[0.07, "o", "o"]
[0.06, "o", "o"]
[0.08, "o", "l"]
[0.1, "o", " "]
[0.07, "o", "r"]
[0.06, "o", "u"]
[0.08, "o", "n"]
[0.1, "o", " "]
[0.06, "o", "-"]
[0.08, "o", "-"]
[0.06, "o", "v"]
[0.07, "o", "e"]
[0.06, "o", "r"]
[0.08, "o", "b"]
[0.06, "o", "o"]
[0.07, "o", "s"]
[0.06, "o", "e"]
[0.6, "o", "\r\n"]
[0.2, "o", "\u001b[36m\u2699\ufe0f Running task: build\u001b[0m\r\n"]
[0.4, "o", " \u001b[90m[1/4]\u001b[0m Collecting sources...\r\n"]
[0.5, "o", " \u001b[90m[2/4]\u001b[0m Compiling...\r\n"]
[0.6, "o", " \u001b[90m[3/4]\u001b[0m Running tests...\r\n"]
[0.4, "o", " \u001b[90m[4/4]\u001b[0m Packaging...\r\n"]
[0.3, "o", "\r\n\u001b[32m\u2714 Build complete (1.2s)\u001b[0m\r\n"]
[1.0, "m", "Build finished"]
[0.5, "o", "\u001b[32m\u001b[1m$\u001b[0m "]getting-started.termshow.yml
source: demos/getting-started.termshow
settings:
idle_time_limit: 1.5
window_chrome: colorful
chapters:
- at: 0.0
label: "Install"
- at: 4.5
label: "Initialize"
- at: 10.0
label: "Build"
annotations:
- at: 0.5
duration: 3.0
text: "Install from PyPI with pip"
position: top-right
style: callout
- at: 5.0
duration: 3.5
text: "Creates project structure with sensible defaults"
position: bottom-right
style: subtle
- at: 11.0
duration: 3.0
text: "Verbose mode shows each build step"
position: top-right
style: calloutgreat-docs-cli.termshow
{"version": 1, "format": "termshow", "term": {"cols": 80, "rows": 24, "type": "xterm-256color"}, "title": "Great Docs CLI"}
[0.5, "o", "\u001b[32m\u001b[1m$\u001b[0m "]
[0.08, "o", "g"]
[0.06, "o", "r"]
[0.07, "o", "e"]
[0.06, "o", "a"]
[0.08, "o", "t"]
[0.06, "o", "-"]
[0.07, "o", "d"]
[0.06, "o", "o"]
[0.08, "o", "c"]
[0.06, "o", "s"]
[0.1, "o", " "]
[0.07, "o", "-"]
[0.06, "o", "-"]
[0.06, "o", "v"]
[0.07, "o", "e"]
[0.06, "o", "r"]
[0.08, "o", "s"]
[0.06, "o", "i"]
[0.07, "o", "o"]
[0.06, "o", "n"]
[0.5, "o", "\r\n"]
[0.2, "o", "great-docs, version 0.10.0\r\n"]
[1.0, "m", "version"]
[0.6, "o", "\u001b[32m\u001b[1m$\u001b[0m "]
[0.08, "o", "g"]
[0.06, "o", "r"]
[0.07, "o", "e"]
[0.06, "o", "a"]
[0.08, "o", "t"]
[0.06, "o", "-"]
[0.07, "o", "d"]
[0.06, "o", "o"]
[0.08, "o", "c"]
[0.06, "o", "s"]
[0.1, "o", " "]
[0.07, "o", "s"]
[0.06, "o", "c"]
[0.08, "o", "a"]
[0.06, "o", "n"]
[0.5, "o", "\r\n"]
[0.3, "o", "\r\n"]
[0.1, "o", "\u001b[36m\u001b[1mPackage:\u001b[0m gdtest_termshow\r\n"]
[0.1, "o", "\u001b[36m\u001b[1mVersion:\u001b[0m 1.0.0\r\n"]
[0.1, "o", "\r\n"]
[0.1, "o", "\u001b[1mDiscovered Exports (3):\u001b[0m\r\n"]
[0.05, "o", "\r\n"]
[0.05, "o", " \u001b[33mFunctions:\u001b[0m\r\n"]
[0.05, "o", " \u001b[32m\u2022\u001b[0m greet(name)\r\n"]
[0.05, "o", " \u001b[32m\u2022\u001b[0m init_project(path, *, template)\r\n"]
[0.05, "o", " \u001b[32m\u2022\u001b[0m run_task(task_name, *, verbose)\r\n"]
[0.1, "o", "\r\n"]
[0.1, "o", "\u001b[90m\u2139 All 3 exports have docstrings.\u001b[0m\r\n"]
[1.2, "m", "scan complete"]
[0.6, "o", "\u001b[32m\u001b[1m$\u001b[0m "]
[0.08, "o", "g"]
[0.06, "o", "r"]
[0.07, "o", "e"]
[0.06, "o", "a"]
[0.08, "o", "t"]
[0.06, "o", "-"]
[0.07, "o", "d"]
[0.06, "o", "o"]
[0.08, "o", "c"]
[0.06, "o", "s"]
[0.1, "o", " "]
[0.07, "o", "l"]
[0.06, "o", "i"]
[0.08, "o", "n"]
[0.06, "o", "t"]
[0.5, "o", "\r\n"]
[0.3, "o", "\r\n"]
[0.1, "o", "\u001b[36m\u001b[1mLinting:\u001b[0m gdtest_termshow\r\n"]
[0.2, "o", "\r\n"]
[0.15, "o", " \u001b[32m\u2714\u001b[0m docstrings \u001b[90m........\u001b[0m 3/3 documented\r\n"]
[0.15, "o", " \u001b[32m\u2714\u001b[0m cross-refs \u001b[90m........\u001b[0m no broken references\r\n"]
[0.15, "o", " \u001b[32m\u2714\u001b[0m style \u001b[90m.............\u001b[0m consistent (numpy)\r\n"]
[0.15, "o", " \u001b[32m\u2714\u001b[0m directives \u001b[90m........\u001b[0m all valid\r\n"]
[0.15, "o", " \u001b[32m\u2714\u001b[0m stale-versions \u001b[90m....\u001b[0m none found\r\n"]
[0.2, "o", "\r\n"]
[0.1, "o", "\u001b[32m\u001b[1m\u2728 All checks passed!\u001b[0m No issues found.\r\n"]
[1.2, "m", "lint complete"]
[0.6, "o", "\u001b[32m\u001b[1m$\u001b[0m "]
[0.08, "o", "g"]
[0.06, "o", "r"]
[0.07, "o", "e"]
[0.06, "o", "a"]
[0.08, "o", "t"]
[0.06, "o", "-"]
[0.07, "o", "d"]
[0.06, "o", "o"]
[0.08, "o", "c"]
[0.06, "o", "s"]
[0.1, "o", " "]
[0.07, "o", "t"]
[0.06, "o", "e"]
[0.08, "o", "r"]
[0.06, "o", "m"]
[0.1, "o", " "]
[0.07, "o", "r"]
[0.06, "o", "e"]
[0.08, "o", "n"]
[0.06, "o", "d"]
[0.07, "o", "e"]
[0.06, "o", "r"]
[0.1, "o", " "]
[0.06, "o", "d"]
[0.07, "o", "e"]
[0.06, "o", "m"]
[0.08, "o", "o"]
[0.06, "o", "s"]
[0.07, "o", "/"]
[0.06, "o", "g"]
[0.07, "o", "e"]
[0.06, "o", "t"]
[0.08, "o", "t"]
[0.06, "o", "i"]
[0.07, "o", "n"]
[0.06, "o", "g"]
[0.08, "o", "-"]
[0.06, "o", "s"]
[0.07, "o", "t"]
[0.06, "o", "a"]
[0.07, "o", "r"]
[0.06, "o", "t"]
[0.08, "o", "e"]
[0.06, "o", "d"]
[0.6, "o", "\r\n"]
[0.3, "o", "\r\n"]
[0.1, "o", "\u001b[36m\u001b[1mRendering:\u001b[0m demos/getting-started.termshow\r\n"]
[0.2, "o", " \u001b[90mScript:\u001b[0m demos/getting-started.termshow.yml\r\n"]
[0.1, "o", " \u001b[90mChrome:\u001b[0m colorful\r\n"]
[0.1, "o", " \u001b[90mSize:\u001b[0m 80\u00d720\r\n"]
[0.2, "o", "\r\n"]
[0.4, "o", " \u001b[33m\u25cf\u001b[0m Parsing recording (24 events)...\r\n"]
[0.3, "o", " \u001b[33m\u25cf\u001b[0m Applying idle_time_limit: 1.5s\r\n"]
[0.5, "o", " \u001b[33m\u25cf\u001b[0m Rendering keyframes...\r\n"]
[0.2, "o", " \u001b[90mframe-000.svg\u001b[0m (0.00s)\r\n"]
[0.15, "o", " \u001b[90mframe-001.svg\u001b[0m (0.50s)\r\n"]
[0.15, "o", " \u001b[90mframe-002.svg\u001b[0m (2.08s)\r\n"]
[0.15, "o", " \u001b[90mframe-003.svg\u001b[0m (3.28s)\r\n"]
[0.15, "o", " \u001b[90mframe-004.svg\u001b[0m (4.50s)\r\n"]
[0.15, "o", " \u001b[90mframe-005.svg\u001b[0m (5.10s)\r\n"]
[0.15, "o", " \u001b[90mframe-006.svg\u001b[0m (7.60s)\r\n"]
[0.15, "o", " \u001b[90mframe-007.svg\u001b[0m (10.00s)\r\n"]
[0.15, "o", " \u001b[90mframe-008.svg\u001b[0m (10.60s)\r\n"]
[0.15, "o", " \u001b[90mframe-009.svg\u001b[0m (14.20s)\r\n"]
[0.2, "o", " \u001b[33m\u25cf\u001b[0m Writing manifest.json\r\n"]
[0.1, "o", "\r\n"]
[0.1, "o", "\u001b[32m\u001b[1m\u2714 Done!\u001b[0m 10 frames, 3 chapters, 16.6s duration\r\n"]
[0.1, "o", " \u001b[90mOutput: termshow/getting-started/\u001b[0m\r\n"]
[1.0, "m", "render complete"]
[0.5, "o", "\u001b[32m\u001b[1m$\u001b[0m "]great-docs-cli.termshow.yml
source: demos/great-docs-cli.termshow
settings:
idle_time_limit: 1.5
window_chrome: colorful
chapters:
- at: 0.0
label: "Version"
- at: 3.5
label: "Scan Exports"
- at: 9.0
label: "Lint Docs"
- at: 14.5
label: "Render Recording"
annotations:
- at: 0.5
duration: 2.5
text: "Check your installed version"
position: top-right
style: subtle
- at: 4.0
duration: 4.0
text: "Discovers all public exports with docstring coverage"
position: top-right
style: callout
- at: 9.5
duration: 4.0
text: "Checks docs quality: docstrings, cross-refs, style, and more"
position: top-right
style: callout
- at: 15.5
duration: 4.0
text: "Renders .termshow recordings into SVG keyframes for embedding"
position: top-right
style: highlighttui-demo.termshow
{"version": 1, "format": "termshow", "term": {"cols": 60, "rows": 18, "type": "xterm-256color"}, "title": "TUI Interface"}
[0.3, "o", "\u001b[2J\u001b[H"]
[0.2, "o", "\u001b[34m\u001b[1m\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[36m\u001b[1m\u2728 my-tool v1.0\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[33m\u276f\u001b[0m \u001b[1mNew Project\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m Open Existing \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m Recent Files \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m Settings \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[90mQuit\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[90m\u2191/\u2193 navigate \u23ce enter q quit\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m\r\n"]
[0.02, "o", "\u001b[34m\u001b[1m\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u001b[0m\r\n"]
[2.0, "m", "Main menu"]
[0.8, "o", "\u001b[9;1H"]
[0.05, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m New Project \u001b[34m\u001b[1m\u2502\u001b[0m"]
[0.05, "o", "\u001b[10;1H"]
[0.05, "o", "\u001b[34m\u001b[1m\u2502\u001b[0m \u001b[33m\u276f\u001b[0m \u001b[1mOpen Existing\u001b[0m \u001b[34m\u001b[1m\u2502\u001b[0m"]
[1.5, "m", "Navigate to Open"]
[0.5, "o", "\u001b[2J\u001b[H"]
[0.2, "o", "\u001b[36m\u001b[1m\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u2594\u001b[0m\r\n"]
[0.05, "o", " \u001b[1mOpen Project\u001b[0m\r\n"]
[0.05, "o", "\u001b[36m\u001b[1m\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u2581\u001b[0m\r\n"]
[0.1, "o", "\r\n"]
[0.1, "o", " \u001b[90mPath:\u001b[0m ~/projects/\u001b[4mmy-app\u001b[0m\r\n"]
[0.3, "o", "\r\n"]
[0.2, "o", " \u001b[32m\u2714\u001b[0m Loaded \u001b[1m3 files\u001b[0m, \u001b[1m2 configs\u001b[0m\r\n"]
[0.5, "o", " \u001b[32m\u2714\u001b[0m Project ready\r\n"]
[1.5, "m", "Project loaded"]tui-demo.termshow.yml
source: demos/tui-demo.termshow
settings:
idle_time_limit: 2.0
window_chrome: colorful
chapters:
- at: 0.0
label: "Main Menu"
- at: 3.0
label: "Navigation"
- at: 5.5
label: "Open Project"
annotations:
- at: 0.5
duration: 2.5
text: "Full-screen TUI with keyboard navigation"
position: top-right
style: callout
- at: 3.2
duration: 2.0
text: "Arrow keys move the selection cursor"
position: bottom-right
style: subtle
- at: 6.0
duration: 2.5
text: "Enter confirms and opens the sub-view"
position: top-left
style: calloutgdtest_termshow/
__init__.py
"""A sample CLI/TUI tool for demonstrating termshow recordings."""
__version__ = "1.0.0"
__all__ = ["greet", "init_project", "run_task"]
def greet(name: str) -> str:
"""Greet a user by name.
Parameters
----------
name
The name to greet.
Returns
-------
str
A greeting string.
"""
return f"Hello, {name}!"
def init_project(path: str, *, template: str = 'default') -> dict:
"""Initialize a new project at the given path.
Parameters
----------
path
Directory to create the project in.
template
Project template to use.
Returns
-------
dict
Project metadata.
"""
return {'path': path, 'template': template}
def run_task(task_name: str, *, verbose: bool = False) -> int:
"""Run a named task.
Parameters
----------
task_name
Name of the task to execute.
verbose
Enable verbose output.
Returns
-------
int
Exit code (0 for success).
"""
return 0user_guide/
01-quick-start.qmd
---
title: Quick Start
---
## Installation & First Run
Watch this quick demo to see `my-tool` in action — from installation
through your first build:
{{< termshow file="demos/getting-started" pause_on_chapters="true" >}}
### What just happened?
The recording above shows three steps:
1. **Install** — `pip install my-tool` fetches the package from PyPI
2. **Initialize** — `my-tool init` scaffolds a new project
3. **Build** — `my-tool run --verbose` executes the build pipeline
You can click any chapter marker in the timeline to jump directly
to that step, or use keyboard shortcuts:
| Key | Action |
|-----|--------|
| Space | Play/Pause |
| ← / → | Seek 5 seconds |
| . | Next chapter |
| , | Previous chapter |
## Next Steps
Now that you have `my-tool` installed, check out the
[TUI Interface](02-tui-interface.qmd) guide for the interactive mode.02-tui-interface.qmd
---
title: TUI Interface
---
## Interactive Mode
`my-tool` includes a full-screen terminal interface for visual
project management. Launch it with:
```bash
my-tool --interactive
```
Here's how it looks:
{{< termshow file="demos/tui-demo" pause_on_chapters="true" >}}
### Navigation
The TUI uses standard terminal navigation:
- **↑/↓** arrows to move between items
- **Enter** to select/confirm
- **q** to quit
- **Esc** to go back one level
### Features
The interactive mode provides:
- Project creation wizard
- File browser with preview
- Live build output
- Configuration editor03-recording-tips.qmd
---
title: Recording Tips
---
## Creating Your Own Recordings
Great Docs makes it easy to record, edit, and embed terminal
sessions in your documentation.
### Recording
```bash
# Start recording
great-docs termshow record demos/my-demo.termshow
# Perform your CLI actions...
# Press Ctrl+D or type 'exit' to stop
```
### Editing with Scripts
Create a `.termshow.yml` file alongside your recording to add
chapters, annotations, and timing adjustments:
```yaml
source: demos/my-demo.termshow
settings:
idle_time_limit: 2.0
window_chrome: colorful
chapters:
- at: 0.0
label: Introduction
- at: 10.0
label: Main Feature
annotations:
- at: 2.0
duration: 3.0
text: This step installs dependencies
position: top-right
style: callout
cuts:
- from: 5.0
to: 8.0
type: ellipsis
```
### Rendering
```bash
# Render SVG frames
great-docs termshow render demos/my-demo.termshow
```
### Embedding
Use the `termshow` shortcode in your `.qmd` files:
```markdown
{{< termshow file="demos/my-demo" pause_on_chapters="true" >}}
```
### Importing Existing Recordings
Already have recordings from asciinema or VHS?
```bash
# Import from asciinema
great-docs termshow import-cast recording.cast demos/my-demo
# Import from VHS tape
great-docs termshow import-tape demo.tape demos/my-demo
```04-termshow-guide.qmd
---
title: Termshow Guide
---
## Overview
The **termshow** is Great Docs' built-in terminal recording player.
It renders pre-recorded terminal sessions as interactive, frame-accurate
SVG animations directly in your documentation pages — no JavaScript
framework dependencies, no external services.
Key capabilities:
- Frame-accurate SVG rendering of terminal output
- Chapter-based navigation with labeled markers
- Contextual annotations that appear at specific timestamps
- Keyboard shortcuts for power users
- Adjustable playback speed (0.5× to 3×)
- Works offline and with `file://` protocol (all data embedded inline)
- Responsive layout that scales to any viewport width
- Light/dark theme support (follows the site theme)
### Live Demo
Here's a recording of real Great Docs CLI commands — `scan`, `lint`,
and `term render` — running against this very package:
{{< termshow file="demos/great-docs-cli" pause_on_chapters="true" >}}
## The Recording Format
Termshow uses a two-file system for each recording:
### The `.termshow` File
This is the raw terminal recording in NDJSON format. Each line is
a JSON array with `[delay, event_type, data]`:
```json
{"version": 1, "format": "termshow", "term": {"cols": 80, "rows": 20}}
[0.5, "o", "$ "]
[0.1, "o", "echo hello"]
[0.6, "o", "\r\nhello\r\n"]
[1.0, "m", "Command executed"]
```
Event types:
| Type | Meaning |
|------|---------|
| `"o"` | Output — terminal data written to stdout |
| `"i"` | Input — user keystrokes (for display purposes) |
| `"m"` | Marker — internal marker used for chapter sync |
The header line sets terminal dimensions and metadata.
### The `.termshow.yml` Script File
This companion file defines chapters, annotations, timing adjustments,
and visual settings:
```yaml
source: demos/my-recording.termshow
settings:
idle_time_limit: 2.0 # Cap any idle gap to 2 seconds
window_chrome: colorful # Window decoration style
theme: monokai # Terminal color scheme
font_size: 14 # Font size in pixels
chapters:
- at: 0.0
label: Introduction
- at: 5.0
label: Configuration
- at: 12.0
label: Running Tests
annotations:
- at: 1.0
duration: 3.0
text: This installs all required dependencies
position: top-right
style: callout
- at: 6.0
duration: 2.5
text: Configuration is auto-detected
position: bottom-right
style: subtle
cuts:
- from: 8.0
to: 11.0
type: ellipsis # Shows '…' for the cut section
```
## Settings Reference
| Setting | Default | Description |
|---------|---------|-------------|
| `idle_time_limit` | `3.0` | Maximum seconds for any idle gap |
| `window_chrome` | `colorful` | Window decoration: `colorful`, `plain`, `none` |
| `theme` | (auto) | Terminal color scheme |
| `font_size` | `14` | Font size in rendered SVG (px) |
| `line_height` | `1.2` | Line height multiplier |
| `padding` | `12` | Inner padding of the terminal area (px) |
## Annotation Styles
Annotations appear as overlays on the terminal at specified times.
Three styles are available:
| Style | Appearance |
|-------|------------|
| `callout` | Semi-opaque dark card with accent border |
| `subtle` | Lighter, smaller text — less intrusive |
| `highlight` | Amber-tinted with warm border — draws attention |
Positions: `top-left`, `top-right`, `bottom-left`, `bottom-right`.
## Embedding in Pages
Use the `termshow` Quarto shortcode in any `.qmd` file:
````markdown
## Basic usage
{{< termshow file="demos/getting-started" >}}
## With chapter pausing
{{< termshow file="demos/workflow" pause_on_chapters="true" >}}
## Autoplay with custom speed
{{< termshow file="demos/quick" autoplay="true" speed="1.5" >}}
````
### Shortcode Options
| Option | Default | Description |
|--------|---------|-------------|
| `file` | (required) | Path to `.termshow` file (without extension) |
| `autoplay` | `false` | Start playing automatically on page load |
| `loop` | `false` | Loop playback when reaching the end |
| `speed` | `1` | Initial playback speed multiplier |
| `pause_on_chapters` | `false` | Auto-pause at each chapter boundary |
| `controls` | `true` | Show the control bar |
| `theme` | `auto` | Player theme: `auto`, `dark`, or `light` |
## Player Controls
The player provides a full set of interactive controls:
### Control Bar
From left to right:
1. **Play/Pause button** — Toggles playback. Shows ↺ (replay) at the end.
2. **Current time** — Elapsed time counter.
3. **Timeline scrub bar** — Click anywhere to seek. Chapter markers
appear as gold ticks with wider hit targets for easy clicking.
4. **Remaining time** — Counts down to zero during playback.
5. **Speed button** — Cycles through 0.5×, 1×, 1.5×, 2×, 3×.
### Chapter Bar
A thin overlay at the top of the player shows the name of the
current chapter, updating as playback progresses.
### Center Overlay
A semi-transparent button in the center of the viewport:
- **Before playback** — Shows ▶ as a call-to-action.
- **After playback ends** — Shows ↺ to indicate replay. Clicking
returns the player to its initial state (frame 0, ready to play).
- **During chapter pauses** — Hidden, so the terminal content
remains fully visible.
### Keyboard Shortcuts
Click the player viewport first to give it focus, then use:
| Key | Action |
|-----|--------|
| `Space` | Play / Pause (or reset from ended state) |
| `→` | Seek forward 5 seconds |
| `←` | Seek backward 5 seconds |
| `.` | Jump to next chapter |
| `,` | Jump to previous chapter |
## Workflow
The full termshow workflow from recording to rendered page:
```text
1. Record great-docs termshow record demos/my-demo.termshow
2. Edit script Create/edit demos/my-demo.termshow.yml
3. Preview great-docs termshow play demos/my-demo.termshow
4. Embed Add {{< termshow ... >}} to your .qmd
5. Build great-docs build (renders SVG frames automatically)
```
### Step 1: Record
```bash
great-docs termshow record demos/install-guide.termshow
```
This launches a recording session. Everything you type and see in
the terminal is captured with precise timing. Press `Ctrl+D` or
type `exit` to end the recording.
### Step 2: Create the Script
Create `demos/install-guide.termshow.yml` alongside the recording.
Define chapters at logical breakpoints in your workflow, and add
annotations to explain what's happening:
```yaml
source: demos/install-guide.termshow
settings:
idle_time_limit: 1.5
window_chrome: colorful
chapters:
- at: 0.0
label: Setup
- at: 8.0
label: Install
- at: 15.0
label: Verify
annotations:
- at: 1.0
duration: 3.0
text: Start by activating the virtual environment
position: top-right
style: callout
```
### Step 3: Preview
```bash
great-docs termshow play demos/install-guide.termshow
```
This plays the recording in your terminal so you can verify
timing and check that chapter boundaries feel natural.
### Step 4: Embed
Add the shortcode to any user guide or documentation page:
```markdown
{{< termshow file="demos/install-guide" pause_on_chapters="true" >}}
```
### Step 5: Build
```bash
great-docs build
```
During the build, Great Docs:
1. Finds all `.termshow` files in your project
2. Renders each recording into a series of SVG keyframes
3. Generates a `manifest.json` with timing, chapters, and annotations
4. The Lua shortcode filter embeds the manifest and all SVG frames
inline in the HTML — no runtime fetches needed
## Importing Existing Recordings
Already have terminal recordings from other tools? Import them:
```bash
# From asciinema (.cast files)
great-docs termshow import-cast recording.cast demos/my-demo
# From VHS (.tape files)
great-docs termshow import-tape demo.tape demos/my-demo
```
The import preserves timing and terminal dimensions. You'll still
want to create a `.termshow.yml` script to add chapters and
annotations.
## Tips & Best Practices
- **Keep recordings short** — 15–30 seconds is ideal. Split longer
workflows into multiple recordings.
- **Use `idle_time_limit`** — Caps long pauses so viewers aren't
waiting through your thinking time.
- **Place chapters at logical transitions** — Each chapter should
represent one distinct step in the workflow.
- **Use `pause_on_chapters`** for tutorials — Gives readers time
to absorb each step before the next one plays.
- **Annotations are brief** — One sentence max. They complement
the terminal output, not replace it.
- **Test at different speeds** — Make sure annotations are still
readable at 1.5× and 2× speed.
- **80 columns, 20 rows** works well for most CLI recordings.
Use 60 columns for narrower TUI demos.
## Architecture
Under the hood, termshow works in two phases:
**Build time** (Python + Lua):
1. `core.py` discovers `.termshow` files and calls the renderer
2. The renderer parses the NDJSON recording + YAML script
3. It produces SVG keyframes at each visual change point
4. A `manifest.json` captures timing, chapters, and annotation data
5. The Lua shortcode embeds everything inline as `<script>` JSON blocks
**Page load** (JavaScript):
1. `termshow.js` finds `.gd-termshow` containers
2. Reads inline manifest and SVG frame data from `<script>` elements
3. Builds the player UI (viewport, controls, chapter bar, overlays)
4. On play: advances time via `requestAnimationFrame`, swaps SVG
frames at the correct timestamps
This architecture means:
- Zero network requests at runtime
- Works with `file://` protocol (offline docs)
- No CORS or fetch issues
- SVGs scale perfectly at any zoom levelgreat-docs.yml
package_name: gdtest_termshow display_name: My Tool description: A demo showing terminal recordings in documentation user_guide: true