$npx -y skills add calesthio/OpenMontage --skill synthetic-screen-recordingSynthetic terminal-style screen recording guidance for Remotion TerminalScene.
| 1 | # Synthetic Screen Recording (Remotion TerminalScene) |
| 2 | |
| 3 | **Decision this skill answers:** When the user wants a screen-recording-looking demo of a terminal, CLI tool, or coding workflow — do I **capture the real desktop** (OS screen recording via `screen_recorder`, Windows-MCP, Cap, or Playwright), or do I **synthesize it in Remotion** with the `TerminalScene` component? |
| 4 | |
| 5 | > **Heuristic:** If the agent can author the exact command/output sequence in advance, synthesize. Only capture live when the real behavior is unpredictable, needs a real app UI, or the user explicitly asked for a real recording. |
| 6 | |
| 7 | ## Why this exists |
| 8 | |
| 9 | v3 of the OpenMontage showcase tried to use Windows-MCP + `screen_recorder` to drive a Git-Bash window for the install walkthrough. It stalled on window positioning, focus races, and taskbar privacy concerns. We pivoted to **pure Remotion rendering** — a React component named `TerminalScene` that draws a fake terminal and types commands character-by-character. The output is visually indistinguishable from a real screen recording (same traffic-light window chrome, blinking cursor, scrolling output) but deterministic, privacy-safe, pixel-perfect at 1080p, and pace-controllable to the frame. |
| 10 | |
| 11 | That component + pattern is the capability this skill makes discoverable. |
| 12 | |
| 13 | ## When to use synthetic (TerminalScene) |
| 14 | |
| 15 | **YES, synthesize when:** |
| 16 | - The demo is a **terminal / CLI / coding session** where commands and outputs are predictable |
| 17 | - The user wants a polished tutorial feel (clean typography, floating pills, cursor blink) |
| 18 | - Install walkthroughs, setup demos, API key config, `make` targets, `git clone` flows |
| 19 | - You need tight sync with narration — every command must land on a specific beat |
| 20 | - You want the result reproducible (re-render gets identical pixels) |
| 21 | - The user's actual desktop has private apps/windows visible you'd otherwise have to crop |
| 22 | |
| 23 | **NO, capture a real screen when:** |
| 24 | - The demo is **a real app UI** that can't be faked (Figma, Photoshop, a web app with live state, a browser flow) |
| 25 | - The user explicitly asked for a recording of *their* actual screen |
| 26 | - The behavior depends on timing you can't script (streaming LLM output, real network latency) |
| 27 | - There's a visual quirk (a cursor effect, a plugin pop-up) that only appears in the live environment |
| 28 | |
| 29 | **For a browser demo** → `playwright-recording` skill, not this one. |
| 30 | **For a real desktop** → `screen_recorder` tool or Cap via `cap_recorder`. |
| 31 | |
| 32 | ## The component — `TerminalScene` |
| 33 | |
| 34 | Located at: `remotion-composer/src/components/TerminalScene.tsx` |
| 35 | Exported from: `remotion-composer/src/components/index.ts` |
| 36 | Wired in dispatch: `remotion-composer/src/Explainer.tsx` (`if (cut.type === "terminal_scene")`) |
| 37 | |
| 38 | **Props:** |
| 39 | ```ts |
| 40 | interface TerminalSceneProps { |
| 41 | title?: string; // shown in the window title bar |
| 42 | steps: TerminalStep[]; // the timeline |
| 43 | prompt?: string; // "$", ">", etc. |
| 44 | accentColor?: string; // pill + prompt glow |
| 45 | backgroundColor?: string; |
| 46 | } |
| 47 | ``` |
| 48 | |
| 49 | **Step kinds:** |
| 50 | ```ts |
| 51 | { kind: "cmd", text: string, typeSpeed?: number, holdSeconds?: number } |
| 52 | { kind: "out", text: string, holdSeconds?: number } |
| 53 | { kind: "pause", seconds: number } |
| 54 | { kind: "pill", text: string, color?: string, durationSeconds?: number } |
| 55 | ``` |
| 56 | |
| 57 | - `cmd` — prints the prompt, types the text character-by-character (`typeSpeed` is seconds per character, default 0.035), then holds for `holdSeconds` (default 0.3) |
| 58 | - `out` — a line of program output, reveals instantly with a short fade-in |
| 59 | - `pause` — dead time. Terminal holds on last visible state. USE THIS TO SYNC WITH NARRATION. |
| 60 | - `pill` — non-blocking floating badge (top-right). Spring-in, hold, spring-out. Does NOT advance the cursor — the next step runs in parallel. |
| 61 | |
| 62 | ## Authoring pattern |
| 63 | |
| 64 | Author a new scene by adding a cut to `build_composition.py` (or your equivalent props builder): |
| 65 | |
| 66 | ```python |
| 67 | install_steps = [ |
| 68 | {"kind": "pause", "seconds": 7.0}, # wait for intro narration |
| 69 | {"kind": "cmd", "text": "git clone https://github.com/calesthio/OpenMontage.git", |
| 70 | "typeSpeed": 0.045, "holdSeconds": 0.3}, |
| 71 | {"kind": "out", "text": "Cloning into 'OpenMontage'..."}, |
| 72 | {"kind": "out", "text": "remote: Enumerating objects: 2847, done."}, |
| 73 | {"kind": "pill", "text": "repo cloned", "color": "#34D399", "durationSeconds": 2.6}, |
| 74 | {"kind": "pause", "seconds": 3.8}, # bridge to next narration cue |
| 75 | # ... |
| 76 | ] |
| 77 | |
| 78 | cuts.append({ |
| 79 | "id": "install-terminal", |
| 80 | "type": "terminal_scene", |
| 81 | "terminalTitle": "bash — OpenMontage setup", |
| 82 | "prompt": "$", |
| 83 | "accentColor": "#22D3EE", |
| 84 | "steps": install_steps, |
| 85 | "in_seconds": 50.0, |
| 86 | "out_seconds": 110.0, |
| 87 | }) |
| 88 | ``` |
| 89 | |
| 90 | ## THE RULE: pace with narration, never ahead |
| 91 | |
| 92 | **The #1 failure mode:** steps run continuously and burn through all content in the first 40% of the scene, leaving the terminal frozen f |