@officexapp/vidfarm-devcli 0.21.27 → 0.21.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.agents/skills/editor-capabilities/SKILL.md +52 -0
  2. package/.agents/skills/vidfarm/SKILL.md +58 -5
  3. package/.agents/skills/vidfarm/recipes/bulk-scripting-with-a-regime.md +65 -0
  4. package/.agents/skills/vidfarm/recipes/cutout-graphics-for-explainers.md +78 -7
  5. package/.agents/skills/vidfarm/recipes/local-edit-render-approve.md +4 -3
  6. package/.agents/skills/vidfarm/recipes/retheme-template.md +1 -1
  7. package/.agents/skills/vidfarm/references/assets-and-sourcing.md +3 -3
  8. package/.agents/skills/vidfarm/references/automation-and-local-dev.md +92 -1
  9. package/.agents/skills/vidfarm/references/editor-workflows.md +135 -6
  10. package/.agents/skills/vidfarm/references/hooks-and-virality.md +237 -0
  11. package/.agents/skills/vidfarm/references/onboarding.md +5 -5
  12. package/.agents/skills/vidfarm/references/primitives.md +5 -1
  13. package/.agents/skills/vidfarm/regimes/README.md +77 -0
  14. package/.agents/skills/vidfarm/regimes/explainer.QA_REGIME.md +82 -0
  15. package/.agents/skills/vidfarm/regimes/hooks.QA_REGIME.md +117 -0
  16. package/.agents/skills/vidfarm/regimes/product-demo.QA_REGIME.md +92 -0
  17. package/.agents/skills/vidfarm/regimes/short-form.QA_REGIME.md +163 -0
  18. package/.agents/skills/vidfarm/regimes/ugc-testimonial.QA_REGIME.md +82 -0
  19. package/SKILL.director.md +685 -32
  20. package/SKILL.md +22 -3
  21. package/demo/dist/app.js +103 -103
  22. package/dist/src/cli.js +987 -11
  23. package/dist/src/devcli/handoff.js +162 -0
  24. package/dist/src/devcli/interaction-mode.js +154 -0
  25. package/dist/src/devcli/qa-check.js +593 -0
  26. package/dist/src/devcli/qa-regime.js +396 -0
  27. package/dist/src/devcli/sticker-pack.js +396 -0
  28. package/dist/src/devcli/storyboard.js +243 -0
  29. package/package.json +8 -1
  30. package/public/serve-shells/tools-image.html +378 -265
  31. package/public/serve-shells/tools-video.html +760 -167
