Recreate OpenCode coding sessions as animated HTML replays. Perfect for:
- Workshop recordings
- Tutorial demonstrations
- Documentation
- Social media content
# Install dependencies
npm install
# Generate a sample replay
npm run demo
# Open in browser
open output/demo.htmlThe easiest way to get real session data:
# Export all three workshop sessions from local OpenCode
npm run export:all
# Convert to replay format
npm run convert:all
# Generate HTML replays
npm run generate:all
# Open in browser
open output/session-1-real.htmlOr run the entire workflow at once:
npm run workflow# List available sessions
~/.opencode/bin/opencode session list
# Export a specific session
~/.opencode/bin/opencode export <session-id> > sessions/my-session-export.json
# Clean the export (remove header line)
tail -n +2 sessions/my-session-export.json > sessions/my-session-clean.json# Convert export to replay format
npx ts-node src/convert-export.ts sessions/my-session-clean.json sessions/my-session.json# Generate replay
npx ts-node src/index.ts sessions/my-session.json output/my-session.html
# Generate with thinking stream
npx ts-node src/index.ts sessions/my-session.json output/my-session-thinking.html --thinking
# Open in browser
open output/my-session.htmlnpm run demoThe three workshop sessions from June 11, 2026:
| Session | Title | Messages |
|---|---|---|
| 1 | 22 tasks in HU | 25 |
| 2 | Revising noncoding_by_country.do | 15 |
| 3 | Creating README from template | 5 |
Generate all three:
npm run workflowThe converter produces JSON in this format:
{
"id": "ses_149804f85ffeQE2csQtVj67ILo",
"title": "22 tasks in HU",
"model": "mimo-v2.5-free",
"provider": "opencode·mimo-v2.5-free",
"started_at": "2026-06-11T11:44:42.107Z",
"duration_ms": 102254804,
"task_count": 0,
"messages": [
{
"id": "msg-0",
"role": "user",
"content": "what 22 tasks are requested in HU?",
"timestamp_ms": 80
},
{
"id": "msg-6",
"role": "assistant",
"content": "Let me look at the data documentation...",
"thinking": "The user is asking about 22 tasks...",
"timestamp_ms": 22121
}
]
}Edit src/types.ts to customize:
export const DEFAULT_CONFIG: AnimationConfig = {
user_typing_speed: 35, // chars per second (realistic human)
assistant_typing_speed: 120, // chars per second (fast machine)
thinking_typing_speed: 200, // chars per second (fastest, for thinking)
message_pause: 500, // ms between messages
tool_call_pause: 300, // ms before tool expansion
tool_speed: 2, // speed multiplier for tools
show_thinking: false, // show chain-of-thought
width: 1280, // output width
height: 720, // output height
css_overrides: '', // custom CSS (optional)
};Pass custom CSS to override the default theme:
renderSession(session, outputPath, {
css_overrides: `
:root {
--bg-primary: #1a1a2e;
--accent-blue: #00d4ff;
}
`
});| Key | Action |
|---|---|
| Space | Play/Pause |
| Escape | Stop |
src/
├── types.ts # TypeScript type definitions
├── animation.ts # Animation engine (typing, tool calls)
├── extractor.ts # Session data parser
├── renderer.ts # HTML generator
├── index.ts # CLI entry point
├── convert-export.ts # OpenCode export converter
└── extract-share.ts # Share URL extractor (manual)
templates/
└── opencode.html # UI template
sessions/
├── *-export.json # Raw OpenCode exports
├── *-clean.json # Cleaned exports (no header)
├── *-real.json # Converted replay format
└── *.json # Manual extractions
output/
└── *.html # Generated replays
Make sure OpenCode is installed and you have sessions:
~/.opencode/bin/opencode session listThe export file must be valid JSON. Clean it first:
tail -n +2 sessions/my-session-export.json > sessions/my-session-clean.jsonCheck the browser console for errors. The session JSON must have:
messagesarray withrole,content, andtimestamp_ms- At least one message
MIT