Shot recreation brief
Give it one shot's clip, cut exactly from the source, and a sentence or two of
context. Gemini watches it at 24 fps with sound and returns an analysis: the
camera, the motion beats (a new beat every 0.2–0.5 s, with times), the
expression arc, other motion, timed sound effects, dialogue, music, and
recreation notes. You turn the analysis plus your direction into the brief a
video model gets. The brief's timing line matches the model's minimum length,
so the render acts in real time and trims to the shot. To get the dialogue and
cast of a whole video, use gemini-script-from-video.
Inputs
- The shot as its own clip at the source's frame rate (
ffmpeg-scene-cutsfor the boundaries). Its length and frame count fromffprobe-inspect-media. - Context: what the spot is, who's who (by what they wear), and what the shot is. Name the main character, so the beats use the name.
Run it
- Analyse. Send the clip, sampled at 24 fps and at high media resolution,
with the prompt in
references/prompt.md(duration, frame count and context filled in) to Gemini 3.1 Pro throughrun, asking for JSON in the schema there. Find its id withmodels("gemini")anddescribeit before the first run (earlier jobs usedgemini-3.1-pro-preview):
The clip is a local path; the engine uploads it. Save the answer asrun("<gemini id>", { "contents": [{"role": "user", "parts": [ {"fileData": {"mimeType": "video/mp4", "fileUri": "<shot>.mp4"}, "videoMetadata": {"fps": 24}}, {"text": "<the filled prompt>"}]}], "generationConfig": {"responseMimeType": "application/json", "responseSchema": <the schema in references/prompt.md>, "mediaResolution": "MEDIA_RESOLUTION_HIGH"}}, into="<shot folder>", unit="<shot>_analysis")<shot>_analysis.jsonnext to the clip. Shots are independent: start every shot's analysis withwait: false, thentasks(wait: true, calls: [...], until: "any"), and read each against its stills (step 2) as it lands. The gateway's Gemini adapter is being built in hn4a;describegives its exact fields. - Read it against the stills. Look at the shot's first and last frames next to the analysis, and note where it is wrong: sides, camera, sizes of movements.
- Write the brief with
references/brief.md. The timing line depends on the model's floor and on whether the last frame is pinned. Your direction replaces the analysis's camera, action, other motion or notes where they are wrong. Write the end state yourself. Save it asdirection/<shot>_<model>_<first_only|first_last>.txt.
What you get
<shot>_analysis.json and a readable version of it for the job's notes, then
one brief per model and pinning. Each brief is a set of plain-text lines: the
timing, camera, action, other motion, look, end state, dialogue or "Nobody
speaks.", sounds, "no music", and must-get-right.
Tips and traps
- Gemini sometimes mirrors frame-left and frame-right. Trust the stills. Your action direction overrides the beats where they disagree.
- It calls slow push-ins "locked off". When the camera moves, write the camera direction yourself. The brief then drops "locked off", "static" and "hazy" from the analysis's lens notes so the two don't contradict each other.
- Act in real time, then hold. Never speed up. A model whose floor is longer than the shot is told to play the action at natural speed and hold the final pose, and the render is trimmed to the shot. Spreading the action over the clip and speeding it up afterwards read badly. With a pinned last frame, the hold is on that frame.
- Spell out counts and sizes. "Blinks exactly once"; a sip "a third of the way, base below her chin"; "keep every movement exactly as small as described". Vague beats come back bigger.
- Sounds marked "added" (post-production effects) stay out of the brief, and so does music. Narration and score go back in at the edit.
- Dialogue in the analysis is for timing only. Lip-synced lines go through a dialogue or lip-sync route, not through this brief.
Check it
Every beat in the brief should be visible in the reference clip at roughly its
time, the end state should match the last still, and the timing line should
name the model's real render length. After rendering, check the take landed
where the brief said with python-check-pinned-frames.