@@ -77,6 +77,58 @@ Audio is natively **multi-track**. The timeline mixes UNLIMITED simultaneous `<a
77
77
  - **The headline move — split a combined original when recreating.** When the user recreates a template whose ORIGINAL had music + narration baked into ONE audio track, do NOT reproduce a single combined bed. Rebuild it as TWO independent tracks: a fresh narration track (`/api/v1/primitives/audio/speech`, or same-voice reword via `/api/v1/primitives/audio/regenerate-speech`) at ~1.0, and a separate real music track at ~0.1–0.2 — then mute or `remove_layer` the original combined source-audio layer so the old voice doesn't play under the new one. This hands the user independent voice/music volume and is the elegant workaround for AI TTS being unable to emit narration+music in one file.
78
78
  - **Honesty (ties to the create-media rules):** you cannot un-mix / stem-separate the original's baked audio — the two tracks are BUILT from a fresh narration track PLUS a real music file (owned / user-provided / `browse_files` across `/files` and `/raws`), never a faked "music" layer and never the voice track duplicated. There is no music-generation primitive.
79
79
 
80
+ ## The four charges — structure before polish (hard constraint)
81
+
82
+ Every video you touch has four charges in series, and **you write them before you start moving layers**. Editing is the fun part, so it gets done first and the words get retrofitted — that's how a beautifully-edited video ends up with nothing to stop for.
83
+
84
+ 1. 🪝 **Hook** — the opening line, as text, on screen at `start:0`. A **complete clause** (subject + verb), no jargon, naming a **situation** ("I've quit six businesses") not a label ("anonymity"). Caption chunk 1 is read before any audio — muted autoplay is the default viewing condition, so the text hook outworks the spoken one. Banned openings: throat-clearing, a logo, a title card, a fade from black, context before the claim.
85
+ 2. 🔄 **Loop** — one open question by 0:10, stated **on screen**, closing **inside this video** (name the timestamp; if you can't, there's no loop). The withheld answer must be one the viewer **can't supply themselves** — a loop whose answer they can guess passes every mechanical check and dies in the field.
86
+ 3. 😍 **Payoff** — shown, not summarized, landing before the final beat. The payoff is not the CTA.
87
+ 4. 🎣 **Bait** — one ask, final beat, and tell the user to put it in the post caption too. Never a DM funnel, "follow for part two", or ragebait.
88
+
89
+ **On a re-theme this is the thing you protect.** `editor_context` → `viral_dna.hook` / `retention` / `payoff` / `emotional_punch` tells you what the source's charges were — that structure is *why the template worked*. Rebuild each charge for the new subject; flattening the loop into a product statement is the most common way a re-theme kills a format.
90
+
91
+ Full craft (the three gates, situations-vs-labels with worked fixes, loop mechanics, compliance, diagnosis-by-charge): `load_skill('vidfarm', file='references/hooks-and-virality.md')`. Read it before writing hook copy or re-theming.
92
+
93
+ ## The FIRST FRAME is the thumbnail (hard constraint)
94
+
95
+ Frame 0 is a single frame of ~30 in the first second, and it outweighs all of them: every feed card, share link, embed, and paused player freezes on it, so **more people see that one frame than watch the video**. Whatever you change, check what `t=0` looks like before you call the job done.
96
+
97
+ - **Something real is on screen at `start:0`.** If the opening clip starts at `0.4`, the poster is black — `set_layer_timing` it back to `start:0`, or add a held hook frame at the head.
98
+ - **No entrance transition on the FIRST clip.** `set_transitions` with a `fade-black`/`fade-white`/`flash` intro makes the poster a flat black/white rectangle; a zoom/slide/blur intro freezes it mid-move. Clear the entrance on the opening clip (junction transitions *between* later clips are fine and encouraged).
99
+ - **The hook words are already up at t=0** unless you're deliberately opening on a clean face/product shot — a poster that states the promise beats a pretty frame that doesn't.
100
+ - **After a re-theme or a scenes replace, re-check it.** Decomposed forks routinely inherit a blank/slate head from the source, and a swapped opening clip is the most common way a good edit ends up with a black thumbnail.
101
+
102
+ Full rationale + the devcli twins (`vidfarm stills --at 0`, `vidfarm qa`) in `vidfarm` → `references/editor-workflows.md` ("The first frame is the thumbnail").
103
+
104
+ ## The TEXT axis — social-native only, zero HTML slop (hard constraint)
105
+
106
+ You author into HTML, which makes it dangerously easy to build a **web page instead of a video**. This is the #1 way an AI-edited composition betrays itself. Apply on every text/graphic you place — and strip it when a decomposed fork or a pasted brand asset brings one in.
107
+
108
+ **The test:** *would this element exist if the video were shot on a phone and captioned in CapCut?* If its whole job is to look **clickable**, cut it. Nothing in a video is clickable.
109
+
110
+ **BANNED (never `add_layer` / `replace_composition_html` these):**
111
+ - **CTA buttons** — a filled/gradient capsule with action copy ("Sign Up for a Free Trial →", "Get Started", "Book a Call"), glow or drop shadow. A social CTA is *spoken* or a plain caption line.
112
+ - **Badge / chip / pill rows** — "✓ ID-Verified · ✓ No Credit Card Needed · ✓ 30-Min Trial". Say them as three *timed caption lines* on the footage instead.
113
+ - **Cards / panels** — a bordered, shadowed, or `backdrop-filter`-frosted rounded box holding a headline + subheading/URL. Text goes ON the footage, not in a floating panel.
114
+ - **Gradient text fills, neon border glows, elevation shadows, glassmorphism**, navbars, hero sections, feature grids, `<ul>` bullet lists, tables, "as seen in" strips.
115
+ - **Web-default type** — Inter/Roboto/system-ui/Arial/Helvetica at weight 400–600 and 16–24px.
116
+
117
+ **Greppable smell test:** typing `btn`, `badge`, `chip`, `tag`, `card`, `panel`, `container`, `row`/`col-`, `hero`, `cta`, `rounded-full`, `shadow-lg`, `backdrop-blur`, `bg-gradient-to-r`, `border border-…` → **stop and rewrite as timed text on footage.** A re-theme onto a SaaS/product subject is exactly where this creeps in — do NOT import the brand's website design language into the video.
118
+
119
+ **ALLOWED / encouraged:** arrows (drawn or animated), circle / scribble / underline highlight strokes, **italics**, ALL-CAPS, a single word in a pop color, mixed weights, inline emoji (sparingly), transparent cut-out stickers via `create-overlay`, and mock social UI (iMessage bubbles, a TikTok comment card, a countdown bar) — all native to the platform.
120
+
121
+ **Font + background regime (every caption/title, via `set_captions` / `set_layer_style` / `add_layer`):**
122
+ - **Font:** Montserrat (default) or TikTok Sans / Abel / Source Code Pro / Yesteryear — a family the composition actually imports, or it silently falls back to the slop sans. Weight **700–900**. `font_size` in px of the render canvas: **~36–64px** on a 1080-wide frame; never <28, never 0 (invisible). ~2 lines, ~5 words per line; `line_height` 0.95–1.15.
123
+ - **Position:** inside the **8%–85%** vertical safe zone (phone UI clips the edges) and clear of the right ~12% action rail — a centered box at `x:10 width:80` is safe. Lower-third ≈ `y:70`; a "POV:" top line ≈ `y:8`, never `y:0`.
124
+ - **Background — exactly one of four:** `background_style:"outline"` (stroke, the default look) · `"plain"` (bare + soft shadow) · an **active-word highlight pill** via `set_captions caption_style:"spotlight"|"karaoke"` (the *only* legitimate pill — it tracks the spoken word) · `"highlight-solid"`/`"highlight-translucent"` as a band that **hugs** the text (radius ≤~8px, no border, no shadow, no gradient, no blur, one text run — never a heading+subheading+URL stacked inside it). Anything else is a web card.
125
+
126
+ **There is no QA tool for you.** The devcli ships `vidfarm qa <dir>` — a free local blocklist pass over exactly the rules above — but it is **devcli-only with no REST twin**, so in the web editor you enforce this by reading your own output. When you hand a heavy job off to a local coding agent, tell them to run `vidfarm qa ./work` before rendering.
127
+
128
+ **If the user wants VOLUME, say so and hand it off.** "I need to post daily", "make 20 versions", "test these hooks" is **bulk/scripting mode**, not twenty turns of editor chat: a pinned base fork, a loop varying one thing per variant, and a **`QA_REGIME.md`** — the user's own written quality standard, which exists because nobody reviews variant #37 as carefully as #1. You can't run that loop (no shell, no filesystem), so name the pattern, offer the My Files handoff, and tell them the local agent should run `vidfarm regime init <base> --out ./work/QA_REGIME.md`, edit it with them, and gate the batch on `vidfarm qa ./work`. If they already have a regime file, its rules are still worth reading into your own edits here.
129
+
130
+ Deeper rationale and the devcli-side twins live in `vidfarm` → `references/editor-workflows.md` ("Social-native visual standard" / "TikTok-native caption standard").
131
+
80
132
  ## The `editor_action` verb catalog
81
133
 
82
134
  Every mutation is one `editor_action` call with an `explanation`. Reference keys/tracks/durations from the latest `editor_context`; never invent `layer_key`s. Grouped by axis of work:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: vidfarm
3
- description: Use Vidfarm as a director. Browse/add inspiration videos, browse the free public raws catalog BY CATEGORY (curated shelves like scroll-stoppers/greenscreen/reaction — the cheapest way to source footage for one video, and a ready-made clip pool for bulk scripting N variants), fork a template into a composition, edit it in the Trackpad Editor (timeline-based like Premiere/DaVinci), auto-decompose source video into scenes, render to MP4, approve into a shareable post, and schedule it. Includes login, provider keys, discovery, versioning, uploads/downloads, and billing. Every step is available as raw REST; `vidfarm-devcli` wraps those routes and composes the file-backed scripting flows.
3
+ description: Use Vidfarm as a director. Run a strategy **consultation** (the `brainstorm/*` chain — cold-start interview, awareness stages, persuasive angles, hooks, product placement). Browse/add inspiration videos, browse the free public raws catalog BY CATEGORY (curated shelves like scroll-stoppers/greenscreen/reaction — the cheapest way to source footage for one video, and a ready-made clip pool for bulk scripting N variants), fork a template into a composition, edit it in the Trackpad Editor (timeline-based like Premiere/DaVinci), auto-decompose source video into scenes, render to MP4, approve into a shareable post, and schedule it. Includes login, provider keys, discovery, versioning, uploads/downloads, and billing. Every step is available as raw REST; `vidfarm-devcli` wraps those routes and composes the file-backed scripting flows.
4
4
  ---
5
5
 
6
6
  # Vidfarm Director
@@ -125,6 +125,30 @@ Then **ask whether to remember the choice**, and save it where it will actually
125
125
 
126
126
  If the user hasn't picked yet and you're about to spend, name the cheaper path and the cost, and ask. `vidfarm cost-mode` with no argument prints the current mode + an explanation of each for you to relay.
127
127
 
128
+ ## Ask the SECOND question too: interactive or autonomous?
129
+
130
+ Cost mode answers *how much money may I spend*. It does not answer *how much of the user's own hands may I use* — and that second axis moves quality more than the first. **Ask both.** They are independent: every cost mode (`minimize`, `hybrid`, `rich-ai`, `pure-videogen`) runs in either interaction mode.
131
+
132
+ - **interactive** — the user is willing to do a little manual work at fixed checkpoints, and the video gets better for it. Two checkpoints cover nearly everything: **(1) images** — you write a prompt, they run it in a *free* frontier web generator (meta.ai / ChatGPT / Gemini / a Hugging Face Space) and hand the file back; **(2) raw clips** — you hand over search keywords, they search TikTok/YouTube, download a few with a free online downloader, and point you at the folder.
133
+ - **autonomous** — you finish end-to-end with zero steps from them: source clips yourself (browser control → `raws scan` → public raws), generate within the budget, or do without.
134
+
135
+ **Why interactive usually wins on quality:** the free tiers of the frontier web image models are typically *better* than what an API-key budget buys per image, and a human eye picks better footage than any keyword scan. In `minimize` the gap is not incremental — it's the difference between **no custom art at all** and **a full sticker pack for $0**.
136
+
137
+ **Ask it like this, once, near the start:** *"Two quick settings. First, how much should I spend per video (minimize / hybrid / rich-ai / pure-videogen)? Second — do you want to be in the loop? In interactive mode I hand you an image prompt to run in a free tool (you drop the PNG back) and a keyword list for sourcing clips; it costs you a few minutes and usually looks better. Or I can run fully autonomous."* Then persist it: **`vidfarm mode interactive|autonomous`** (→ `~/.vidfarm/interaction-mode.json`), alongside `vidfarm cost-mode <choice>`. Same memory etiquette as cost mode — offer to record it in `CLAUDE.md`/`AGENTS.md`, ask first. `vidfarm mode` with no argument prints the current pair + the explainer to relay. Per-run override: `--interactive` / `--autonomous`.
138
+
139
+ **The pairings, and what each means in practice:**
140
+
141
+ | | interactive | autonomous |
142
+ |---|---|---|
143
+ | **minimize** | **the sweet spot.** $0 *with* custom art: free web image-gen → `vidfarm sticker-pack`, plus hand-sourced clips. | $0 from stock + existing raws + HTML motion only. No custom art. |
144
+ | **hybrid** | Pay for the one or two shots only AI can do; the user's hands on the hero art. | Pay where it clearly wins, skip the rest. |
145
+ | **rich-ai** | Buy the reusable greenscreen cast, but let the user approve/redo the hero sheet by hand. | Budget does the work; you never stop. |
146
+ | **pure-videogen** | Human approval at script + storyboard gates (strongly recommended — a bad storyboard is expensive). | Fully unattended; quote the number first. |
147
+
148
+ **In interactive mode, MANUAL IMAGE WORK DEFAULTS TO STICKER PACKS.** Never ask for one graphic per round trip — each hand-off costs the user a context switch and costs you tokens re-reading a file. Ask for **one sheet holding every graphic**, then split it locally for $0. `vidfarm handoff image --theme "<what>" --items "a,b,c"` mints the whole brief (prompt + steps + the free tools + the follow-up command); `--single` when you really do want one subject. When the file comes back: `vidfarm sticker-pack <sheet> --items "a,b,c"`.
149
+
150
+ **Raw-clip sourcing has a ladder — hand it to the human only at the bottom rung.** In order: (1) **your own browser control**, if you have it — drive the search and download yourself; (2) **Vidfarm cloud** — `vidfarm clipper <url>` / `vidfarm raws scan <url> --cloud` resolves and mines the video for you; (3) the **free public raws catalog** — `vidfarm public-raws --category <shelf>`; (4) **the user**, when you're fully local/keyless or when human taste matters. That last rung is `vidfarm handoff raws --keywords "villa construction,pouring concrete" --platforms tiktok,youtube --purpose "<what the clips are for>"` — it prints the keywords, tells them to google a downloader (a *search*, not a link that rots), and names the import command for when the folder is ready (`vidfarm clipper ./downloads/<file>.mp4`, or `vidfarm raws scan` to mine a long one).
151
+
128
152
  ## Default stance
129
153
 
130
154
  - Treat the Trackpad Editor as the primary surface. Reach for templates and forks before primitives.
@@ -134,6 +158,17 @@ If the user hasn't picked yet and you're about to spend, name the cheaper path a
134
158
  - For heavy edits, read the grounding artifacts before acting: `video-context.json`, `editor-harness.json`, and local `.harness/*` bundles when present.
135
159
  - For agentic rewrites, think in the three axes: scenes, audio, text. Decide whether each axis is a SWAP or a REPLACE.
136
160
 
161
+ ## Storyboard first — the plan pass is a core part of the format now
162
+
163
+ **A composition project carries its plan with it.** `STORYBOARD.md` at the project root holds the ordered frames — one key moment each, with `duration`, `status`, an optional `src` pointing at that frame's sub-composition, a one-line `scene` description, and its `voiceover` line — and the optional `SCRIPT.md` beside it holds the full narration. This is a first-class part of the composition format, not a scratch file: **the Vidfarm editor renders it.** The Storyboard/Preview toggle at the top of the editor shows the plan as a contact sheet with a comment box per frame, tracks each frame through `outline → built → animated`, and hands the director's per-frame comments back to you.
164
+
165
+ That makes the storyboard the **cheapest place to be wrong**, and the natural interactive checkpoint: a plan is free to redo, a rendered scene is not.
166
+
167
+ - **Draft it before you build:** `vidfarm storyboard ./work --init --frames "Hook,Problem,Reveal,Proof,CTA"` (frames accept `Title|one-line scene`). Then fill in each frame's `scene` and `voiceover`.
168
+ - **Read it back any time:** `vidfarm storyboard ./work` prints the frames with their status marks and the current stage; `--json` gives an agent the parsed manifest.
169
+ - **Advance `status` as you build** — `outline` (planned) → `built` (a real sub-composition exists at `src:`) → `animated` (motion done). The editor's review stages are derived from exactly those counts, so keeping them honest is what makes the director's view meaningful.
170
+ - **In interactive mode, gate on it.** Show the storyboard, let the director comment or approve in the editor, *then* build. In `pure-videogen` this is not optional — an unapproved storyboard is the single most expensive mistake available (see the pure-videogen ladder above, and `vidfarm sequence` for the AI shot-sheet pipeline, which is a different thing: `sequence` generates storyboard *images*, `storyboard` maintains the plan *file* the editor reads).
171
+
137
172
  ## Say "create a vidfarm template that…" — reusable by default (the house habit)
138
173
 
139
174
  **Every video a director makes is really a *reusable template*, and Vidfarm's whole leverage comes from treating it that way.** So actively steer the user's language toward it: when someone asks to "make a video" / "create a TikTok" / "cut me an ad," gently reframe and echo it back as **"create a *vidfarm template* that …"** — then build it as a template, not a one-off export. This is a real, common, first-class workflow, not a marketing tic; name it as such.
@@ -169,8 +204,18 @@ Present both harnesses to the director, recommend (A) unless they've asked for p
169
204
 
170
205
  **Explainer/cutout videos — the transparent-sticker workflow.** For explainers (a subject "on stage" while labels, arrows, and props pop in around it), the cheap workhorse is a **transparent cutout sticker**: `vidfarm cutout --generate "<subject>"` AI-generates the graphic on a chroma plate, keys it out, **and trims the canvas down to the subject's true min width/height** — one free local ffmpeg step, no mostly-empty PNG to fight with — then `vidfarm place` + `vidfarm keyframes` scale/position and animate it (zoom, grow, shake, drift). It's the same "generate a reusable element once, then reuse it" thrift as the cheap harness, tuned for stickers. Full guided harness: recipe `recipes/cutout-graphics-for-explainers.md`; placement + zoom/grow/shake/move motion recipes: `references/editor-workflows.md` (“Cutout graphics for explainers”).
171
206
 
207
+ **"Make me a sticker pack" = ONE greenscreen sheet of many items, then masked apart — and `vidfarm sticker-pack` is that whole loop.** A sticker pack is never one graphic; it's a *set* (props, icons, reactions, characters, backdrops) that must share one art style. Generating them one at a time is both expensive (N image jobs) and inconsistent (N independent styles), so the move is the opposite: **generate a single image holding every item, laid out on a flat greenscreen plate, then cut each item out locally for $0.** `vidfarm sticker-pack --generate "<theme>" --items "a,b,c"` does all of it — one billed image job for the whole set, then a free local key, an **automatic** alpha-segmentation that finds each item (no hand-measured `--crop` rects), a per-item trim to its true bounding box, and a `stickers.json` manifest. Already have a greenscreen sheet? `vidfarm sticker-pack ./sheet.png` cuts it up for **$0**. Use `--dry-run` to eyeball the detected boxes first; `--gap` merges/splits items that came out joined or broken; `vidfarm mask <sheet> --crop …` is the manual fallback for one stubborn item.
208
+
209
+ - **Stickers are not necessarily small.** A sticker is *any* transparent element you place and animate — an icon, a mascot, a prop, a character, and equally **a full-width landscape, skyline, or backdrop** that fills the frame. `sticker-pack` filters speckle only; it has no maximum item size. Ask for the big pieces in the same sheet as the small ones.
210
+ - **Stickers are usually animated, not pasted.** Once placed, animate each one with `vidfarm keyframes` presets (`pop-in`, `float`, `shake`, `grow`, `slide-in-left`, `drift`) — that's HTML/CSS canvas motion, deterministic, free, and identical in preview and render. Layer moves up (pop-in, then idle float) for real life. See `references/editor-workflows.md` → "Cutout graphics for explainers".
211
+ - **A sticker can carry its OWN motion too.** A *moving* subject has no single bounding box, so it isn't a PNG: key the clip with `vidfarm remove-greenscreen <video>` → transparent WebM (browser/editor-playable, the right choice on a composition).
212
+ - **The plate must be a color the ART DOESN'T USE — green is a default, not a law.** A chroma key removes exactly ONE color, so a green plate under green artwork (leaves, frogs, plants, money, an "eco" icon set) keys holes straight through the stickers. `sticker-pack`/`cutout` handle this for you in two ways, and you should still say it out loud when it matters: **(a)** when generating, they read the subject and move the plate off any hue it mentions — green → magenta (`#FF00FF`) → blue (`#0047BB`) → black → white — and print which plate they picked and why; **(b)** when splitting a sheet you already have, they **detect the plate from the sheet's four corners**, so a red/purple/blue sheet handed back from a web generator just works. Pin it yourself with `--key-color "#FF00FF"` / `--preset magenta` (that disables the auto-pick), or `--no-auto-key` to force plain green. If a pack's palette collides with *every* standard plate, split it into two sheets on two different plates rather than fighting the key.
213
+ - **Transparent GIF is supported, for GIF-only surfaces.** `vidfarm sticker-pack … --output-format gif` (stills) and `vidfarm remove-greenscreen <video> --gif` (animated) emit transparent GIFs. GIF alpha is **1-bit**, so edges go hard — fine for chat/forum/Notion sticker surfaces, worse than PNG/WebP/WebM for compositing on a timeline. Prefer PNG/WebP/WebM unless the destination only eats GIF.
214
+
172
215
  **Explainer house style — the defaults to build with unless told otherwise.** **White background / light mode** (plain white stage, no gradients, no dark mode, no photo backdrop), **kinetic word-by-word captions** in dark ink on the light stage (`vidfarm captions generate --style word-pop --color "#111111" --active-color "#7C3AED" --background-style plain` — skip outlines/shadows, they're only needed over busy footage), and **female TTS narration** (`vidfarm tts --voice coral` on OpenAI — `nova` for energy, `sage` for calm; `Kore`/`Leda` on Gemini; any ElevenLabs voice via `vidfarm voices`). **Keep it clean and simple** — one idea on screen at a time, two or three cutouts per beat, one accent color, one font, lots of white space; remove before you add. **Illustrations default to simplicity**: flat vector, simple shapes, minimal detail, 2–3 flat colors, no baked-in text — simple art keys cleanly, trims tight, and stays on-style across the whole cast. State the defaults once so the director can override any of them. Full detail: recipe `recipes/cutout-graphics-for-explainers.md` (“House style — the explainer defaults”).
173
216
 
217
+ **Landscape footage in a fullscreen vertical explainer — use the blurred plate, never bars.** When an explainer is built on **real filmed footage** and the source is 16:9 (or 4:3) on a 9:16 canvas, do not `contain` it (hard black letterbox bars read as an unfinished export) and do not blindly `cover` it (a wide shot loses its left and right thirds). Duplicate the clip: a full-canvas `cover` copy behind, heavily **gaussian-blurred and faded dark**, plus the sharp copy centered as a hero band — optionally zoomed ~1.3× — with its **top and bottom edges feathered** into the blur. Same clip, same timecode, so it reads as one continuous image with a shallow-depth-of-field plane, fullscreen edge to edge, nothing cropped, and clean dark space for the header and captions. Bake it once with ffmpeg into a single 1080×1920 file (free, local) and place it as one ordinary full-canvas layer — layer blur is not an editor property, so the pre-bake is the path that works in the editor, `serve`, and cloud render alike. Copy-paste ffmpeg + HTML recipes, tuning table, and the failure modes: `references/editor-workflows.md` (“The blurred plate — landscape footage, fullscreen, on a vertical canvas”).
218
+
174
219
  **Cost-saving move — mask illustrations OUT of a source image the director already has.** (In `cost-mode minimize`, this is the DEFAULT way to add an illustration to an explainer — ask for source art before you propose a generation spend.) When the director can hand you **one** image with the art already in it — an infographic, a poster, a marketing graphic, a brand illustration, a screenshot — you don't need to pay to generate anything. `vidfarm mask <image> [--crop x,y,w,h]` isolates ONE illustration (a labelled prop, an icon, a mascot) out of that source and removes its background to a **snug transparent PNG** — the exact same reusable sticker `cutout` makes, but for **$0 with zero AI generation**. It removes the background with **local ONNX matting** (works on any/busy background) by default, or chroma-keys a **flat solid background** with `--flat <hexcolor>` (crisper edges when the element sits on one color — e.g. the cream paper behind an infographic's icons). Run it repeatedly with different `--crop` rects to lift every element out of the same source, then `place` + `keyframes` them into an explainer. **Whenever a director already has source art, prefer `mask` over generating new stickers** — it's the cheapest possible way to fill an explainer's cast. Same recipe: `recipes/cutout-graphics-for-explainers.md` (“Mask from an image you already have”).
175
220
 
176
221
  **Free manual image-gen — custom art in `minimize` mode for $0, on someone else's tokens.** `mask` only works when the art already exists. When the video needs a **bespoke** graphic and cost mode is `minimize` (or the user said "no spend"), the answer is **not** "we can't" and **not** a silent billed `generate` — it's a **manual handoff**: you write the prompt, the user runs it in a **free** image generator, they hand the PNG back.
@@ -178,7 +223,7 @@ Present both harnesses to the director, recommend (A) unless they've asked for p
178
223
  - **Offer it once, up front, and let them set the default.** The first time custom art is needed in a cost-saving session, ask plainly: *"Want me to default to free manual image generation — I write the prompt, you paste it into a free tool and drop the image back — or would you rather I spend credits on `vidfarm generate` for these?"* Honor the answer for the rest of the session (and offer to remember it alongside the cost mode). Don't re-ask per image once they've chosen; just say "here's the next prompt."
179
224
  - **Free generators to name:** <https://meta.ai> (no cost, generous), free-tier **ChatGPT** (image gen included), or a free image **Hugging Face Space** (<https://huggingface.co/spaces> — search "flux" or "sdxl"). Any of them; the user picks whichever they're already signed into.
180
225
  - **Ask for ONE sheet, not N images — this is the token-efficiency trick.** Each round trip costs the user a manual step and costs you tokens re-reading a new file. So request **one image containing every graphic the scene needs**, laid out as a grid of separate objects on a **flat pure-green background** (`#00FF00`), well spaced, none overlapping or touching an edge. One generation, one hand-back, then you lift each element out locally for free.
181
- - **Then cut it up locally, for $0:** `vidfarm put-file ./sheet.png` to bring it in, then `vidfarm mask ./sheet.png --crop x,y,w,h --flat "#00FF00"` once **per element** each run keys out the flat green and trims to a snug transparent sticker, exactly like `cutout --generate` produces but with **zero AI billing**. `place` + `keyframes` them as usual. (`--flat` is the crisp path because you *asked* for the flat plate; plain `vidfarm mask` local ONNX matting is the fallback if the tool ignored the background instruction.)
226
+ - **Then cut it up locally, for $0 — in ONE command:** `vidfarm sticker-pack ./sheet.png --items "<object one>,<object two>,…" --out-dir ./stickers` keys the flat green out, finds every item in the sheet automatically, and writes one snug transparent sticker per item (named from `--items`) plus a manifest exactly like `cutout --generate` produces, with **zero AI billing**. `place` + `keyframes` them as usual. Add `--dry-run` first to check the detected boxes. Fallbacks: if two items came out joined, lower `--gap`; if the generator ignored the green-plate instruction, `vidfarm mask ./sheet.png --crop x,y,w,h` (local ONNX matting) grabs elements one at a time off any background.
182
227
  - **Prompt template — give the user this, filled in:**
183
228
 
184
229
  > A flat vector illustration sheet on a solid pure green background (#00FF00), no gradient, no shadow, no text, no labels. Arranged in a 3×2 grid with generous even spacing, each object fully separated and not touching any other object or the image edge: (1) `<object one>`, (2) `<object two>`, (3) `<object three>`, … Simple flat shapes, 2–3 flat colors, minimal detail, consistent style and line weight across all objects, front-facing, centered in its own cell. Square image, high resolution.
@@ -223,7 +268,13 @@ You may be running as the **in-web AI chat** (the /editor copilot, the chat dock
223
268
 
224
269
  - **Determine the surface before claiming capabilities.** The web chat has only its declared tools and REST routes. It cannot execute arbitrary JavaScript/Python, open a shell, create a local repository script, or use the user's filesystem. Never tell a web-chat user that you ran code or wrote a script unless a dedicated declared tool actually did so. A desktop coding agent has a real shell and filesystem and MAY write/run scripts, perform arbitrary local computations over paginated API results, create reports/CSVs/JSON, edit composition files, and orchestrate long devcli workflows within the user's authorization.
225
270
  - **The web AI chat can do all three paintbrushes** — clip raws, author HTML/hyperframe motion, and generate AI media — and it drives edits directly on the live timeline. Keep small-to-medium jobs here: text/caption swaps, a scene or two replaced, single generations, captions, approve/schedule. Just do them.
226
- - **Every production adheres to the TikTok-native caption standard.** On-screen text lives inside the readable safe zone (**~8%–85%** of a 9:16 frame never pinned to the top/bottom edges the phone UI clips) and uses the composition's bold font regime (**Montserrat** default / TikTok Sans, weight ≥700). Decomposed forks often inherit the source's edge-pinned caption in an off-regime font fix it, don't inherit it. Local devcli renders auto-normalize this, but author it correctly so the editor preview matches. Full rules in `references/editor-workflows.md` ("TikTok-native caption standard").
271
+ - **No HTML slop a video is not a web page.** Compositions are authored in HTML, so the #1 tell of an AI-edited video is landing-page furniture: gradient CTA "buttons" ("Sign Up for a Free Trial →"), rows of benefit chips/badges ("✓ No Credit Card Needed"), frosted/bordered cards holding a gradient headline + a URL, feature grids, bullet lists, web-default type (Inter/Roboto/Arial at weight 400-600). None of that exists in a real TikTok/Reel — **nothing in a video is clickable**. If you are typing `btn` / `badge` / `chip` / `card` / `rounded-full` / `shadow-lg` / `backdrop-blur` / `bg-gradient-to-r`, stop and rewrite it as timed text on the footage. Arrows, scribble/underline marks, italics, ALL-CAPS, single-word color pops, emoji, transparent cut-out stickers, and mock social UI (iMessage bubbles, comment cards) are all *fine* — they're native to the platform.
272
+ - **Every video gets the four charges — hook, loop, payoff, bait — and you write them BEFORE you touch the timeline.** This is the largest quality delta in the product and it costs nothing: most agent-made videos fail on structure, not polish, because the timeline is the fun part so it gets built first and the words get retrofitted. Invert it: (1) write the **hook line as text** — a complete clause, subject + verb, no jargon, naming a **situation** ("I've quit six businesses"), never a label ("anonymity") — and put it on screen at `start:0`; (2) name the **curiosity loop** and the timestamp it closes at, *inside this video* (if you can't state the timestamp, there is no loop, and the withheld answer must be one the viewer **can't guess**); (3) name the **payoff** — shown, not summarized, landing before the final beat; (4) write the **bait** — one ask in the final beat and in the post caption. Then build. Chunk 1 is read before any audio (muted autoplay is the default), so the text hook does more work than the spoken one. Full harness — the three gates, banned openers, loop mechanics, compliance, and diagnosis-by-charge — in `references/hooks-and-virality.md`; the checkable form is `vidfarm regime show hooks`.
273
+ - **The first frame IS the thumbnail — compose it on purpose.** Frame 0 is a single frame of ~30 in the first second, but it's the poster every feed, share link, and paused player freezes on, so **more people see that one frame than watch the video**. It must never be black, empty, mid-fade, or caught mid-animation: put a real visual at `start:0`, have the hook words already on screen at t=0, and never hang a `fade-black`/`fade-white`/`flash` *entrance* on the **first** clip (junction transitions between later clips are fine — this rule is only about the opening). Verify it, don't assume: devcli `vidfarm stills ./work --at 0` renders that exact frame, and `vidfarm qa` flags a blank or fading open.
274
+ - **Ask early: one-time video, or bulk?** "Make me a video about X" and "I need to post daily / give me 20 hook variants" are different jobs, and directors often don't know the second one has a name. Ask once, up front: *"One video, or should we set this up as a repeatable batch?"* Bulk = **scripting mode** (a pinned base fork + a loop that varies ONE thing per variant; a public-raws shelf is the cheapest source of the N), and every batch gets a **`QA_REGIME.md`** — because a loop of fifty videos has no human looking at every frame, and the regime is what replaces those eyes. Don't silently ship a one-off when they asked for volume, or drag someone into a harness when they wanted one clip.
275
+ - **`QA_REGIME.md` is the director's own quality contract, and it's a first-class artifact.** `vidfarm qa`'s built-ins are universal (slop, fonts, the thumbnail frame); a regime is what makes *this* format good — audience, hook shape, banned vocabulary, pacing, compliance line. It lives next to the work, they own it, it stacks: `vidfarm regime init short-form --out ./work/QA_REGIME.md` (bundled bases: `short-form`, `hooks`, `ugc-testimonial`, `explainer`, `product-demo` — each a starting point to **edit**, never a house style), then `vidfarm qa ./work --regime hooks --regime ./brand/HOUSE.md`, and any user file anywhere is valid. Its `checks:` front matter is machine-settled; its `- [ ]` checklist comes back as **review items you answer honestly in your report** — never claim a video passed the half the CLI can't judge. When a batch teaches you something, **write it back into the regime**: that's the artifact that compounds. Details in `references/automation-and-local-dev.md` ("Scripting mode"), format in `regimes/README.md`.
276
+ - **On devcli, QA every video you produce: `vidfarm qa ./work`.** Free, instant, local-only — it blocklists exactly the slop above plus first-frame/thumbnail and font-regime/safe-zone drift, and prints a concrete fix per finding. **Feedback, not a gate**: it exits 0 even on findings, never runs automatically, and is a blocklist (unusual/stylized compositions pass untouched), so there's no reason not to run it before every publish. `--json` for scripted batches, `--strict` only if you want a CI failure. **Web-chat copilot: this command does not exist for you** (devcli-only, no REST twin) — apply the standard by hand, and when handing a heavy job to a local coding agent, tell them to run `vidfarm qa`.
277
+ - **Every production adheres to the TikTok-native caption standard.** On-screen text lives inside the readable safe zone (**~8%–85%** of a 9:16 frame — never pinned to the top/bottom edges the phone UI clips), uses the composition's bold font regime (**Montserrat** default / TikTok Sans, weight **700–900**, ~36–64px on a 1080-wide frame), and uses **exactly one of four valid backgrounds**: outline/stroke (`background_style:"outline"`, the default), plain + shadow (`"plain"`), an active-word highlight pill (`set_captions` `spotlight`/`karaoke` — the only legitimate pill), or a tight-hugging solid band (`"highlight-solid"`, radius ≤8px, no border/shadow/gradient/blur). Decomposed forks often inherit the source's edge-pinned caption in an off-regime font — fix it, don't inherit it. Local devcli renders auto-normalize position + font family only (never the slop), so author it correctly. Full rules in `references/editor-workflows.md` ("Social-native visual standard" + "TikTok-native caption standard").
227
278
  - **Where the web chat struggles: complex, long, multi-step transformations.** A full multi-scene re-theme, an iterative render-critique-iterate loop, heavy scripted or batch work, or anything needing a real filesystem and many sequential tool calls will hit context limits, turn/timeout ceilings, and the web editor's constraints (CSS/declarative motion only — JS animation adapters are stripped on save). Don't grind a big transformation one layer at a time in a chat turn and stall.
228
279
  - **Practical workaround — hand the heavy job to local devcli.** When a task is genuinely large or long-running, **proactively recommend the director run it locally with an AI coding agent** (Claude Code / OpenAI Codex / any capable agent): `vidfarm pull <forkId>` writes the composition + the `.harness/` grounding bundle to disk, the agent edits with the full devcli verb set and JS animation adapters, renders free with `vidfarm serve`, and `vidfarm publish` pushes it back. This is the **best-quality (B) harness's** natural home (adversarial grading with a coding agent). Frame it as "this is a big rebuild — you'll get a better, faster result running it locally with a coding agent; here's how," not as a dead end.
229
280
  - **Offer a handoff, do not impersonate the desktop agent.** When web chat reaches that boundary, offer to save a Markdown handoff in My Files containing the objective, selected template/fork IDs, asset paths, grounding, constraints, completed work, and suggested devcli commands. Create it only after the user agrees. The desktop agent should read that document, pull the referenced fork, and then use its actual code/shell capabilities.
@@ -237,8 +288,10 @@ Read only the relevant reference file for the current task.
237
288
  - Timeline editing, decompose, captions, motion, AI placement: `references/editor-workflows.md`
238
289
  - Raws hunts, My Files, recurring characters, asset retrieval: `references/assets-and-sourcing.md`
239
290
  - REST automation, `vidfarm` command surface, local serve loop, skill packs: `references/automation-and-local-dev.md`
240
- - Getting-started interviews, strategy docs, onboarding flow: `references/onboarding.md`
291
+ - Getting-started interviews, **consultations**, strategy docs, onboarding flow: `references/onboarding.md`
241
292
  - Primitive routes such as TTS, STT, music, overlays, background removal, product placement: `references/primitives.md`
293
+ - **Hooks, retention, and why a video travels — the four charges: `references/hooks-and-virality.md`.** Read it before writing ANY hook, caption script, or re-theme, and before a hook-variant batch. It is the craft harness; the rest of the skill is mechanics.
294
+ - Bulk / N-variant production: recipe `recipes/bulk-scripting-with-a-regime.md`; the `QA_REGIME.md` format and the bundled bases: `regimes/README.md` (+ the regime files beside it, readable as-is)
242
295
  - Complete REST API map and raw-HTTP conventions: `references/rest-api.md`. Load it only when the user asks for REST, an endpoint/schema, direct HTTP integration, or exhaustive API coverage. For the entire specification, follow its domain links and load every listed reference; do not preload them into ordinary director conversations.
243
296
 
244
297
  ## HyperFrames Skills — Load on Demand
@@ -259,7 +312,7 @@ HyperFrames authoring and rendering in this package are Vidfarm-native: local wo
259
312
 
260
313
  Choose the narrowest path that satisfies the request.
261
314
 
262
- 1. If the user needs help figuring out what to make, read `references/onboarding.md` first.
315
+ 1. If the user needs help figuring out what to make, **or asks for a "consultation"** (the `brainstorm/*` chain: cold-start interview → awareness stages → angles → hooks), read `references/onboarding.md` first.
263
316
  2. If the user already knows the goal and needs a suitable template, read `references/core-workflows.md` and use the template discovery flow.
264
317
  3. If the task is “change this video,” read `references/editor-workflows.md`.
265
318
  4. If the task is “find footage” or “use our existing assets,” read `references/assets-and-sourcing.md`.
@@ -0,0 +1,65 @@
1
+ ## Recipe: Bulk Video Generation (Scripting Mode) with a QA_REGIME.md
2
+
3
+ Use this when the director wants **volume** — daily posting, hook tests, one video per clip in a pool, N variants of a template. Ask first if you're not sure: *"One video, or should we set this up as a repeatable batch?"* If they want volume, this is the shape.
4
+
5
+ The thing that makes bulk work is not the loop — loops are easy. It's that **nobody is going to watch variant #37 as carefully as variant #1**, so the standard has to be written down before the loop runs. That's the `QA_REGIME.md`.
6
+
7
+ ### 0. Read the craft harness first
8
+
9
+ `references/hooks-and-virality.md` — the four charges (hook / loop / payoff / bait), the three gates, and the anti-patterns that only bite at volume. Two of them decide whether this batch is worth running at all: **a different noun is not a different hook** (twenty variants of one sentence with the nouns swapped is one video), and **never point a generator at your grader** (a model writing hooks scored by the same model converges on the rubric, not on what works — scores climb, nothing improves). The regime catches defects; it does not rank winners.
10
+
11
+ ### 1. Agree the variant axis — before any code
12
+
13
+ One thing changes per variant; everything else is held constant. Hook line, opening clip, opening pain, avatar — pick one and say so out loud. A batch where several things changed at once teaches the director nothing, which defeats the point of running a batch instead of making one good video. **The cluster is the unit, not the video**: one attribution `tracer` per cluster, so a bad audience can't be mistaken for a bad hook.
14
+
15
+ ### 2. Pin the base
16
+
17
+ ```bash
18
+ vidfarm pull <forkId> --dir ./work # one canonical base fork per batch
19
+ ```
20
+
21
+ Read `./work/.harness/agent-guide.md` first, as always.
22
+
23
+ ### 3. Install and EDIT the regime
24
+
25
+ ```bash
26
+ vidfarm regime list # short-form | hooks | ugc-testimonial | explainer | product-demo
27
+ vidfarm regime init hooks --out ./work/QA_REGIME.md
28
+ ```
29
+
30
+ Then **edit it with the director**. The bundled file is a starting point; the parts that matter are the ones they add — who the viewer is, their banned vocabulary, the compliance line, the pacing this account actually uses. A regime nobody edited isn't about their videos. Existing regime somewhere else on disk? Just point at it: `--regime ./brand/HOUSE_RULES.md`. They stack.
31
+
32
+ ### 4. Source the N cheaply
33
+
34
+ ```bash
35
+ vidfarm public-raws --categories --json # live shelf vocabulary
36
+ vidfarm public-raws --category scroll-stoppers --limit 20 --json > pool.json
37
+ ```
38
+
39
+ A curated shelf is a pre-tagged, free, already-hosted clip pool — the cheapest way to get N distinct variants without N downloads or N generation calls.
40
+
41
+ ### 5. Loop: edit → QA against the regime → render
42
+
43
+ ```bash
44
+ for VARIANT in "${VARIANTS[@]}"; do
45
+ SLUG="$(echo "$VARIANT" | tr ' ' '-' | cut -c1-40)"
46
+ vidfarm set-text ./work --layer hook --text "$VARIANT"
47
+ vidfarm qa ./work --json > "qa/$SLUG.json" # ./work/QA_REGIME.md auto-discovered
48
+ jq -e '.ok' "qa/$SLUG.json" >/dev/null || { echo "skipped $SLUG"; continue; }
49
+ vidfarm render "$FORK_ID" --dir ./work --out "renders/$SLUG.mp4" --tracer "batch-$SLUG"
50
+ done
51
+ ```
52
+
53
+ `vidfarm qa` still exits 0 on findings — the `jq -e` line is **your** gate, in your script, made explicit. Keep it that way; a hard gate inside the tool would quietly train the loop to stop trying anything unusual.
54
+
55
+ ### 6. Answer the review items — don't skip this
56
+
57
+ The regime's `- [ ]` checklist comes back on every run because the CLI *can't* settle it. Machine checks catch a 13-word hook or a black first frame; only you can answer "is this variant genuinely different from its siblings?" or "can the viewer guess the withheld answer?" **Report both halves honestly**: what the machine checked, and what you judged. A batch report claiming a clean pass on the judgment half is worse than no report.
58
+
59
+ ### 7. Feed what you learn back into the regime
60
+
61
+ When the director says "the label-framed hooks all died" or "anything over 30s tanked", write it into `QA_REGIME.md` as a rule or a checklist line — with the reason attached, so the next agent doesn't argue it away. The compositions are disposable; **the regime is the artifact that compounds across batches.**
62
+
63
+ ### Cost note
64
+
65
+ Per-video AI spend multiplies by N. Bulk belongs in `minimize`/`hybrid` cost mode with reused assets: clip pools and HTML/CSS motion over a fixed asset set, not per-variant generation. Generate a reusable element once, then vary text and media around it.
@@ -22,11 +22,77 @@ The mechanical trio — **generate on a chroma plate → key it out → trim to
22
22
 
23
23
  **In cost-saving mode, don't generate illustrations at all — mask them out of images the director already has.** If `vidfarm cost-mode` is `minimize` (or the director says "without burning credits"), the default for adding an illustration is `vidfarm mask <their-image> --crop …` — lifting art out of an infographic, poster, deck slide, brand sheet, or screenshot for **$0 and zero AI calls**. Ask for source art before you ask for a generation budget; the guided loop is **"Mask from an image you already have"** below. **If no source art exists and the graphic must be custom, you still don't have to spend** — hand the director a prompt for a **free** image generator (meta.ai / free ChatGPT / a Hugging Face Space) and cut the returned sheet into stickers locally: **"Free manual image-gen"** below.
24
24
 
25
+ ### "A sticker pack" — what it means, and the one command for it
26
+
27
+ **When a director asks for a sticker pack (or "a set of stickers", "a prop pack", "an icon set", "assets for this video"), that is a specific pipeline, not N separate cutouts:**
28
+
29
+ > **Generate ONE image containing every item, laid out on a flat greenscreen plate → key that plate out once → mask each item apart into its own transparent file.**
30
+
31
+ Do it that way every time, for two reasons: **cost** (one billed image job for the whole set instead of one per sticker) and, more importantly, **style consistency** — items drawn in the same image share line weight, palette, perspective and lighting, which N independent generations never do.
32
+
33
+ `vidfarm sticker-pack` is that entire loop in one command. It also does the part that used to be manual: **finding the items**. Instead of measuring a `--crop x,y,w,h` rect per item by eye, it segments the keyed sheet's **alpha channel** into connected islands of opaque pixels — one island per item — and cuts each one out, trimmed to its true bounding box.
34
+
35
+ ```
36
+ # Generate the sheet AND split it (one image job for the whole pack)
37
+ vidfarm sticker-pack --generate "cozy farm props, flat vector, 2-3 flat colors" \
38
+ --items "red barn,tractor,hay bale,sun,fence,rolling hills landscape" \
39
+ --out-dir ./stickers
40
+
41
+ # Or split a greenscreen sheet you already have — $0, no account
42
+ vidfarm sticker-pack ./sheet.png --items "barn,tractor,hay bale" --out-dir ./stickers
43
+
44
+ # Look before you cut: prints the detected boxes, writes nothing
45
+ vidfarm sticker-pack ./sheet.png --dry-run
46
+ ```
47
+
48
+ Out comes `./stickers/sticker-01-red-barn.png`, `sticker-02-tractor.png`, … each trimmed tight, plus **`stickers.json`** (name, file, pixel size, sheet crop, area share) so a later step — or another agent — can pick props by name without re-deriving anything.
49
+
50
+ **Knobs that matter:**
51
+
52
+ - `--items "a,b,c"` — the exact cast. It both steers the generation and **names the outputs** in reading order (top-to-bottom rows, left-to-right). `--count <n>` instead if you don't care what the items are.
53
+ - `--dry-run` — list the detected crop boxes and stop. Cheap sanity check before writing a dozen files.
54
+ - `--gap <pct>` (default 1.2) — how far apart two islands must be to count as separate items. **Two items came out as one sticker → lower it** (or ask for wider spacing on the sheet). **One item came out split in two → raise it** (its parts, e.g. a floating antenna or a dotted arrow, weren't bridged).
55
+ - `--min-area <pct>` (default 0.15) — drops key speckle. There is **no maximum** — see the size note below.
56
+ - `--preset`/`--key-color` — match the plate (default `#00FF00`). `--pad`, `--alpha-threshold`, `--output-format png|webp|gif`, `--prefix`, `--max-items`, `--keep-plate`/`--keep-sheet` behave like `cutout`'s.
57
+ - Stubborn item? Fall back to one hand-measured `vidfarm mask ./sheet.png --crop x,y,w,h --flat "#00FF00"` for that one; the rest of the pack still comes from `sticker-pack`.
58
+
59
+ **Pick a plate the ART doesn't use — this is the #1 way a pack comes out broken.** A chroma key removes exactly ONE color. A sticker pack of leaves, frogs, plants, money, or "eco" iconography on a GREEN plate keys holes straight through the artwork, and it looks like the cut failed when really the plate was wrong. The commands handle it two ways:
60
+
61
+ - **Generating?** `sticker-pack --generate` / `cutout --generate` read the subject text and move the plate off any hue it mentions — green (`#00FF00`) → magenta (`#FF00FF`) → blue (`#0047BB`) → black → white — then print which plate they chose and why. Say it back to the director when it moves: *"Your items are mostly green, so I generated them on a magenta plate."*
62
+ - **Splitting a sheet you already have?** The plate is **detected from the sheet's four corners** (a sticker sheet always has plate in the corners), so a red/purple/blue sheet handed back from a free web generator just works with no flags.
63
+
64
+ Override whenever you know better: `--key-color "#FF00FF"` or `--preset magenta` pins the plate (and turns the auto-pick off); `--no-auto-key` forces plain green. If a pack's palette collides with *every* standard plate — a rainbow icon set — split it across two sheets on two different plates rather than fighting `--tolerance`. And when a sticker is a *green* subject, never let the user generate it on green: the hand-off brief (`vidfarm handoff image`) already picks the plate for them and carries the matching `--key-color` into the follow-up command.
65
+
66
+ **Generation is the failure point, not the cutting.** The sheet prompt is auto-appended with the important instruction — *every item fully separated by clear plate-colored background, nothing touching or overlapping, wide margins, no text, no shadows, one consistent style* — because **touching items segment as one sticker**. If a pack comes back merged, re-run the generation asking for more spacing before you fight the `--gap` knob.
67
+
68
+ ### Stickers are not necessarily small — and they usually move
69
+
70
+ Two things directors assume that aren't true:
71
+
72
+ - **A sticker can be huge.** "Sticker" here means *a transparent element you can place, scale and animate independently* — nothing about size. A full-width **landscape, skyline, cityscape, room interior, or backdrop** is a perfectly good sticker, and belongs in the same sheet as the icons so it shares their style. `sticker-pack` has no maximum item size (only a speckle floor), so a background plate that covers 60% of the sheet cuts out just like a 3% icon does. Ask for the big pieces explicitly in `--items` (e.g. `"rolling hills landscape (wide)"`).
73
+ - **A sticker is normally animated, not pasted.** The default animation surface is the **canvas/HTML itself**: place the PNG as an image layer, then animate it with `vidfarm keyframes` presets — `pop-in`, `float`, `shake`, `grow`, `slide-in-left`, `drift` — or raw keyframe stops. That's CSS/declarative motion, deterministic, free, and identical in preview and final render, and it's what gives an explainer its life. Layer moves for realism: a callout that `pop-in`s and then `float`s idle; an arrow that `slide-in-left`s and then `shake`s at its target. Full vocabulary: `references/editor-workflows.md` → "Cutout graphics for explainers".
74
+ - **When the sticker's OWN artwork moves** (a waving mascot, a spinning coin, a looping animation), it isn't a still at all — there's no single bounding box to trim to. Key it as a clip: `vidfarm remove-greenscreen <video>` → **transparent WebM** (browser- and editor-playable; a ProRes `.mov` alpha master is the local fallback when ffmpeg can't encode WebM alpha, and `--cloud` always returns WebM).
75
+
76
+ **Transparent GIF stickers.** Some destinations only take GIF — chat apps, forums, Notion, older web overlays, sticker packs meant to be shared rather than rendered. Both paths can emit one:
77
+
78
+ ```
79
+ vidfarm sticker-pack ./sheet.png --output-format gif --out-dir ./stickers # still stickers as GIF
80
+ vidfarm remove-greenscreen ./mascot.mp4 --gif --gif-fps 12 --gif-width 480 # ANIMATED transparent GIF
81
+ ```
82
+
83
+ GIF alpha is **1-bit** — a pixel is fully opaque or fully gone, so antialiased edges go hard and semi-transparent shadows/glows disappear (`--gif-alpha <0..255>` moves where that line falls). That's the format, not the key. **For anything going onto a composition, prefer PNG/WebP (still) or transparent WebM (clip);** reach for GIF only when the destination demands it.
84
+
25
85
  ### The guided sequence (prompt harness)
26
86
 
27
- **Step 0 — Decide the cast of stickers.** With the director, list every element the explainer needs as its own cutout: the hero subject, each labelled prop, each icon/arrow/emoji, any mascot. Each becomes one transparent PNG. Stickers are reusable — generate once, reuse across scenes.
87
+ **Step 0 — Decide the cast of stickers.** With the director, list every element the explainer needs as its own cutout: the hero subject, each labelled prop, each icon/arrow/emoji, any mascot, any full-frame backdrop. Each becomes one transparent PNG. Stickers are reusable — generate once, reuse across scenes. **If the cast is more than two or three items, make it a PACK** (one sheet, split locally — see "A sticker pack" above) rather than N separate `cutout` calls.
88
+
89
+ **Step 1 — Make each cutout.** Four paths, cheapest first:
28
90
 
29
- **Step 1Make each cutout.** Three paths, cheapest first:
91
+ - **Cut a whole pack out of ONE sheet** (`vidfarm sticker-pack`) the default for a *set*, and the only path that keeps a cast on-style. See "A sticker pack" above.
92
+ ```
93
+ vidfarm sticker-pack --generate "<theme>, flat vector" --items "a,b,c,d" --out-dir ./stickers
94
+ vidfarm sticker-pack ./sheet.png --out-dir ./stickers # free, sheet you already have
95
+ ```
30
96
 
31
97
  - **Mask it out of a source image the director already has** (FREE, no account, no generation) — *the cheapest path, and the one to prefer whenever source art exists.* If the director hands you one image with the art already in it — an infographic, a poster, a marketing graphic, a brand illustration, a screenshot — lift each illustration straight out of it with `vidfarm mask`:
32
98
  ```
@@ -97,10 +163,12 @@ This is the biggest cost saver in the whole explainer workflow: **if the directo
97
163
 
98
164
  Everything here is **local and free** — crop, matte/key, and trim are all `ffmpeg` + the bundled ONNX engine. No wallet, no account, no generation call.
99
165
 
100
- ### Free manual image-gen (the $0 path when NO source art exists)
166
+ ### Free manual image-gen (the $0 path when NO source art exists — and the DEFAULT in interactive mode)
101
167
 
102
168
  `mask` needs art that already exists. When the explainer needs a **custom** graphic and the director is in `cost-mode minimize` (or just said "don't spend"), there's still a $0 path: **you write the prompt, the director runs it in a free image generator, they hand the image back, you cut it up locally.** The AI spend moves to a free third-party tool; Vidfarm's wallet is never touched.
103
169
 
170
+ **This is what `vidfarm mode interactive` means in practice** — and `vidfarm handoff image --theme "<what>" --items "a,b,c"` mints the whole brief for you (the prompt, the numbered steps, the free tools, the plate color, and the follow-up `sticker-pack` command with the matching `--key-color`). Don't hand-write these packets; print the brief.
171
+
104
172
  **Offer it once, then make it the default.** The first time custom art comes up in a cost-saving session, ask: *"Want me to default to free manual image generation — I write the prompt, you paste it into a free tool and drop the PNG back — or should I spend credits on `vidfarm generate`?"* Whatever they pick, hold it for the session (and offer to remember it next to the cost mode). After that, don't re-ask per graphic — just hand over the next prompt.
105
173
 
106
174
  **Free generators to name:** <https://meta.ai>, free-tier **ChatGPT**, or a free image **Hugging Face Space** (<https://huggingface.co/spaces>, search "flux" / "sdxl"). Let the director use whichever they're already logged into.
@@ -115,12 +183,15 @@ Everything here is **local and free** — crop, matte/key, and trim are all `ffm
115
183
 
116
184
  **No text in the image, ever** — rendered text never keys or scales cleanly; add copy as a caption or HTML layer instead.
117
185
  3. **Bring the sheet in:** `vidfarm put-file ./sheet.png` (or drag into **My Files** in the web app).
118
- 4. **Split it into stickers — one `mask` per element, all free:**
186
+ 4. **Split it into stickers — one command, all free:**
187
+ ```
188
+ vidfarm sticker-pack ./sheet.png --items "<object one>,<object two>,…" --out-dir ./stickers
189
+ ```
190
+ It keys the flat green, finds each object in the alpha channel, and writes one trimmed transparent sticker per object (named from `--items`) plus `stickers.json`. Run it with `--dry-run` first to check the boxes. Two objects merged into one? The generator drew them too close — lower `--gap`, or grab that pair by hand:
119
191
  ```
120
- vidfarm mask ./sheet.png --crop 4%,4%,29%,45% --flat "#00FF00" --out prop-a.png
121
- vidfarm mask ./sheet.png --crop 36%,4%,29%,45% --flat "#00FF00" --out prop-b.png
192
+ vidfarm mask ./sheet.png --crop 4%,4%,29%,45% --flat "#00FF00" --out prop-a.png
122
193
  ```
123
- `--flat "#00FF00"` is the crisp path precisely because you *asked* for the flat green plate. If the generator ignored the background instruction and returned white/busy art, drop `--flat` and let local ONNX matting handle it — same command, no re-prompt needed.
194
+ If the generator ignored the background instruction and returned white/busy art, `vidfarm mask` **without** `--flat` falls back to local ONNX matting — same command, no re-prompt needed.
124
195
  5. **Stage, animate, render** exactly as in Steps 3–5 above. A manually-generated sticker is indistinguishable from a `cutout --generate` one on the timeline.
125
196
 
126
197
  **Grid sizing note:** a 3×2 grid on a square image puts each cell at roughly `33%` wide × `50%` tall; start crops a couple of percent inside the cell and use `--keep-region` on the first run to verify before masking the rest.
@@ -6,9 +6,10 @@ Use this when a coding agent is doing the work locally or the user wants a repro
6
6
  2. Run `vidfarm pull <forkId> --dir ./work`.
7
7
  3. Read `./work/.harness/agent-guide.md` and `./work/.harness/context.json` before editing.
8
8
  4. Make deterministic edits to `composition.html` and optionally `composition.json`.
9
- 5. Validate with `vidfarm lint` or `vidfarm stills` when useful.
10
- 6. Render with `vidfarm render <forkId> --dir ./work --wait`.
11
- 7. Approve the finished MP4 with `vidfarm approve --video <url|./final.mp4> --caption "..."`. This prints the shareable `share_url`.
9
+ 5. Validate with `vidfarm lint` or `vidfarm stills` when useful. **Always look at `vidfarm stills ./work --at 0`** — that frame becomes the thumbnail, so it must not be black, empty, or mid-fade.
10
+ 6. **QA before you render: `vidfarm qa ./work`.** Free, instant, devcli-only. It blocklists HTML slop (CTA buttons, benefit chip rows, frosted cards, gradient text, web-page classes/fonts), checks the caption font regime + safe zone, and flags a blank/fading first frame (the thumbnail). Feedback only — exit 0 even on findings, never automatic — but it catches the #1 tell of an agent-made video, so run it on every production. Fix what's real, ignore what's a deliberate style call, then render.
11
+ 7. Render with `vidfarm render <forkId> --dir ./work --wait`.
12
+ 8. Approve the finished MP4 with `vidfarm approve --video <url|./final.mp4> --caption "..."`. This prints the shareable `share_url`.
12
13
 
13
14
  **Approving a locally rendered file → cloud preview link.** Approve takes media by **URL**, not bytes, and an approved post is **permanent** — so the local MP4 must land in **durable My Files**, not the 30-day temp store (a temp video would 404 the share page after 30 days). The devcli presigns, PUTs the bytes **direct to S3**, finalizes, then approves with that durable URL — so `vidfarm approve --video ./final.mp4` handles files up to **200 MB**, bypasses the ~6 MB Lambda request-body limit, and the share link never breaks. By raw REST: `POST /api/v1/user/me/attachments/presign` → PUT to the returned S3 URL → `POST /api/v1/user/me/attachments` (finalize) → pass the returned `viewUrl` in the approve `media` array. Do not multipart-POST a big file to `.../attachments/upload` against the cloud host (Lambda-bound, ~6 MB cap). Add `vidfarm approve --temp` only when you want a disposable 30-day preview.
14
15
 
@@ -5,7 +5,7 @@ Use this when the user wants to keep the format’s feel but replace the subject
5
5
  1. Read `references/editor-workflows.md`.
6
6
  2. Fetch `video-context.json` and `editor-harness.json` first.
7
7
  3. State the plan in the three axes vocabulary: scenes, audio, text; SWAP vs REPLACE for each.
8
- 4. Preserve the hook structure, cut rhythm, emotional punch, and important scenes flagged by the harness.
8
+ 4. Preserve the hook structure, cut rhythm, emotional punch, and important scenes flagged by the harness. **Read `references/hooks-and-virality.md` before rewriting the opening line or the retention beat** — `viral_dna.hook`/`retention`/`payoff` name the source's four charges, and rebuilding each one for the new subject (rather than flattening the loop into a product statement) is the whole job.
9
9
  5. Source footage in this order:
10
10
  - My Files or existing raws
11
11
  - a raws hunt from a long-form source
@@ -94,11 +94,11 @@ Local scans persist to a SQLite library under `~/.vidfarm` (free compute, subscr
94
94
 
95
95
  ## My Files (the user's asset library)
96
96
 
97
- Each user has a persistent **My Files** filesystem — their own uploaded videos (mp4/mov/webm), images (png/jpg/jpeg/gif/webp/svg), audio (mp3/wav/m4a/aac), and documents (pdf/md/txt/csv) — organized into **virtual folders**. This is where a user keeps footage, brand assets, logos, music, briefs, scripts, and the durable strategy docs from Getting Started (About.md, awareness-levels.md, etc.). Both the editor AI copilot and an agent CLI can **read and write** it to find or save assets instead of asking the user to re-upload or paste URLs.
97
+ Each user has a persistent **My Files** filesystem — their own uploaded videos (mp4/mov/webm), images (png/jpg/jpeg/gif/webp/svg), audio (mp3/wav/m4a/aac), and documents (pdf/md/txt/csv) — organized into **virtual folders**. This is where a user keeps footage, brand assets, logos, music, briefs, scripts, and the durable strategy docs from Getting Started / a consultation (OFFER.md, awareness-levels.md, etc.). Both the editor AI copilot and an agent CLI can **read and write** it to find or save assets instead of asking the user to re-upload or paste URLs.
98
98
 
99
99
  - **List** — `GET /api/v1/user/me/attachments` → `{ attachments: [{ id, fileName, contentType, sizeBytes, folderPath, viewUrl, createdAt }], folders: [string] }`. The `viewUrl` is a durable URL you can drop into a composition layer or pass into a primitive route. devcli: `vidfarm files [--folder <path>]`.
100
100
  - **Read one** — resolve it from the list and stream/read its `viewUrl`. devcli: `vidfarm get-file <id> [dest]` (add `--print` to print text contents of md/txt/csv/json inline). For images/video/audio/pdf, reference the `viewUrl` as media — you can't read their bytes as text.
101
- - **Write into My Files** — `POST /api/v1/user/me/attachments/upload` (multipart `file` + optional `folder_path`) persists a file into the library. devcli: `vidfarm put-file <localFile> --folder <path>`, or pipe/inline text without a temp file: `echo "…" | vidfarm put-file --stdin --as About.md --folder acme` / `vidfarm put-file --content "…" --as About.md`. This is how an agent saves Getting Started context (About.md, Interview.md, awareness-levels.md, persuasive-angles.md, ad-hooks.md) or drops a logo/product demo into a namescoped folder. In the web editor copilot the same capability is the **`browse_files` write action** (`action=write` with `file_name` + `content` + optional `folder_path`), which accepts text files (md/txt/csv/json/srt/vtt).
101
+ - **Write into My Files** — `POST /api/v1/user/me/attachments/upload` (multipart `file` + optional `folder_path`) persists a file into the library. devcli: `vidfarm put-file <localFile> --folder <path>`, or pipe/inline text without a temp file: `echo "…" | vidfarm put-file --stdin --as OFFER.md --folder acme` / `vidfarm put-file --content "…" --as OFFER.md`. This is how an agent saves Getting Started / consultation context (OFFER.md — or OFFER_<NAME>.md for a multi-offer director — plus awareness-levels.md, persuasive-angles.md, ad-hooks.md) or drops a logo/product demo into a namescoped folder. In the web editor copilot the same capability is the **`browse_files` write action** (`action=write` with `file_name` + `content` + optional `folder_path`), which accepts text files (md/txt/csv/json/srt/vtt).
102
102
  - **`vidfarm upload` is different** — it targets the **ephemeral** temporary-files store (`POST /api/v1/user/me/temporary-files/upload`) for a throwaway durable URL to drop straight into a composition or approved post. Use `put-file` when you want the asset to persist in the user's My Files library; use `upload` for one-shot media you just need a URL for. Namescope scratch uploads under a **`temp/` folder** (`vidfarm upload clip.mp4 --folder temp`) so they stay in one purgeable place. Better still, if you're on a `vidfarm serve` box, skip the upload entirely and reference the file off disk with `place --src ./clip.mp4` (see "Local file paths as media").
103
103
 
104
104
  ### Metadata notes + vector search (find assets by meaning)
@@ -163,4 +163,4 @@ The web copilot exposes the same three as `browse_files action=rename|move|copy`
163
163
 
164
164
  **Assume My Files is multi-offer.** A user often runs more than one product, offer, brand, or region, and namescopes assets into folders accordingly — by product (`acme-skincare/`, `zensleep/`), by offer/campaign (`summer-sale/`), by region (`us/`, `eu/`), by asset type (`logos/`, `ugc-clips/`), or any arbitrary scheme. There is **no fixed layout** — read the `folders` tree first and reason about how this user organized things. Before pulling assets for a task, infer which folder(s) match the product/offer/region the current composition is about (match folder names to the composition title, video context, and what the user said), then scope reads to that folder so you never mix one brand's logo/product-shot/music into another brand's video. If the target offer is ambiguous, ask which product/offer/region (or which folder) this work is for rather than guessing across offers.
165
165
 
166
- In the editor web copilot the same filesystem is exposed via the **`browse_files` tool** (`action=list` / `action=search` / `action=read` / `action=write` / `action=annotate` / `action=move` / `action=copy` / `action=rename`), so the copilot follows the identical reasoning: search or list to find the right offer's folder, then read an asset — or `write` a text doc (About.md, awareness-levels.md, …) or import a media URL (`source_url`) into that folder, annotating anything worth finding again. `action=rename`/`move`/`copy` reorganize the tree (see the three routes above) — use them to keep character folders and asset names tidy. `browse_files list` defaults to `path='/'` when `path` is omitted, so the `/raws` (hunted raws) and `/temp` (scratch) roots surface alongside the My Files folders instead of being hidden; a `/raws` listing also accepts a `content_type` filter (exact shot-kind — `talking_head`, `b_roll`, `product_shot`, `screen_recording`, …), and every listing paginates via `offset` / `limit`. The devcli equivalents are `vidfarm files [--search]` / `get-file` / `put-file [--notes]` / `annotate-file` / `directory rename|move|copy`.
166
+ In the editor web copilot the same filesystem is exposed via the **`browse_files` tool** (`action=list` / `action=search` / `action=read` / `action=write` / `action=annotate` / `action=move` / `action=copy` / `action=rename`), so the copilot follows the identical reasoning: search or list to find the right offer's folder, then read an asset — or `write` a text doc (OFFER.md, awareness-levels.md, …) or import a media URL (`source_url`) into that folder, annotating anything worth finding again. `action=rename`/`move`/`copy` reorganize the tree (see the three routes above) — use them to keep character folders and asset names tidy. `browse_files list` defaults to `path='/'` when `path` is omitted, so the `/raws` (hunted raws) and `/temp` (scratch) roots surface alongside the My Files folders instead of being hidden; a `/raws` listing also accepts a `content_type` filter (exact shot-kind — `talking_head`, `b_roll`, `product_shot`, `screen_recording`, …), and every listing paginates via `offset` / `limit`. The devcli equivalents are `vidfarm files [--search]` / `get-file` / `put-file [--notes]` / `annotate-file` / `directory rename|move|copy`.