| name | art-director |
| namespace | user |
| description | Prompt and asset generation craft — turns an approved scenario into prompts.json and generated media through `ralphy generate`. Owns anchor order (location-master-plate first), character fit, photoreal-human prompting, model choice and cost preview, the reference-photo policy, regeneration rules, and the image/video quality gate. USE WHEN the user asks to "generate prompts", "generate assets", "make images / video / voiceover / music", "regenerate scene-XX", "try a different model", "A/B variant", "how much will this cost". TRIGGER (EN): "generate prompts", "make the images", "regenerate scene", "model swap", "cost preview", "A/B variant", "redo this shot". |
Art director playbook
Read this when: "generate prompts", "generate assets", "make images / video / VO / music", "regenerate scene-XX ", "try a different model", "A/B variant", "how much will it cost".
Anchor order discipline (every multi-scene project):
- Location-master-plate first — for any project where ≥2 scenes share a setting, generate the room / location plate as anchor #1, BEFORE any character or scene anchor. Pass the plate as
--ref alongside character masters on every subsequent scene gen. Skipping this cost noski-people-001 $0.45 image-regen + 45 min user-feedback loop ("in every shot they're sitting on a different couch and I asked for the same one" — three different couches across three anchors). For ≥25-scene projects, the plate alone isn't enough — generate ≥3 unique anchor angles per recurring subject (location, hero character, hero product). Full discipline + CLI shape + worked example: art-director/location-plate.md. This is the single highest-leverage rule in this playbook.
- Character / persona masters second — one per cast member, each generated with the location plate as
--ref. Pass both (location + character) on every downstream scene gen to lock identity + setting.
- Scene anchors third — scene-01 first, surfaced to user → wait → scene-02 → wait → … only batch 4-6 anchors at a time AFTER two solo gens land with user approval.
- i2v / video generation last — never i2v an unapproved scene anchor.
Photoreal-human projects: read art-director/photoreal-humans.md before drafting prompts — TV-commercial register (Tom-Ford / chiaroscuro / marble) is the wrong default for natural-feeling UGC; use Sony A7 IV + Sigma 35/85mm + Kodak Portra 400 still-photo register instead. Venom-bodywash-001 burned ~$3 on this miscalibration.
Aesthetic-lock checkpoint (HARD gate, applies before anchor fan-out): after the location-master-plate (anchor #1) and the character master(s) (anchor #2) are approved by the user, the agent MUST (a) name the register in one phrase ("still-photo candid documentary" / "Old-Spice high-key commercial" / "liminal-spaces analog-horror" / "CGI translucent specimen" / etc. — taxonomy at the top of photoreal-humans.md), (b) run the character-fit.md check (clean mascot + gritty register? pick reinterpret / distressed-variant / shift-register BEFORE fan-out), (c) write the one-line aesthetic-lock string into STORYBOARD.md, and (d) generate one cover per register and surface it to the user. Refuse to fan out scene anchors until the cover is approved. Skipping this is the documented cause of ralphy-vs-higgsfield-001's three-register shipping defect (Lesson #7) and ralphy-carousel-001's clean-ghost-in-punk drift (postmortem #2). When in doubt about which register applies, run ralphy ref pull <one-canonical-url> --frames and READ the frames — do NOT scrape-summarize (biofix-hypnic-en-001 defect class).
Model drift handling: read art-director/regeneration.md — one retry max on a kling/seedance prompt that misses; then redesign the scene, don't fight model basins. Glitter-cream-001 lost 2× $0.42 fighting "jar near cheek → powder compact" drift across 3 retries.
Between "scenario approved" and "assets on disk for the editor" — that's my zone. Prompt engineering, API orchestration, single-slot regeneration, A/B variants, cost discipline. Never invent model-id from memory — always cross-check MODELS.md.
STOP rule. Every model call goes through ralphy generate. No raw fetch / curl / bunx tsx against a media API — gen-log + asset-manifest + cost rollup all depend on the CLI. AGENTS invariant #2.
CLI cookbook
Every model call goes through ralphy generate. No raw fetch / curl / bunx tsx against media APIs — the gen-log + asset-manifest depend on it. Cross-check MODELS.md for --model overrides.
ralphy generate image --project <id> --slot scene-01-bg --prompt "<text>" \
[--ref <url> ...] [--model <id>] [--size 1080x1920] [--negative "<text>"]
ralphy generate video --project <id> --slot scene-01-vid --prompt "<motion>" \
--duration 5 [--image <ref-url>] [--model <id>] [--audio]
ralphy generate voiceover --project <id> --slot scene-01-vo --voice <voiceId> --text "<line>"
ralphy generate music --project <id> --slot bed-01 --prompt "<genre, tempo, mood>" --duration 30
ralphy generate captions --project <id> --audio <vo.mp3>
ralphy generate video --project <id> --slot scene-03-vid --prompt "<new>" --duration 5
ralphy project show <id> --assets
ralphy project show <id> --prompts
ralphy project log <id> -- generations -- 50
ralphy asset list --project <>
If you reach for a backend that isn't covered (e.g. lipsync, image editing, talking-head) — STOP. Don't write a script. Either MODELS.md already documents the route, or propose adding the verb to cli/commands/generate.ts.
Sub-docs (read on demand)
Sub-tasks
| Sub-task | When | Sub-docs |
|---|
prepare-prompts | scenario.json ready, prompts.json missing/stale | prompt-style |
generate-assets | prompts.json ready, asset-manifest incomplete | regeneration |
regenerate-slot | "regenerate scene-XX", model/prompt/seed change | regeneration + quality-gate |
compare-variants | "I want 2-3 variants of this shot" | regeneration |
cost-preview | "how much will N videos cost" | model-choice |
What I read on start
AGENTS.md — invariants (no FAL, no scripts, ref-required, quality gates).
MODELS.md — every model call. Don't hardcode from memory.
.agents/skills/ugc-* (and /poster, /carousel, …) — the content-niche craft-overlay skill for the brief's kind of content, loaded on top of the matched format / template as the prompt-authoring overlay. The format / template is the primary route (docs/templates-index.md, ralphy template suggest --help); a style template doubles as a remix target only when the user pointed at a specific video to reproduce. See docs/skills-vs-templates.md.
docs/creative-library/personas/ARCHETYPES.md — 8 archetypes (when there's a persona slot).
docs/creative-library/scenes/SETTINGS.md — 9 scene settings (when you need to pick a setting).
.ralphy/workspaces/<ws>/projects/<id>/scenario.json — slots + VO text.
.ralphy/workspaces/<ws>/projects/<id>/prompts.json — what already exists.
.ralphy/workspaces/<ws>/projects/<id>/asset-manifest.json — what's already on disk (skip).
.ralphy/workspaces/<ws>/projects/<id>/logs/generations.jsonl — on regeneration, to avoid repeating a failure.
templates/<slug>/{TEMPLATE,hooks,prompt-cookbook}.md (or .ralphy/workspaces/<ws>/templates/<slug>/) — if the project was scaffolded from a template, the cookbook is your prompt-writing reference.
Step 1 of every gen — read the library (02.0L.03)
Before writing a prompt for any slot, run ralphy prompts library lookup --goal "<one-line description of the slot>" and read the top-matched entry.md. The library is organized by goal/situation (not by model) — it carries the Bad / OK / Ideal worked-example pattern for hooks, product reveals, selfie monologs, caption styles, music modes, and so on.
ralphy prompts modes --kind <video|voice|music> lists the cookbook mode files when the agent already knows which model family to call. Pair the library entry (goal layer) with the per-model adapter (shape layer) — the adapter consumes a NormalizedPrompt and emits the model-specific syntax automatically (see cli/lib/providers/prompt-adapter/).
Hard rules (inherited from AGENTS.md)
- All calls go through
ralphy generate {image|video|voiceover|music}. No runtime TS scripts in .ralphy/workspaces/<ws>/projects/<id>/scripts/. If an operation isn't covered — stop and extend cli/commands/generate.ts, don't copy code into the project.
- Reference-required gate (named real entities only). See art-director/ref-photo-policy.md. The gate fires for a named person / recognizable brand product / IP. Generic briefs do not trigger. Override path:
ralphy generate ... --no-ref-consent "<reason>" on the specific failing call; the CLI auto-appends stage: "no-ref-consent" to user-prompts.jsonl.
- Quality gate. See art-director/quality-gate.md. Two failures in a row → stop, report concrete options to the user. Refuse, do not warn (AGENTS invariant #4).
- MODELS.md is the only source. See art-director/model-choice.md. Always pick the best model per kind — there is no "cheaper draft" path. Budget caps (
.agents/skills/producer/SKILL.md#budget) are the lever to control cost, not model downgrade (04.0A.03).
- Iterate by single-slot regen, never overwrite. "Rework scene-03" →
ralphy generate <kind> --project <id> --slot scene-03-<kind> --prompt "<new>". Append-only versioning writes <slot>.v2.<ext> (then v3, v4, …). The prior version stays on disk for diff / rollback; the manifest tracks both. Pass --force-overwrite only when the user explicitly asks for legacy destructive behavior (04.01.03).
- Generation logging is automatic via
ralphy generate (logs are written to generations.jsonl). User-prompt logging is NOT automatic — you MUST log it. Every user feedback turn on an anchor / prompt / model swap goes to user-prompts.jsonl via ralphy project log-prompt <id> --text "<verbatim>" --stage <feedback|approval|critique|rejection> BEFORE you regenerate. Same MUST-log discipline as the scenarist playbook (see → "User-prompt logging"). "Try v2 with a wider lens", "approve scene-03", "scene-05 looks AI-slop" — all log-prompt turns. Sparse logs are the documented cause of unreliable postmortems.
Prompt hygiene
Three small rules every ralphy generate call should clear before submit. Each is a one-liner; each saves one regen cycle (~$0.15–$1) per occurrence and was filed from a real postmortem. See notes/issues/done/050-anti-mockup-and-prompt-hygiene.md for the bundle.
1. Anti-mockup directive (nano-banana / gemini-3-pro-image-preview)
nano-banana defaults to a tiny iPhone-mockup-in-corner composition unless the prompt explicitly forbids it. Without the forbid-string, even a clearly full-bleed brief (poster, hero, magazine layout) comes back with a postage-stamp phone floating in the lower third. Validated on appstore-takeaminute-001 (screen-01-hero-v2/-v4 both leaked mockups; 2 paid regens at $0.15 each before the directive went in; ~8 further regens prevented across the run).
Rule. Any full-bleed slot prompt for nano-banana / gemini-3-pro-image-preview MUST lead with the verbatim block below. The HERO / TROPE / CTA register from appstore-takeaminute-001 is the canonical wording:
CRITICAL: This is a FULL-BLEED MAGAZINE POSTER LAYOUT — NO iPhone
device frame, NO phone mockup, NO screen bezel. The poster IS the
entire image edge-to-edge.
The player-UI-overlay variant (HD / video-content register) — use when the slot is "video still with player chrome drawn on top", not a poster:
CRITICAL: This is FULL-BLEED video content with a PLAYER UI OVERLAY
drawn directly on top — NO iPhone device frame, NO phone-mockup bezel
around the image. The video scene IS the entire image edge-to-edge;
the player chrome (scrubber, quality pill) sits ON TOP of the video
like a watermark.
When the slot genuinely IS a phone-mockup (LIBRARY / NEW screen in an App Store pack — i.e. the phone is the intended subject), invert the rule and name the mockup explicitly so nano-banana places it deliberately instead of as a leak:
CENTER VISUAL: sleek 3D angled iPhone mockup floating tilted, screen
showing <concrete scene description with named in-app content>. Soft
<brand-color> glow under the phone, additional cards spilling out
behind in 3D depth.
Naming actual in-app content (real series titles, real card text, the brand's real palette) makes nano-banana populate the mockup with plausible on-brand artwork instead of generic placeholders. Source: .ralphy/workspaces/<ws>/projects/appstore-takeaminute-001/POSTMORTEM.md § "Prompt patterns that worked (verbatim)".
2. Markdown punctuation in quoted strings
Markdown emphasis (**bold**, _italic_, ~strike~) inside a typography slot bakes literal asterisks / underscores into the rendered glyphs. appstore-takeaminute-001 shipped a prompt with **EVERY DAY** and got back a poster with actual ** characters set in the headline — a $0.15 regen.
Rule. Before submitting any ralphy generate image / ralphy generate video prompt that quotes on-poster / on-screen copy, scan the quoted strings for **, __, ~~, and stray single * / _ used as emphasis. Strip them, OR replace them with a non-markdown emphasis directive (e.g. the word EVERY DAY set larger / in the accent color). The model only sees plain text — there is no markdown renderer between you and the typography. The CLI-side fix (auto-strip at the cli/lib/providers/media.ts submit boundary, or warn-on-detect) is a future cleanup; until it lands, this is an agent-side hygiene step.
3. Background-job file hygiene
Mirror of AGENTS.md invariant #17. ralphy generate image --prompt-file reads prompt / ref files lazily during the run, not eagerly at submit. Deleting or rewriting those files while the daemon is running fails silently — ralphy-carousel-001 lost slides 03-05 of a 6-slide dark-background loop because rm prompts/slide-0?.txt ran mid-loop and the daemon reported --prompt arg missing without aborting.
Rule. While any background ralphy generate is in flight against this project, treat its --prompt-file, --ref, and prompts/ paths as read-only. To swap a prompt, kill the job first and relaunch; do not edit-in-flight. The CLI-side fix (snapshot prompt-file contents at submit time, or warn-on-delete-of-referenced-file) is tracked in the same issue.
Split-scene-instead-of-regen (repeat-failure rule)
Rule. When a single scene fails twice on the same axis — the same motion beat, the same camera move, the same physically-impossible action — stop re-prompting and split it into N micro-shots inside the original slot's time budget. Don't try a third prompt variant; that loop converges nowhere.
The default agent instinct is re-prompt-on-fail (tweak verbs, try a different model, add a negative). For "one beat the model can't deliver" failures, that instinct is wrong. Splitting converts an impossible 5s shot into three possible ~1.6s shots — each a beat the model can hit — and the editor stitches them within the same slot duration. The total cost is usually lower than a third regen and the result actually lands.
Concrete example — flipper-hypermotion-001 scene-03 (POSTMORTEM rule #11). Scene-03 was a single 5s hypermotion shot the model couldn't sustain; two regens on the same prompt axis drifted the same way. The redo (one scene, split into micro-shots) cost $1.28 — ~10% of the entire project budget — and produced more lessons per dollar than the rest of phase 3 combined. The lesson the postmortem locked in: the second failure on the same axis is the signal to restructure, not to re-prompt.
Structural pairing. Splitting becomes much cheaper once ralphy ref extract-frame + ralphy generate video --extend-from <slot> ship (see notes/issues/done/012-no-frame-extract-or-i2v-extend-verbs.md) — that pair lets you i2v-anchor each micro-shot from the previous one's last frame, keeping continuity without a fresh anchor for every sub-beat. Until those verbs land, hand-author the split by reusing the scene anchor as --ref on every micro-shot.
Operationally.
- After the second failure on the same axis, write down the axis in one line ("camera can't crash-zoom through the prop on contact") and stop regenerating.
- Rewrite the scene as 2-4 micro-shots whose durations sum to the original slot. Each micro-shot must be a beat the model has hit in this project before.
- Update
scenario.json slot list (scene-03a, scene-03b, …) via ralphy project update, regenerate prompts for the new slots only, then ralphy generate each.
- Editor stitches the micro-shots back into the original scene's time window.
Pre-render self-review (HARD gate)
Before handing the project to the editor for ralphy render <id> — every project, no exceptions — walk the pre-render checklist. This is not a soft "should snapshot key beats"; it is a refuse-not-warn gate.
- MUST snapshot every beat in
STORYBOARD.md via bunx hyperframes snapshot .ralphy/workspaces/<ws>/projects/<id> before render.
- MUST eyeball every snapshot for anatomy (hands, eyes, limb clipping — the
noski-people-001 failure class).
- MUST eyeball every snapshot for location continuity (same couch / wall / light across scenes that share a setting).
- MUST eyeball every snapshot for pivot / camera-axis sanity (180° line, camera height, no v1→v2 mirror flip).
- MUST cross-check identity locks against each cast master shot.
- MUST verify on-prompt props present at the right timestamp.
A single fail aborts the render — fix at this layer via regeneration.md, then re-snapshot. Full worked rationale + noski-people-001 / odindoma-fb-ad-001 postmortem evidence in art-director/pre-render-checklist.md.
The future --require-snapshot-review flag on the ralphy hyperframes render namespace (out of scope here — tracked in notes/issues/028) will mechanise this gate. Until it ships, the agent enforces by reading the sub-doc.
Handoff
- After
generate-assets with all slots filled → editor playbook (compose + render).
- After
regenerate-slot → re-render via ralphy render <id> if the editor has already composed.
- If VO changes → captions are regenerated inside
generate-assets (after VO).
- If the scenario doesn't hold up → handback to scenarist playbook.