Install
$ agentstack add skill-duncan-buildroom-profit-room-skills-saas-ad-studio ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
SaaS Ad Studio — cinematic UI ads from a URL
You turn a live SaaS product into a short, premium, UI-forward cinematic ad. The look is the current AI-tool standard: pitch-black canvas, a single accent color, real product screenshots revealed scene-by-scene in locked frames, scored with music and clean on-screen text. No talking heads, no avatars, no stock footage — the product's own interface is the hero.
This skill is the SaaS/UI sibling of ad-studio (which is for physical products). It reuses that skill's living-brief.html, "Visual DNA" prompt discipline, and ffmpeg assembly, driven by the Higgsfield MCP motion engine.
The one rule that makes or breaks this: DO NOT let the UI morph
AI video models warp text and UI when asked to animate an interface. The entire technique here is built to avoid that:
- The real screenshot is the first frame. Motion comes from the camera and light, never
from the model redrawing the UI.
- Allowed motion on a UI shot: slow push-in, gentle parallax/drift (1–2%), rack focus, a glint
of light, the accent color pulsing, a soft reveal from black. No whip pans, no UI elements re-animating, no morphing menus, no cursors that retype text.
- If a feature needs to "do something," show it as a hard cut between two real screenshots,
not as in-frame animation.
- Every Seedance prompt ends with the guardrail line: *"Interface stays perfectly sharp and
static; do not warp, morph, or re-render any UI text, icons, or layout."*
Read references/cinematic-ui-doctrine.md before writing any prompt. It has the camera vocabulary, the shot archetypes, and copy-paste prompt templates.
Requirements
- Higgsfield MCP — the motion/image engine (
generate_image,generate_video,
models_explore, media_import_url, media_upload, media_confirm, job_display, show_generations, upscale_video). Tool names are prefixed per your install (mcp____generate_image, etc.) — check your connected MCP list for the exact prefix and use those names. Requires a Higgsfield account with credits. No key is embedded here.
- Playwright MCP (
mcp__playwright__browser_*) — for the live UI audit / screenshots.
Firecrawl firecrawl_scrape is the no-login fallback.
- ffmpeg (installed locally) — assembly, on-screen text, muxing.
- Graceful fallback: if the Higgsfield MCP isn't connected, tell the user to add it (or fall
back to any image/video-gen MCP that exposes equivalent generate_image/generate_video tools); if Playwright isn't available, use Firecrawl for screenshots + copy and note the limit.
Tooling (use these exact tool names)
- Image model:
gpt_image_2— paramsquality: high,resolution: 2k|4k, oneimage
reference role.
- Video model:
seedance_2_0—duration4–15s per clip, setgenerate_audio: false
on UI shots (we score in post), roles include start_image.
- Audio/music: no standalone music model exists here — use the video model's native audio
(generate_audio:true on Seedance), best captured on a single 15s timestamped render that scores the whole clip. Royalty-free/track fallback in references/assembly.md. You can't QA audio by ear in-harness — surface it for the user to judge.
- Audit: Playwright MCP (
mcp__playwright__browser_*). Firecrawlfirecrawl_scrapefallback. - Assembly:
ffmpeg(installed). Seereferences/assembly.md. - Full tool/param contract, polling, downloading, and
get_costpreflight:
references/higgsfield-tools.md — read it before the first generation call.
Seedance caps at 15s per render, but a single render can hold multiple internal cuts via a timecoded prompt — so a 15s ad is usually one render of ~3–5 timestamped shots (this is how ad-studio renders). Longer ads chain 15s segments: a 30s ad ≈ two segments, a 60s ad ≈ four, ffmpeg-concatenated. Tooling is website + Higgsfield + ffmpeg only — no Remotion or other editors.
Phase 0 — Intake (one message)
Ask everything at once. Fill any blank with the default and move on; only the URL is required.
- Product URL (+ login creds / a path to a staging build if the good screens are gated).
- Aspect ratio —
16:9(default; site hero / YouTube),9:16(Reels/TikTok/Shorts),1:1. - Duration —
15/30(default) /60s. - Sound —
music + on-screen text(default) /+ AI voiceover/music only. - Brand — paste brand colors + logo URL if known; otherwise I extract them from the live CSS.
- Feature focus — the 3–6 screens/features to spotlight; otherwise I pick the hero modules.
- Output dir — default
./saas-ad-studio//.
Create the output folder tree, then proceed autonomously to the first check-in.
Phase 1 — Live audit + Brand DNA (autonomous)
Goal: real screenshots + the real brand, never invented. Follow references/audit-playbook.md.
browser_navigatethe URL; if creds were given,browser_fill_form/browser_typeto log
in. Walk every reachable key route.
browser_resizeto a clean capture size matched to the chosen aspect (e.g. 1920×1080 for 16:9,
1080×1920 for 9:16), then browser_take_screenshot each hero screen → screens/.
browser_evaluateto read the live CSS tokens off the DOM: background, surface, the single
accent, text, border hexes, and font-family. This is the source of truth for the palette.
- Grab the logo (favicon/nav SVG/PNG). Note the module map and any real numbers visible in the UI
(counts, statuses, names) — they make great on-screen text.
- No login / SPA blocks Playwright? Fall back to
firecrawl_scrapeon the marketing site for
copy + colors, and use marketing-page hero screenshots.
- Parallelize: this is a good place to fan out subagents (one per route) if the app is large.
Write research.md (palette + hexes, type, voice, module map, the real numbers). Initialise brief.html themed from the extracted palette — the product's own brand drives the brief.
Phase 2 — Concept + look — ⏸ CHECK-IN 1
Present 2–3 concepts on brief.html (with the captured screenshots embedded). Each concept:
- Logline — one sentence.
- 4-act arc scaled to the chosen duration: **hook → problem → feature reveals → payoff +
logo lock.** Map each beat to a specific real screen from screens/.
- Visual signature — how the single accent is used; the on-screen-text style.
- Music mood — 3–5 words.
Recommend one. After the user picks, lock two verbatim blocks into dna.md:
- Concept spine — 2–4 things that must be visibly true in every shot.
- Visual DNA — the exact lines appended to every image and video prompt: pitch-black
canvas, accent hex, Inter-class type, grain/glow, camera language, and the no-morph guardrail.
Phase 3 — Shot list + hero frames — ⏸ CHECK-IN 2
Decompose the arc into N shots (respect 4–15s/clip and the total duration). For each shot record: duration, the real screen used, camera move, UI treatment (flat push-in / UI floating in dark volumetric space / on a device / glass reflection), on-screen text copy, and the accent moment. Write shotlist.md.
Build one hero frame per shot:
- UI shots: composite the real screenshot into the cinematic dark scene with
gpt_image_2
(screenshot passed as the image reference, quality: high, resolution: 2k), keeping the UI on a flat, undistorted plane — OR, for a clean straight push-in, use the raw screenshot directly (no regeneration = zero morph risk).
- Brand / atmosphere / logo-lock shots: text-to-image with
gpt_image_2. - Append the Visual DNA lines to every prompt.
Render frames in parallel, bind each job to its filename (never trust completion order), eyeball each as it lands, re-render any that break the brand/UI (max 2 retries, then show best and flag). Save to frames/ (01.png…). Present the full storyboard on brief.html and get approval before spending video credits.
Phase 4 — Animate the shots (autonomous)
models_explore get seedance_2_0 once to reconfirm params. Two render methods — prefer A:
A — Single timestamped render with EVERY storyboard frame as a reference (default — strongly preferred). Render the whole 15s ad as ONE Seedance call: pass all the storyboard frames as references in narrative order (cap ~9) — start_image = the opener/establishing frame, end_image = the logo lock, and every middle beat (the real UI screenshots, proof cards, comparison, community) as image refs. Write the prompt as timecode blocks, each naming the shot's reference content + its camera move, and explicitly tell it the UI animates (scrolls, glows, cursor moves, light sweeps) and must not warp/melt/scramble text or numbers. Set generate_audio:true so the same render carries the score. This gives native animation + native transitions between the real frames — far better than ffmpeg-stitching separate clips, and it makes the actual product UI come alive (passing the real screenshot as the reference is what animates it). This is how ad-studio renders, and it's what the user wants. Template in references/cinematic-ui-doctrine.md.
B — Isolated start_image shot (fidelity fallback). Only when ONE beat's text must be pixel-perfect and Seedance softened it too much in the single render — re-render just that beat from its real screenshot as start_image, or overlay that one number/label with an ffmpeg text pass. Reach for this surgically, not as the default; don't fall back to stitching the whole ad in ffmpeg.
generate_video(params:{
model: "seedance_2_0",
prompt: " … … ",
medias: [{ role: "start_image", value: "" }, { role: "image", value: "" }, …],
duration: 15, // method B: the shot's own 4–15s
aspect_ratio: "",
resolution: "1080p",
generate_audio: false,
count: 1
})
For a 30/60s ad, render multiple 15s timestamped segments (each its own mini-arc) and concat them in Phase 5. Submit in batches of ~4, poll to terminal, download each to shots/ (01.mp4…). Watch each; if the UI morphs or a cut breaks, re-render that one segment once with tighter/lower motion — don't loop endlessly. Media IDs, polling, downloading, and the multi-shot pattern are in references/higgsfield-tools.md.
Phase 5 — Music + on-screen text + assembly (autonomous)
- Audio/music: prefer Seedance native audio (
generate_audio:true) — describe the score in
an Audio: … line in the render prompt. A single 15s timestamped render scores the whole clip in one pass (best). No standalone music model exists; for a specific track, mux a royalty-free/user track per references/assembly.md.
- On-screen text: burn the per-beat copy with ffmpeg
drawtext(Inter/Inter-class font,
accent color for emphasis), or pre-render text cards as transparent PNGs and overlay. Keep it minimal — one idea per beat.
- Optional VO (only if chosen at intake): generate the line with
text2speech_v2_elevenlabs,
time it under the cut, and duck music ~-10 dB beneath it.
- Assemble: a single 15s timestamped render just needs text burned + music muxed; for a
multi-segment ad, concat the 15s segments first (hard cuts + the occasional 6–10 frame dissolve), then text + music. Optional upscale_video for a 4K master.
- Output
ad-final.mp4. The full ffmpeg command set (concat, drawtext, mux, ambience-duck) is in
references/assembly.md. Website + Higgsfield + ffmpeg only — no Remotion or other editors.
Phase 6 — Deliver
Finalize brief.html: embed ad-final.mp4, lock every section, add a one-line "recreate" recap. Print the output folder tree and the final file path. Note credit spend if the user asked.
Output folder (per run)
saas-ad-studio//
├── brief.html # living doc: research → concept → DNA → storyboard → final video
├── research.md # palette+hexes, type, voice, module map, real numbers
├── concepts.md # the 2–3 concepts + which was picked
├── dna.md # Concept spine + Visual DNA (verbatim, appended to every prompt)
├── shotlist.md # locked shots: screen, camera, UI treatment, text, duration
├── screens/ # raw captured screenshots (source of truth for the UI)
├── frames/ # cinematic hero frames 01.png …
├── shots/ # rendered clips 01.mp4 …
├── music-prompt.txt
├── music.m4a
└── ad-final.mp4
Check-in protocol (only 2)
- Concept + look (end of Phase 2) — pick a concept; locks the spine + Visual DNA.
- Storyboard (end of Phase 3) — approve the hero frames; gates the video render spend.
Everything else runs autonomously. Show every rendered asset on brief.html the moment it lands (never "rendering…" placeholders).
Rules
- Never invent UI. Every screen shown must be a real screenshot from
screens/. Every claim
in on-screen text must trace to something actually in the product.
- Single accent. Use the one extracted accent hex; resist adding a second color.
- Preflight cost with
get_cost: truebefore a big batch if the user is watching credits. - Match the user's language in all on-screen text and copy.
- Default look = the doctrine. Only deviate if the user asks for a different style.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: duncan-buildroom
- Source: duncan-buildroom/profit-room-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.