Assemble a ChatGPT chat-reveal video ad from a thread + timeline JSON — one continuous Playwright recording of a ChatGPT mobile chat (user types with the iOS keyboard up → taps send → keyboard slides down + header cluster swaps in one beat → one gray loading dot → the assistant answer streams in word-by-word) crossfaded into a designed end card, with subliminal ChatGPT SFX and an optional ducked music bed. FREE assembly (Playwright + ffmpeg); the recipe supplies the per-brand thread + timeline + end-card config and gates the paid music call to its own capability. The ChatGPT sibling of render-imessage-chat. Use for the chatgpt-chat format.
69
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
The free renderer for the chatgpt-chat video ad format — the "I just asked ChatGPT…" creative, where someone asks ChatGPT a question and the streamed assistant answer is the punchline (the brand surfacing as the natural response). Deterministic Playwright + ffmpeg assembly; no generative video of the UI, so the bubble text and streamed answer stay pixel-crisp.
This is the ChatGPT sibling of render-imessage-chat. Reach for this one when
ChatGPT is the more credible host for the answer; reach for iMessage when the
punchline is a peer's reaction in a DM. The template recipe (DB) supplies the
per-brand thread + timeline + end_card config and gates the paid music call
(music bed → create-music-elevenlabs) to its own capability.
One continuous take — never scene-by-scene (every reload flickers):
composer-type).personPlus/dottedCircle → edit/more) all on
the same t. Never sequence them across frames.stream-words, ~7 wps) with a
soft opacity ramp; the conversation auto-scrolls to keep it in view.The chat records at the ChatGPT-native ~9:19.5 (default 750×1624) to match a real iPhone screen recording. Never stretch the chat to a different aspect ratio — the end card is scaled-to-fit + padded to the chat's dimensions in stitch, so the chat is never touched.
cd scripts && npm install # once — installs Playwright
npx playwright install chromium # once
node record-chat.js --config config.json --out-dir <work> # → master-chat.mp4 + .sfx.json
node render-end-card.js --config config.json --out-dir <work> # → scene-end-endcard.mp4
bash stitch.sh --chat <work>/master-chat.mp4 --end <work>/scene-end-endcard.mp4 \
--sfx <work>/master-chat.sfx.json --out <work>/master-final.mp4 \
--pad-color "#ffffff" [--music <work>/music-bed.mp3] [--also-1x1]record-chat.js — reads config.json (thread + timeline + geometry),
renders the bundled create-chatgpt-mockup HTML once with every message
pending, walks the timeline on requestAnimationFrame inside the page, records
it as one continuous MP4, and emits the deterministic SFX cue list.render-end-card.js — fills end-card.template.html from config.end_card
(wordmark/logo_svg, stars, proof, trust trio, CTA, colors) → still MP4. This is
the SAME generic end card as render-imessage-chat (copied verbatim).stitch.sh — normalizes the end card to the chat's dimensions, crossfades
chat → end card, layers the subliminal ChatGPT SFX, optionally ducks a music bed
under it, and optionally derives a 1:1 crop. All FREE ffmpeg. Pass
--pad-color = end_card.bg (default #ffffff, ChatGPT light mode) so the pad
under the end card is seamless.The ChatGPT chat HTML comes from create-chatgpt-mockup (its generate.js +
templates/ produce the light-mode ChatGPT iOS HTML — status bar, header, message
rows, streaming word-spans, composer, and the inline iOS keyboard). Those files are
bundled into scripts/mockup/ so this capability renders the chat body
standalone — no sibling fetch of create-chatgpt-mockup is required. record-chat.js
does require('./mockup/generate.js').
The keyboard is inlined by the mockup (renderKeyboard) — no separate keyboard atom.
| Kind | Meaning |
|---|---|
composer-type | { text, dur_sec } — type into the composer. SFX = one key-tap per word. |
composer-clear | Wipe the composer instantly (fire at send-tap). |
keyboard-show / keyboard-hide | Slide the iOS keyboard up / down. |
send-tap | Pulse the send button. SFX = send-tap. |
pop | { target: <msg-id> } — reveal a message row. |
header-swap | { value: "alt" } — swap the header right-cluster. |
loading-dot-show / loading-dot-hide | { target: <dot-id> } — the single gray dot. |
send-state | { value: "streaming"|"active" } — composer send-button state. |
stream-words | { target, dur_sec, wps } — reveal the assistant answer word-by-word. SFX = stream-tick every 12 words + response-done at the end. |
scroll-to | { target, dur_ms } — smooth-scroll a row into view. |
See scripts/config.example.json for the canonical thread + timeline (the "one
beat" send-tap and the streamed list answer are both wired there).
thread (light-mode ChatGPT,
assistant message set stream: true), the timeline, the end_card (prefer a
real logo_svg wordmark), and an optional music bed."sfx": false in the config to ship the chat silent.create-music-elevenlabs (paid, proxy-routed, billed to the Ads agent) and passes
the file into stitch.sh --music.key-tap/send-tap/stream-tick/response-done) were lost from Git LFS (the
objects 404 on the server), so assets/sfx/*.wav are freshly synthesized
subliminal clicks/ticks. They work as-is; swap in real wavs (same filenames) for
tuned SFX./tmp/gooseworks-scripts/render-chatgpt-chat/scripts/… — the chatgpt-mockup
generator + templates are bundled under scripts/mockup/, and the generic end
card is bundled under scripts/. No /Users/… or repo-relative paths, and no
required sibling fetch.npx playwright install chromium).end_card.bg.8866b2a
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.