Install in seconds
Install this skill
Copy the command and run it in your terminal. You can review the source before installing.
terminal
git clone https://github.com/gooseworks-ai/goose-skills

Works with Git. The repository opens in your current directory.

πŸ“±
AutomationPython

Render ChatGPT Chat

by gooseworks-ai

Assemble a ChatGPT-style video ad from a thread and timeline JSON by recording a simulated mobile chat with Playwright and compositing with ffmpeg. Use when creating a ChatGPT chat-reveal ad where the assistant's answer is the punchline.

1.1K stars194 forksAdded 2026/07/20
claudeclaude-skillsclaudecodeclaudecode-skillscodexcursorgtmskills

Documentation

README

render-chatgpt-chat

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.

What it renders

One continuous take β€” never scene-by-scene (every reload flickers):

  1. User types in the composer with the iOS keyboard up (composer-type).
  2. Send-tap is ONE beat β€” the user bubble pops, the keyboard slides down, and the header right-cluster swaps (personPlus/dottedCircle β†’ edit/more) all on the same t. Never sequence them across frames.
  3. One gray loading dot holds ~500ms (never three β€” three reads as iMessage typing, wrong app), silently (no SFX on the dot).
  4. The assistant answer streams in word-by-word (stream-words, ~7 wps) with a soft opacity ramp; the conversation auto-scrolls to keep it in view.
  5. Crossfade to a designed end card (wordmark + ⭐ proof row + trust trio + CTA pill) and mux a ducked music bed β†’ master MP4.

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.

Run

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]
  1. 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.
  2. 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).
  3. 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 chat body: bundled create-chatgpt-mockup

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.

Timeline events (consumed by record-chat.js)

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).

Contract

  • FREE assembly: Playwright record + ffmpeg composite/mux + the bundled SFX. No AI-rendered text β€” the bubbles, the streamed answer, and the end-card copy are all real HTML/PIL, never invented by a model.
  • The recipe (DB) supplies the per-brand config: the 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 are subliminal by design (ChatGPT has no native chime): key-tap -28dB, send-tap -20dB, stream-tick -32dB, response-done -22dB, and never a cue on the loading dot. Set "sfx": false in the config to ship the chat silent.

Gaps / routing notes

  • Music bed is an input, not generated here β€” the recipe gates it to create-music-elevenlabs (paid, proxy-routed, billed to the Ads agent) and passes the file into stitch.sh --music.
  • Bundled SFX are synthesized stand-ins. The original four wavs (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.
  • Portability: everything runs from the fetched /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.
  • Requires ffmpeg/ffprobe on PATH and Playwright Chromium (npx playwright install chromium).

Self-QC (per project rule β€” always /watch the master)

  • Keyboard is up the whole time the user types, and slides down only on the send-tap beat (never visible while the answer streams).
  • Send-tap is one beat: user bubble + keyboard-down + header-swap on the same frame.
  • Exactly one gray loading dot for ~500ms (not three), and no SFX on the dot.
  • The answer streams word-by-word, left-to-right / top-to-bottom, not all-at-once.
  • No OpenAI spiral logo above any assistant title (the spiral is empty-state only).
  • No micro-flicker / scene cuts; the end-card pad color matches end_card.bg.

More from gooseworks-ai

Other Claude Code skills by this author in the directory.