Watch a brand's own product footage (screen recording, product film), pick the moment that proves each line with the user, and render those picks as a product layer — free, local. survey.py turns footage into timestamped contact sheets + scene cuts + motion so the agent can actually look at it; the agent writes a cut list (beat → source window + framing); preview.py draws it as a review sheet the user corrects round by round; cut.py renders the approved list into a silent 1080x1920 layer with the creator's area left as a plate. Also frames footage as a filmed screen (keystone, bezel, handheld drift) with dissolves between beats, and takes still screenshots as sources. Use for any format that shows real product footage beside, between or instead of a creator (split-screen, screen inserts, walkthroughs).
npx gooseworks install --all # then, in Claude Code, Cursor, or Codex: /gooseworks use the footage-cutlist skill
Picking which moment of a customer's footage plays under which line is a judgement, not a formula. A position map ("beat 3 is 40% through the reel, so take the footage 40% through") was measured up to 5.7s off a person's picks on a reference build. So this capability does the free, mechanical parts and leaves the decision to the agent and the user:
| Step | Script | Who decides |
|---|---|---|
| Look at the footage | survey.py | nobody; it just shows it |
| Choose a window per line | the agent writes cutlist.json | agent, then the user |
| Show the choices | preview.py | the user corrects them |
| Render the approved choices | cut.py | nobody |
All free. ffmpeg + Pillow + numpy only.
python survey.py --video footage.mp4 --out work/survey # whole clip, ~1 frame/s
python survey.py --video footage.mp4 --out work/s-12 --from 12 --to 18 --every 0.25 --frames
python preview.py --cutlist work/cutlist.json --out work/review.png
python cut.py --cutlist work/cutlist.json --out work/layer.mp4 [--draft]survey.json lists cuts (scene changes), motion (change per second) and still
(runs of 1.5s+ with nothing moving: a dead screen reads as a frozen video). Read the
sheets; open a single frame-*.png (from --frames) when you need to read small UI text.
{
"size": [1080, 1920], "fps": 30, "seam": 768, "creator_side": "bottom", "bg": "auto",
"sources": {"demo": "footage/demo.mp4"},
"beats": [
{"id": "b1", "start": 0.0, "end": 3.1, "state": "creator", "vo": "..."},
{"id": "b2", "start": 3.1, "end": 7.4, "state": "split", "vo": "...",
"source": "demo", "in": 12.0, "fit": "width", "why": "the brand kit fills in at 13.4s"}
]
}state: creator (creator full frame), split (footage in the product zone, creator in
the other), product (footage full frame).in is where the window starts in the source; out defaults to in + slot (1.0x). A
window may play between 0.5x and 2x; it is never looped or frozen to fill a slot.fit: width (whole frame, letterboxed; the default), cover (fill + crop around
focus), crop (a source box [x0,y0,x1,y1] in fractions, then fit by width).bg: auto samples the footage's own corner colour so the letterbox and the footage read
as one surface; blur; or #rrggbb.look: "screen": frame the footage as a screen filmed at close range (thin bezel, dark
room, faint moire, grain, slow handheld drift). crop picks the source region,
screen: {rot, keystone, fill, fit, drift} the geometry, mask boxes are blurred in the
source (an email, a customer name). Inserts over a creator: keystone ~0.007,
rot within ±1°. Walkthroughs: keystone ~0.024, rot -1.5..0, fill ~0.80. Never
bigger angles and never alternate them between beats (read as a wonky camera).transition: {"dissolve_frames": 7} (top level): cross-dissolve every beat into the next.
A hard cut between two screens reads as an edit; 6-7 frames reads as the camera moving.look: "screen" so the drift keeps it alive.why: one line on what the window shows. It is printed on the review sheet so the user
can see the reasoning, and it makes the agent say what it saw.Beats must tile the timeline from 0 with no gaps. cut.py refuses a list that does not.
--every 0.25 and
look at every frame. A click, a page load or a half-typed field lives between the
samples, and it is exactly what a user then points out ("you didn't look at the video
properly").why.fit: width; use crop only to isolate a small
subject, and check the review sheet for cut-off text.still run reads as the video having stopped.
Start it where something moves, or shorten it.fit: width and let the room fill.mask it.cut.py warns when two beats overlap in the same source: it
reads as a loop.align_beats.py). Re-run preview.py + cut.py on the aligned list and look again.Expect several rounds. Each round:
review.png (and a --draft layer if they want to see motion).Picking is free, so take as many rounds as the user needs. Never spend on the creator until the user has approved the cut list.
state: creator (creator full frame), split (footage in the product zone, creator inin is where the window starts in the source; out defaults to in + slot (1.0x). Afit: width (whole frame, letterboxed; the default), cover (fill + crop aroundbg: auto samples the footage's own corner colour so the letterbox and the footage readlook: "screen": frame the footage as a screen filmed at close range (thin bezel, darkFull video production sequence with script review, actual ingredient choices, controlled generation, editing, evidence-based quality review, polish, captions and delivery. A host binding supplies project storage, authentic approvals, provider access and billing.
Build a vox-pop street interview video ad. An interviewer with a handheld mic asks passers-by one question about the brand's product, they give blunt wrong guesses, one gives the real answer, and the cut lands on a branded end card. Generates the takes through the GooseWorks fal proxy (Seedance 2.0 with native voice), then grades, re-cuts, captions and gates them locally. Use for the street-interview format.
Write the words of a short-form video ad (voiceover, dialogue, chat bubbles, on-screen lines) the way performance creative teams do instead of from a blank page. Builds the script from the buyers' own words, the beat sheet of an ad that already works and three deliberately different angles, filters them with a rule check and a second non-Claude model, and takes the strongest into the review with the other two as one-line swaps. Use it in every video ad run before any paid step, and whenever the user asks to write, rewrite or improve a video ad script or says a script sounds generic or AI-written.