← Files PicsartARCHIVED FILE
skills/film-scenes/SKILL.md
110 KB · Oct 10, 2026 · 18:02 UTC
---
name: film-scenes
description: "Generate the film's shots — the shooting period. Final per-scene shotlists, preset-driven shot design (camera moves, optics, two-source lighting, acting), every scene's pictures on one board (scene picture, wide, a room map when needed), the handbook's two-part prompt — one prompt per RUN of shots (as much of the film as fits a single generation, scenes included), the model making the cuts inside it — drafts, surgical iterations with a full log, the delivered run split back into its shots, and take selection into selects. Use for stage 6 of the film pipeline, only after the scenes' asset sheets are approved. Routed from the film skill."
---
# ChatGPT and Codex integration
Apply these host conventions throughout this skill and its references.
- Discover the connected Picsart tools and use their actual names and schemas.
The `picsart_*` names in the workflow identify tools, not a fixed host namespace.
If the connection is missing, explain that Picsart must be connected; continue
script and shot planning when possible. Never invent tool results or renders.
- Read board decisions from the current user message and attached widget context.
Use `read_widget_context` only if the host actually exposes that tool. Do not
assume ChatGPT has Claude's context reader. Treat a board's initial tool result
and unsent widget state as previews, never as user approval. If a submitted
decision has no accessible payload, explain briefly and use the text fallback
to collect the missing decision; do not guess or repeat charged operations.
- Use the host's available question interface or one concise conversational
question for preset choices.
- UI rendering and delivery of feedback are the remote MCP server's responsibility.
If a board is unavailable, present its relevant options in text and record the
user's selection using the same documented feedback fields. Do not claim that
a plugin manifest makes Claude-specific widgets compatible with ChatGPT.
- Save `film.json` and artifacts in the user's writable project workspace, not
the installed plugin directory. If persistent file tools are unavailable,
keep a structured project checkpoint in the conversation and provide it for
download when the host supports files. Never claim a file was saved without
confirmation from a file tool.
- Honor the user's current instructions and already authorized scope. Preserve
quoted spend limits and production locks; do not infer authorization from a
preview, a timeout, or a connection being installed. A timed-out charged call
needs a status check before considering a retry.
- This package holds six film skills (`film`, `film-development`, `film-assets`, `film-scenes`, `film-edit`, `film-finishing`) and three motion skills (`motion`, `motion-import`, `motion-design`). Route between them directly.
- `motion-import` reads a design's layers through the Figma app's tools. If Figma is not connected in this host, use its flat-frame fallback and say so once.
# Scenes — the shooting period
This is where the money goes, so it runs as a seven-step conveyor per scene, in
order, because each step is more expensive than the one before it. The gate behind
you is real: **no run generates until the assets of every scene it spans are
locked** (the matrix in `film`) — a run that crosses a production-block boundary
waits for both blocks, so where the film works block by block, the run pass cuts
runs at block boundaries. The gate ahead: every shot `final`, in selects, logged.
**Nothing charged in video goes out on a number the user has not seen and said
yes to (2026-09-07).** Reported from real sessions: runs dispatched with no
credit figure in front of the user at all. Video is the film's largest spend, so
every charged video call — the pilot run, the batch, a re-roll, an edit, an
extend, the final-resolution pass — happens in three steps in this order:
`picsart_preflight` (free) returns a number, the number goes to the user in one
line, and the dispatch **waits for their yes**. One quote per dispatch, never per
shot: a run of five shots is one number and one yes.
What does NOT count as that yes — the forecast below (a plan, not a purchase),
the shot list's approval (that is the list's yes, and its board figure prices
per-card generations, which a run is not), the sheets' lock, the yes that opened
this stage, and the yes that covered an earlier dispatch. **Express pace changes nothing here.** When
preflight cannot price the call, say so in the same line — the rate arithmetic,
named an estimate — and still wait; an unpriced call never reads as free. Record
the figure in `film.json`'s `credits.nextActionQuote` before the call, so the
yes has a number on record.
**Before the money phase, state the film's forecast once.** Convert the
shotlist into numbers before anything renders: runs × expected takes × each
run's `genSec` × the model's per-second rate, plus a regeneration buffer
(~20%), the edit passes you can foresee (one per risky stretch, at the edit
model's rate — quote it once), and the charged QC
frames (take QC, cut-point checks). **The
~25% keep rate practitioners quote is per-shot data and does not transfer**: a
run passes only when every cut in it passes, and nobody has measured that rate
on this pipeline yet — so plan two takes per run, say the number is a guess,
and correct it out loud after the first run lands. One honest range — "this
film will cost roughly X–Y credits" — before the first dispatch; track
actual-vs-forecast in `film.json`'s `credits` and say so when the pace will
blow it.
## The unit of generation is the run, not the shot (2026-09-03)
**Repair exception:** this section governs initial production, not permission
to replace accepted footage. A user-approved connecting insert between existing
clips may generate alone under `../film-edit/references/JOIN-REPAIR.md`. Preserve
both originals and verify both joins; do not merge the insert into their run and
re-roll it merely to satisfy the packing rule.
**Shots are authored one at a time and bought together.** Measured on this
pipeline's own material: a film generated shot by shot — one `picsart_generate`
per card, the takes cut together at the edit — loses to the same shots
generated as ONE multi-shot take with the cards written in as its cut list. The
loss is not subtle and it is not one thing: identity holds across the cuts
because the model never re-reads the descriptor from cold, the light and grade
are less likely to step at every join, voices face fewer independent generation
decisions, and the cuts *land* — a match on action that one generation authored
into both halves actually matches, where two independent renders only ever
approximated it. *(Owed beside this date when the experiment's notes are typed
up: the model, the shot count, the run length, and the axes it won on. The
finding stands; the numbers are still to be recorded.)*
So the **run** is the unit: **as much of the film as fits inside a single
generation at the model's live ceiling** (`picsart_model_params` — Seedance 2.5
goes to 30s), scenes included. A short that fits is ONE generation — garage
scene and street scene together; a film that does not is the fewest runs that
cover it, split where the last paragraph of this section says. A scene change
inside a run is a cut like any other: a shot block whose first frame is the new
place, with the new scene's geography line stated where its first shot is
(`references/PROMPT-BLOCKS.md`).
**“Fewest runs” is a quality rule, not merely a cost preference.** The measured
continuity advantage above increases with the amount of consecutive film the
model authors together. Therefore a payoff, climax, close-up, long hold,
different emotional beat, scene boundary, or a belief that a shot will “hold up
better alone” is **never** a reason to start another generation. Those facts
shape the shot header and its seconds; they do not shape the run boundary. A
partition is invalid if the same ordered shots can fit in fewer runs at the live
ceiling while keeping every necessary run edge valid. Before dispatch, merge
every adjacent pair of planned runs that fits as one generation; scene changes
inside the merged run remain ordinary internal cuts.
Nothing about *authoring* changes. The shot cards, the cut-by-cut pass,
sizes, who is in frame, the geography line, the silence after every line — all
of it is still written per shot; the user still sees short cards on
`picsart_shotlist_board` and still sets each one with the presets. What
changes is where it lands: one prompt per run in the handbook's two-part shape
— a setup once (the tagging header, the tone, the camera line, the cut list),
then one short block per shot that opens with its shot type and camera move
(`references/PROMPT-BLOCKS.md`, 2026-09-09).
**Everything travels as a reference image; the prompt says what each one is
for.** The `startFrame` *field* and reference media are exclusive (step 2), and
that field anchors exactly one frame — the first — while a run has many shots
that each need identity pixels. The way round it is solved (user-verified
2026-09-03): the run's call carries `imageUrls` only — the **views** of every
character and location the run uses *and* every approved still — in a fixed
order, and
**the tagging header gives each image its role in words**: a face and an
outfit (*"100% matched based exactly on IMAGE n"*), `START FRAME` (the run
opens on exactly this image), `FRAME REFERENCE for shot N` (that shot opens on
this framing), `SPACE` (the wide, the map). The model honours the role it is
told; after the header, names only. That is the anchoring a run gets — identity
pixels for every character in every shot, *and* a photographed first frame for
any cut that has one. A character the user supplied as a **photograph** goes
first and untouched — *"Cal face 100% matched based exactly on IMAGE 1 — a
photograph of the real person"* — with one view of its generated angle sheet, when one
exists, second as *wardrobe and angles, face from IMAGE 1* (`film-assets`, *When
the user brings the asset*).
**One image, one thing — never a multi-panel sheet (2026-09-07).** Every entry
in `imageUrls` shows exactly one view of exactly one asset. An asset's sheet is
cut into single-view files at lock, and those are what a run carries; the sheet
itself stays in the library as the approved archive. This is not tidiness: a
four-panel reference of one woman at four ages, with the references header correctly naming
*"the adult-formalwear panel"*, gave sc04a the wrong Alina — and the identical
prompt gave sc04b a *different* wrong Alina, plus one frame that blended two
panels into a face not in the cast. Each generation is an independent draw
against the same ambiguity, so it fails differently every time, never appears in
a prompt diff, and holds *within* a run while moving *between* runs. Panel
labels rendered into the sheet's own pixels did not fix it either. **There is no
fallback pointer**: a prompt naming a panel or a position is a dispatch error
(the lint in step 2). And every run that needs a state passes the **same view
file**, so identity rests on byte-identical input rather than on a guess
repeating. The method and the crop recipe are in
`../film-assets/references/ASSET-SHEETS.md`, *How an asset reaches the run*.
**What you are accepting, stated once so nobody rediscovers it mid-film:**
- **A repair is an edit or an extend before it is ever a re-roll (2026-09-04).**
The model ships two siblings for exactly this, recorded at the pick as
`shoot.editModel` and `shoot.extendModel` (never a version named here —
2026-09-10): the **edit** sibling
changes something *inside* a clip (the clip + the change in words + the same
numbered references → the same clip, changed), and the **extend** sibling
makes a clip *longer* (the clip + what happens next → the clip continued).
The note's *meaning*, read against what was selected on the board, routes
the call (step 5): a note about how the marked stretch plays → the edit
model; a note asking for something that has not happened yet in the clip →
the extend model; only "regenerate / redo", or a note about the whole run →
a fresh roll. A clip selected with the note "expand" is an extend call, never
a regeneration — that mistake was made and reported. Both siblings are
candidates, not measured methods: the first of each is a test, judged in the
cut in the scene editor, and a clip that will not take an edit in two tries
is re-rolled.
- **Handles exist only at the run's two ends.** Inside the run the model's cut
is the cut; the trim room at an internal boundary is the silence after a line, and
nothing else.
- **The declared cut times are a request.** The model cuts near them, not on
them, and will occasionally fold two declared cuts into one or add one nobody
asked for. The delivered take is split where it *actually* cut (step 6), never
at the planned times, and a wrong cut count is a failed take.
- **Length can cost resolution on some models.** A model whose long takes cap
below the finish format makes every run a resolution decision — which is why
native multi-shot *at the finish resolution* is a hard filter at the model
pick (`film`, model policy), not a trade-off discussed per scene.
**What you are not losing — and say so when it comes up:** per-shot *editing*.
The run comes back as one file and is split at its delivered cuts into
shot-shaped clips before anyone sees it — compositor bookkeeping, free — so
trims, reorders, drops, the scene editor's clips, Final Cut and the join QC all
stay per shot exactly as before. "We lose shot editing" is imprecise: a shot
is edited in place with the edit model, lengthened with the extend model, and
only re-rolled — with its run — when the user says so.
**There are no exceptions at planning.** No shot shoots alone, no film shoots
shot by shot: a risky stretch is a risk the run carries, a shot whose
composition matters gets a longer header and a labelled composition reference.
*Repair* is the edit model, the extend model, or a re-roll of the run (step 5).
The planning decision was made once (2026-09-03) so it is not re-made per
scene.
**One primary action per CUT is still the rule** — it moved from the
generation to the cut header. A header with five unrelated beats smears exactly
as a five-beat shot did; a scene of eleven cards is eleven headers of one action
each, with beats inside a header legitimate at roughly one per 2–3 seconds when
they are one continuous movement (a hand reaching, a head turning, a line
landing). What the run retires is the *other* half of the old rule — "use the
edit, not a generation, to build sequence structure" — because the measured
result says the generation builds it better.
**The ceiling is a packing limit, not a shot-length recommendation.** Author
coverage first, then pack those cards into a run. Default dramatic cuts are
3–8s and action may be shorter. A card over 8s needs
`design.durationReason`; over 12s is a deliberate long take. A scene longer
than 12s with one card must not pass silently: recommend a 2–4-shot coverage
version, warn that the long take
risks stretched motion and gives the edit no reaction/insert coverage, and keep
the one-card version only after the user explicitly chooses it. Model choice,
run grouping, visual rhyme, "restrained" tone, or spare seconds under the ceiling
do not constitute that choice. Several short shots still cost one generation
when they share a run — never merge their actions onto one card to save calls.
**Run length is arithmetic, not habit.** A run's `genSec` is the sum of its
shots' `sec` plus one handle at each end of the run, snapped **up** to a length
the model offers; the 3–8 seconds AI motion tolerates before it reads uncanny
(`film-edit`) is authored into each shot's `sec` rather than trimmed out of a
long take afterwards. Going to the ceiling is not an exception any more — it is
what a film costs — and the one trade-off that survives is the re-roll: a broken
second 22 of 30 re-rolls all 30, and the film has chosen to pay it.
Where the film outruns the ceiling, **the edge between two videos is joined the
handbook's way** (`references/SEAMS.md`, *The video edge*, 2026-09-09): video A's
last shot ends in the middle of a movement, video B's first shot picks that
movement up from a clearly different angle and size — a close-up, a detail, an
over-the-shoulder, never the same framing twice — and both videos carry the
same pictures in the same order, so every video dispatches together. The edge
falls where the ceiling falls, moved to the nearest moment where something is
moving; the story decides where scenes change, and an edge is never dragged to
a scene change to make it "clean" — that rule (2026-09-04 to 2026-09-08) made
films jump between places for no story reason. The one exception is a video
that changed its place or its people: the videos after it there take their
pictures of that place from its frames and wait for it (step 6).
(The extend sibling stitches several clips into one continuous video — ten on
the catalog's Seedance on 2026-09-10 — and may turn out to be a join between
two runs; nobody has measured it here — a candidate, not a method.)
**Inside a video the cuts are the model's, and the pair rules are written into
the shot blocks** — match on action, eyeline, screen direction, motivation
(`references/SEAMS.md`, *Internal cuts*). Three habits carry: the scene picture
opens the video — **the FIRST video of the scene only; a second video of the
same scene carries no `START FRAME` at all: it opens on its block's words plus
the identity views, the wide and the map** (`references/SEAMS.md`, *No two
adjacent cuts open on the same still*, and the reason it is a pixel contract);
one geography line,
identical in every prompt of the scene;
silence after every spoken line. Two uses of a frame image are opposites: an
**authored, approved still** labelled `START FRAME` in `imageUrls` is the
anchor (step 3); a **frame exported from an earlier video** is used only when
that video changed the place (step 6) or the scene is written as one unbroken
shot — it inherits the earlier video's drift and makes the next video wait.
## Which surface owns which decision
Every board answers about the artifact in front of it. Asking a question on a
surface that has nothing to show is what makes a console feel like a form.
| What exists | Surface | What the user decides there |
|---|---|---|
| nothing — a list | `picsart_shotlist_board` | story, coverage, shot **size**, **duration**, order, cuts |
| one run's take, split into its shots | `picsart_scene_editor` | is this the run, which cut (if any) failed, and what exactly is wrong |
| an assembled cut | `picsart_scene_editor` | watch it, trim, split, delete a stretch, and say in comments what to regenerate |
| a retake of a shot they already watched | `picsart_scene_editor` | the new take in the cut — keep it, or go back to the one in the log |
The shotlist board has **no modes**. It had a `plan` and a `conveyor` pass once;
the conveyor was take triage, and that moved off the board when it was rebuilt
(2026-08-21). The board plans — one call, every scene of the pass, one approval.
A take is judged in the scene editor, always.
**The board still thinks in shots; generation thinks in runs.** Its rows,
`genSec` and "commit to video" are per shot, and it has no way to show which
rows share a generation — so the run grouping is said in chat when the list is
approved, and the board's per-shot `genSec` is read as "what this shot would
cost alone", never summed into the forecast. A run marker on the board is a
server-repo ask (`../../docs/PLATFORM-ASKS.md`), not something to fake with
row labels.
**Camera has one author.** The shot's card on the shotlist board is where it is
chosen — the move pill, previewed by the board's own clip for that move — and
after a video exists it is re-asked exactly once, as the step-4 severity
routing. There is no separate design screen (retired 2026-08-21); a second
surface asking the same questions is the duplication this flow removed. Pass
takes with `kind` (`video` | `image`) so a still is never shown as a broken
player.
**The model is chosen BEFORE the durations.** A shot's length is only real if the
model accepts it — and what the model accepts is read off `picsart_model_params`
(`duration`: min, max, step), never from a note here: on 2026-09-10 the schema
said any whole second from 4 to 30, and a 7-second call was accepted and
delivered at 7.0 s — the older note in this file that listed a ladder with no 7
was wrong. The run's `genSec` is still
preflighted before the board opens. A card planned
model-blind gets snapped afterwards, which is an approved
plan being quietly changed. Pass `model` on the `picsart_shotlist_board` call and
the board offers exactly that model's lengths; a length nobody was offered cannot
be snapped. Switching models later re-opens every duration, which is why the
pick sits in Stage 1 — after the look console, before the shot list ever opens
(`film-development`) — and not at the bible lock. **And the model is chosen
before the runs**, for the same reason one level up: its ceiling is what decides
how many generations the film is, so a film grouped model-blind is a grouping
that will be redone.
## Step 1 — final scene shotlist
Sharpen the preliminary cards from `film-development` into the generation
shotlist. Per shot: id (`12A`), size, movement, FOV anchor, action (one),
line/sound, light/time of day, palette world, duration, and **the tags of every
asset in frame** — that last column is the prompt's checklist. The board's return replaces
the fields the board owns and leaves `design`, `refs`, `run` and `trim` on the
card by id (`../film/references/WIDGET-FEEDBACK.md`); an action that no longer
tells the story's paragraph is a story note back to `film-development`: the
paragraph is rewritten and shown first, never answered with a board.
Coverage logic as
on a set: scene master → sizes → details; mind eye-lines, the action axis,
cutaways. Present via `picsart_shotlist_board`, feedback per
`../film/references/WIDGET-FEEDBACK.md`. The markdown-table fallback is for a
connection that does not expose the tool — never a shortcut when it does, and
never the answer to "show me the shot list". **Asked to see the shot list, open
the board again**, whatever stage the film is at: the board is where a shot list
is read and changed, and printing the rows instead hands back data the user then
has no way to edit.
### The cut-by-cut pass — write every cut as a pair, then read three checks
Shots are drafted one at a time, as a director drafts them. Then walk the scene
in adjacent pairs, **before any prompt is assembled**, and write each cut into
the two shot blocks as a pair — the end of A's action and the start of B's —
with one of the four pair rules in `references/SEAMS.md` (match on action,
eyeline, screen direction, motivation). Nothing is recorded per boundary; the
pair lives in the prompt. A cut rule is a claim about two shots' *content*, and
content is decided in the prompt: an editor handed two shots that never shared
a movement cannot invent one.
**Three checks, free, read off the cards:**
- **No two adjacent shots of the same subject share a size.** Two sizes apart or
the cut stutters. This is the checkable half of the 30° rule.
- **Eyelines agree.** Where a look answers a thing, A's gaze direction and B's
subject placement are on opposite sides of frame. Same side reads as the
thing being behind them.
- **Screen direction holds inside the scene**, shot to shot. A reversal is legal
with a toward-or-away shot between it, and illegal silently.
Shot length is a habit, not a gate: dramatic shots run 3–8 seconds, action
shorter, a reaction shorter still (the handbook: *"Use the duration based on
what the shot needs."*). A shot over 8 seconds carries its reason in one line
on the card and nothing else — no approval, no alternative shown.
A failure here costs a keystroke. The same failure found after generation costs
a take.
### The run pass — the videos the plan named, filled to the ceiling
**The videos were decided in Stage 1, with the user's yes** — the video plan
(`../film-development/SKILL.md`, step 5) already says how many videos the film
is, which scenes each covers, its `genSec`, and one sentence for every join,
seeded into `film.json.runs[]`. The run pass does not plan videos; it fills
them. With the cuts written, walk the FILM in cut order and assign each card to
its planned video, **filling each one up to the model's live ceiling** (30 s on
Seedance 2.5; `picsart_model_params`). The edge falls where the plan put it —
on a movement, never a rest, never a scene change for its own sake
(`references/SEAMS.md`, *The video edge*). At that edge the last shot block says
*ends in the middle of the movement* and the next video's first shot block
says *picks that movement up from this new angle*, and is a clearly different
size and angle — a detail or an extreme close-up by preference.
**A moved edge is shown, never re-cut in silence (2026-09-09).** When the
cards' seconds do not sum to a video's `genSec`, or the plan's edge lands on a
rest, say so in one line with the fix — *"video 1 runs 33 s; the edge moves
from 1G to 1F, where Rasa's hand closes on the flask"* — and get the yes, the
way a story note gets one. Two adjacent planned videos that fit as one are one,
and that too is said, not done. On 2026-09-08 the videos were decided at this
stage, after the pictures and unseen, and the user asked four times how scene 1
connected to scene 2.
Record only what the dispatch needs: each shot carries `run` (`"r1"`), and
`film.json.runs[]` holds each video's shot ids in order (across scenes), its
planned `cutTimes` (the running sum of `sec`, in run seconds from the prompt's
0.0), its `genSec`, its `join` sentence from the plan, and its `refs` — the
ordered list of reference images every shot block numbers against.
Say the grouping in one line when the shot list is approved — *"the film is
three videos of 30 s as planned, the edges at 1F/2A and 2G/3A"* — because it is
the first thing that changes the invoice, and the one thing the board cannot
show.
### OTS is not a shot size — it is a two-body claim
Shot size is **one dial, and it means distance**: WS, MS, MCU, CU, ECU. Any of
them can be shot with one person alone in an empty room; none of them says who
else is present.
**Over-the-shoulder is a different kind of thing wearing the same label.** It
describes an arrangement: two people facing each other, the camera tucked behind
one of them, looking past their shoulder at the other. Recorded in the `size`
column it reads downstream as "how close is the camera", and three facts travel
nowhere:
- **whose shoulder** is in the foreground,
- **which side of frame** it sits on, and
- that a **second body must persist** — a close-up needs one person for six
seconds; an OTS needs two people holding fixed positions for six seconds, one
of whom is barely visible.
The third is what fails. A start frame where the near shoulder is an ambiguous
dark mass gives the model nothing to hold, and it stops treating that mass as a
person partway through the shot. Observed twice on one shot; it held only once
the near figure's ear, jaw, shoulder line and garment texture were all legible.
So the rules, and none of them costs a render:
1. **The card names the near body.** `values.nearCharacter` (whose shoulder) and
`values.nearSide` (left/right). `picsart_shotlist_board` refuses an OTS card
that names neither, and refuses one that lists fewer than two assets in frame.
2. **Check the side against the location map** before generating. The map already
says who sits where; if it says Maro sits right, an OTS over her shoulder puts
her on the right. Put her left and the audience reads it as her having got up
and moved.
3. **The prompt claims the near body as a person, not a silhouette** — named
features, and holding position for the whole shot. See the foreground-body
clause in `references/PROMPT-BLOCKS.md`.
The board carries this as its own decision now — **Who's in it**, separate from
size: `single` · `two-shot` · `dirty single` · `OTS` · `POV` · `insert` · `group`.
Three of them (two-shot, dirty single, OTS) are two-body claims and take the
`nearCharacter` + `nearSide` treatment above. Two more were being mis-recorded as
sizes: a **POV** is about whose eyes the camera is — and the other actor must look
*into the lens*, which no size can say — and an **insert** is a thing rather than
a person, which is what an "ECU of the instrument on the table" actually is.
`group` is worth naming because three or more bodies is where models start
cloning people.
**Camera height is a decision too, and the board had none.** `eye level` ·
`low` · `high` · `top-down` · `dutch`. It is the second instruction a director
gives after size — low looks up and grants stature, high looks down and takes it
away — so a shot that never says it is a shot nobody framed. Set it per shot like
any other value.
An OTS also rarely travels alone: a conversation is covered as **two reverse
angles**, and the pair must match in everything except who is near — same lens,
same height, same distance, eyelines reversed. Nothing checks that pairing yet;
until it does, set the two shots' values identically by hand and look at them
side by side.
## Step 2 — design the shot on its card, then assemble the prompt
**The card is the design surface, and it arrives filled in.** Every shot's six
decisions — size, camera move, lens, light, colour, length — plus its
arrangement and camera height are pills on its card on `picsart_shotlist_board`,
each opening a picture rather than a list. **A pill the user changes is written
into that shot's block; a light left as seeded writes nothing, but lens and
aperture reach every shot, seeded or changed, and so does a palette other than
`auto`** (`references/PROMPT-BLOCKS.md`, Part 2, *The card's own picks*).
A choice made on the board is never a choice the model did not hear. **Seed them before the board opens**,
from what is already decided (the story's action, the scene location's light,
the world defaults' register, the run's model), so the user touches only what they
disagree with; nothing forces a stop, in either pace. There is no console behind
a row — the inline design panel and its "compose the first frame" button were
retired with the board's 2026-08-21 rebuild, and the requirement to open one
per scene went with them (2026-09-04). Without boards, the same rule: state the
seeded design in one line and the host's question interface only what the card leaves open,
from `references/PRESETS-CAMERA.md`, `PRESETS-LIGHTING.md`,
`PRESETS-ACTING.md`. Both paths return preset names plus their compiled text
fragments. World defaults come from the bible's setup; the shot stores only its
deviations (`design` on the shot in `film.json`).
**The scene's pictures are step 3, always (2026-09-08).** A shot's frame is no
longer composed here on request: every scene gets the handbook's set of
pictures before its run — the scene picture the run opens on, the wide, the
room map — on one board for all scenes (step 3).
A user who asks "show me how the opening looks" is shown that board.
**A fragment is the start of the Camera block, not the whole of it.** Nineteen
of the moves have been generated and measured (`genre-previews/_camera/` in the
plugin repo), and the finding that matters at prompt time is that a model
renders a described *picture* and ignores a stated *quantity*. So paste the
fragment, then make sure the block ends on the arrival as an image, name the set
as rigid if the camera travels through it, and — for any move that ends on a
changed aspect — say that the camera does the turning. `PRESETS-CAMERA.md`'s
"Getting a model to actually do the move" carries the rules and what each one
cost to learn.
**The board holds choices; the numbers behind them are yours.** Several blocks
want a quantity where the card holds a word — the Kelvin behind `warm`, the
km/h behind a moving car, the fog density behind a foggy street, the ratio
between two things of different size. **None of them becomes a pill.** The
console's job is a decision with a picture behind it, and nobody can judge 5200
against 5600 from a chip; a board that asks would be the form this pipeline
keeps trying not to be. Resolve each from what the user already chose plus the
scene's location and time of day, write it into its block, and do not raise it
in chat either unless it is genuinely in question. `PROMPT-BLOCKS.md` blocks 8,
9 and 10 carry the rules and the tables.
**A slow shot names which kind of slow it is.** There is no tempo setting
anywhere (retired 2026-09-04 — `PRESETS-LOOKS.md` has the why). Models render
described pictures and ignore stated qualities, so rhythm is written, never
stated: the shot block's action and the card's `sec` carry it, and tempo
words (slow, calm, measured, brisk, urgent) do not appear in a header. A shot
that should feel slow has less happening in more seconds, and it records
`design.slowReason`, from four:
| `slowReason` | What it is | How it reaches the shot |
|---|---|---|
| `anti-tempo` | slow *against* the scene around it, for contrast | real time; the neighbours carry the contrast, so it is a cut decision as much as a shot one |
| `hero reveal` | the thing itself deserves the seconds | **not generated slow** — generated at normal speed and ramped at the edit, because a model asked for slow motion smears instead of slowing |
| `breath` | the film needs air after a heavy beat | real time, minimal action, usually paired with a `tailHold` |
| `emotional pause` | a face working, nothing else happening | real time; the seconds go to the acting, not to the action lines |
The value is not decoration: three of the four are real-time shots whose slowness
comes from *having less happen*, and one is a post effect that should never be
asked of the generator. A card that just says "slow" gets whichever the model
guesses.
**Generate one size wide when the shot can afford it.** A take framed one
shot-size wider than the card's intent gives the edit spatial trim room —
virtual reframes, subtle push-ins, and composition fixes are then free crop
moves instead of retakes. Skip this on faces at CU and tighter (resolution is
the budget; a crop spends it).
**Generate one beat long, for the same reason.** Two numbers, not one:
- `sec` is the **cut length** — how long the shot runs in the film. It is what
the ±10% runtime gate measures and what the dialogue rule computes.
Unchanged.
- `genSec` is the **generation length**. For a run it is the sum of its shots'
`sec` plus a handle at each end *of the run*, snapped **up** to a duration the
model actually offers; for a solo shot it is `sec` plus a handle at each end.
It is what you pass to `picsart_generate`, and you trim back to the shots'
`sec` in the assembly.
This is the temporal twin of shooting one size wide, and the same logic: a
generated take has no second take, so the cheapest repair is material you
already paid for. A tail that drifts, an action that lands half a beat late, an
end state the next shot cannot cut to — with handles those are trims; without
them they are re-renders.
**Handles are a per-film policy**, stored independently of setup feedback
(the MCP setup no longer sends `handles`), because
they are a real and permanent cost: duration is what video models bill. On a run
they are exactly two — one at each end of the run — and they are cheap in
proportion: two seconds on a 28s run, not two on every 5s shot. Skip them
(`handles: "off"`) only when the run is already at the model's ceiling and there
is no room to add. **Inside the run no shot has a handle**, by construction: an
internal boundary is the model's cut, and its only trim room is `tailHold` and
the audio line's silence. That is why the silence is not optional, and why a run whose
line runs into its cut is a failed take rather than a trim — there is no handle
behind the last word.
### Audio: the takes keep the voice they were born with (2026-08-27)
**Shoot dialogue with `generateAudio: true` and each speaker's saved voice
description.** Read the character's `voice` field and copy it verbatim into every
speaking block, including inserts, retakes, edits and extensions; see
`references/PROMPT-BLOCKS.md`. Fill a missing field once using
`../film-assets/references/ASSET-SHEETS.md`, without an extra user question.
Describe the shot's emotion and volume separately. Native audio is the default;
no separate TTS, cloning or saved audio sample is required for this text rule.
The description improves consistency but does not guarantee identical timbre.
Compare new dialogue with accepted takes before declaring the voice consistent.
Optional reference audio is conditioning, not a deterministic voice lock or a
promise that the supplied waveform will be reproduced. A separate voice workflow
is a distinct production choice; do not silently substitute it or remove dialogue.
Five rules make native audio survivable. They are not optional:
1. **Fewer, longer takes.** Keeping a dialogue scene in one generation reduces
independent voice decisions. Still check the delivered performances; neither
a shared run nor the copied description guarantees perfect consistency.
2. **Transcribe every dialogue take and read it against the story's lines.** The model
paraphrases, drops words, adds filler, and mispronounces names. Cheap to
check, impossible to fix later without a retake.
3. **Demand silence handles** — a beat before and after each line — and reject a
take that runs its line into the last frame. Native audio is welded to the
picture, so the only cut points the edit gets are the silences the model left.
4. **Carry a bed across every scene.** Each take is mastered on its own, so
levels, EQ and room tone step at every join; a continuous ambience or music
bed is what hides it. Audiences forgive picture mismatch, not level jumps.
5. **Preserve the scripted dialogue.** Voice drift is a review issue, not a reason
to replace a requested line with silence or narration. Judge accent, register
and timbre against the accepted character performance, separately from emotion.
A bed can smooth changes in room tone and level; it cannot repair a changed
speaker identity. Do not automatically accept voice drift under the native policy.
### Frames or references — one way: `imageUrls` only
**Every video call carries `imageUrls` only, and the `startFrame` field stays
empty** — on a run, a bridge, an insert, a one-shot reshoot, whatever the clip
is called (rule 7, `../film/SKILL.md`). The frame the video must open on is
picture 1, labelled `START FRAME` in the tagging header; the identity and
wardrobe views of everyone in the video ride beside it, in the order `runs[].refs`
fixes, and the header says which is `FRAME REFERENCE for shot N`, which a face
or an outfit, which `SPACE`; after the header, names only. User-verified
2026-09-03: the model honours the role stated in words, so one call gets both
things the two fields used to force a choice between.
Why the field is never filled — measured facts, kept here as reasons, not as
a second recipe:
- **A start frame and reference media cannot travel in the same request**, and
"reference media" means images, video **and audio** alike: the video model
routes on which fields you set. Verified by running it (2026-08-26) — a call
carrying both `startFrame` and `audioUrls` came back
> `bytedance_invalid_parameter` — *"The parameter `content` specified in the
> request is not valid: first/last frame content cannot be mixed with reference
> media content"*
while the same audio alongside `imageUrls` rendered fine. Seedance 2.5's
schema pairs `image_urls` (up to 30 references) against `image_with_roles`
(≤ 2 entries: `first_frame`, `last_frame`, `reference_image`) as
alternatives. Sending both is a rejection **after** the wait.
- **A frame shows only the people in it.** The 2026-09-08 bridge went out with
scene 1's last frame in the `startFrame` field — one woman's face — and no
picture of the other woman, who was in the shot but not in the frame. She
came back in a long coat with two flasks, and the bridge put a wardrobe jump
on both of its joins.
- **Native audio is NOT reference media.** Tested end to end (2026-08-26):
`generateAudio: true` with the line in its shot block was accepted, rendered,
and the character spoke the line — so a call carries its lines and its
images together. Until 2026-09-09 this test was also written up here as a
second way to build an anchored shot (*"approved start frame + generateAudio
+ the line"*). It is not a way: it is the proof about audio, and the call is
still `imageUrls` only.
- **Keep the reference set tight, and every entry a single view.** The
identity view and the wardrobe view of every character in the video — both,
always (rule 7, `../film/SKILL.md`) — and per scene the run plays its pictures — the scene
picture, the map and the wide (step 3). A tagged
state a cut names — `@cal_wet` — is its
own view, numbered like any other image, never a panel pointer into a sheet.
For a photo-sourced character the photograph is the identity view and, when
it shows the outfit the story dresses them in, the wardrobe view too; when it
does not, the user is asked for one more photograph that does (rule 7,
2026-09-10) — a view of its angle sheet comes along only when a cut in this
run needs that angle. Every prop the film gave a plate to rides as `IMAGE n —
PROP: <name>` (rule 7): the descriptor is not in the prompt, so a picture is
the only carrier an object has. Every image is inlined and the total has a
ceiling.
- **The ceiling is real and it is measured before every dispatch**
(2026-09-04). The 22MB that died on `inline_media_too_large` was three
*lossless PNG* references; a view is a JPEG crop of a max-resolution sheet
scaled to a **2048 px delivery cap** (the model renders 1080p and declares
no input pixel limit, so the cap is ours to hold), which puts each one at a
few hundred KB — **what binds is the image count, not the bytes**. Still: `picsart_media_probe_media` every
URL (free — `bytes`, `width`, `height`), sum, and stay **under 15 MB** —
the count follows the scenes the run plays (two characters and one scene
are seven images; Seedance 2.5 takes 30) and the old 6–8 cap is gone
(2026-09-08).
**The probe returns `width` and `height` for a reason: read the short side
of every picture, not only the bytes.** `min(width, height)` under 300 px is
refused by the provider after the wait, so nothing under **320 px on its
short side** is dispatched — width counts as much as height. On 2026-09-09 a
252×508 wardrobe view was probed, its bytes were summed, and it was
dispatched anyway: only the total was being read, and the floor everyone
remembered was *"300 px tall"*. The cut that made it is fixed in
`../film-assets/references/ASSET-SHEETS.md`, *The crop*; this is the gate
that should have caught it regardless.
Over budget, in order: **drop the wide — but only when the map is in the set
and no cut in the run opens the setting up** (a pull-back, a reframe wider
than the shot it came from, a move that reveals a skyline or a street: those
cuts need the wide, and dropping it there is what let a location drift on
2026-09-10); **the map never leaves, and neither do the identity
and wardrobe views** (rules 7 and 10 — no descriptor is in
the prompt any more, so neither the costume nor the geography has another
carrier); re-encode any PNG as
JPEG; downscale a view only as far as keeps
the identity view ≥ 600 px on its short side — and **a view downscaled once
becomes that state's file from then on**, recorded in `views[]` and passed
by every later run, never a one-run copy (one state, one file). The old last step — splitting
the face panel out of a sheet — is gone, because that split now happens at
lock for every asset. The method and the export calls are in
`../film-assets/references/ASSET-SHEETS.md`, *How an asset reaches the
run*. Never discover the ceiling after the render.
- **The panel-pointer lint, run at the same moment (2026-09-07).** Read the
image labels before the prompt goes out — the references header and every cut header's
image reference. A pointer **into a reference image** — *panel 2*, *the
leftmost panel*, *the top-right of IMAGE 1*, *the bottom row of the sheet* —
is a **dispatch error**, not a wording preference: it means one image in
this set has more than one thing in it, and the fix is a crop (free, at
boxes `film.json` already holds), never a reworded label. Two runs of one
correct pointer returned two different women; the wording was never the
variable. **Scope: reference labels only.** Position words describing the
*frame being made* — the location map, the blocking block, where a
character stands, where the camera is — are the film's staging and are
required; the lint never touches them.
**The anchor is compositional, not pixel-exact.** Measured on that test: the
delivered first frame scored SSIM 0.73 / PSNR 20dB against the approved still —
same woman, wardrobe, room, pose and props, framed slightly wider with the
subject shifted. Excellent anchoring, and *not* a guarantee of identical pixels,
whatever the vendor doc's "exactly match" says. That measurement went through
the `startFrame` field; a run's frames travel in `imageUrls` with their role in
words, and the same expectation applies — compositional, not pixel-identical.
**Reference audio is a conditioning input, never the film's voice.** Also
measured: feeding a 5.3s scratch line as `audioUrls` produced audio whose
envelope correlated with it at 0.249 — the model performed its own line in its
own timing, not the supplied track. So a scratch mix earns its keep for
**timing** (see step 3), and the final voice comes from native audio or from the
dub at finishing. It is never delivered by attaching a wav.
**Duration = the spoken line + one second, snapped UP the model's list.** Block
11 already requires a second of silence after each line as the editor's cut
point; the duration has to leave room for it. A 5.3s line needs 6.3s, and a
solo clip snaps that **up** to the next length the model's `duration` schema
allows (read off `picsart_model_params` — never a ladder remembered from a
note; on Seedance 2.5's step-1 schema 6.3s is a 7s clip, and 7 s was accepted
and delivered on 2026-09-10). The same test
asked for 6s and the dialogue ran to the final frame with no cut point — exactly
the failure the audio line exists to prevent. **Inside a run the snap moves to the
total.** Cut times are prompt text, so a shot inside a run keeps its exact
`sec` — 6.3s is 6.3s, no ladder — and only the run's `genSec` snaps up to what
the model offers; the slack that snapping adds goes to the run's tail handle,
never to a shot.
Either error — the mixed pair, or `inline_media_too_large` — is permanent.
**Change the payload; never re-run the same one**, and say in one line what you
changed.
Every run's prompt is the handbook's two-part shape — see
`references/PROMPT-BLOCKS.md` for the template, the shape per model, a worked
example and the pre-dispatch checklist. The assembly is mechanical by design:
the handbook's lines verbatim, the style prefix verbatim from the bible, the
geography line verbatim from the scene; no descriptor is pasted — the pictures
carry identity. There is no negative prompt: every ban is written as what IS in
the frame.
**Before every video dispatch, including edits, extensions and inserts, run the
prompt-verify step — `references/PROMPT-VERIFY.md` — not just the format lint.**
It opens the files that govern a run (the blocks reference, the camera, lighting
and acting presets, the seams, the look), derives what they require for this
call, and checks the **literal tool arguments** against them; its verdict is
written before preflight and a fail blocks the dispatch. Use
`picsart_prompt_verify` for the objective half and read the rest yourself. A valid schema and a credit approval do not excuse missing dialogue,
changed story content, or a house line paraphrased on its way into the prompt.
**Price the model before believing the draft rule.** The rule below exists for
ONE reason — keep the iterations cheap so only the keeper is paid for at full
size — and it only works on a model whose price moves with resolution. Prices
change and no number is recorded here: quote both resolutions with
`picsart_preflight` before the first dispatch. If the price moves with
resolution, draft at 480p; if it is the same, draft at the finish resolution and
there is no second pass to pay for. Say which of the two the film is doing, once,
in the forecast.
### Native draft to final
Read `picsart_model_params` for the chosen model before quoting. On Seedance
2.5, when the schema lists `draft`, use `picsart_generate` with
`extra: { "draft": true }` for a native draft, keeping the approved prompt,
references, duration and format. Preflight the same payload including `extra`.
Record the returned result URL exactly in `film.json`.
If the live schema also exposes `fromDraft`, preflight a final request with
`extra: { "fromDraft": "<exact draft result URL>" }`; use the schema's
required envelope only. The tool requires a `prompt` string: use an empty
string for a from-draft request only if preflight accepts it. Re-quote and
obtain approval before the paid final. Do not add the original references,
duration or draft flag unless the live contract requires them.
If `fromDraft` is absent or rejected, it is not available on this connection.
Explain that the final requires a separately quoted rerender and may change
content; follow the normal finishing approval and re-review. Choose a regular
resolution-priced draft instead when that better fits the approved budget.
For models without the native draft path, dispatch drafts at **480p** — where resolution actually changes the price —
with the run's images in `imageUrls`, in exactly the order the prompt numbers
them, and **the `startFrame` field empty** — the start frame is the image the references header
labels `START FRAME`. `generateAudio: true` on any run with a
line in it — the line, its lip-sync, and
the voice block are part of what is being judged; a run with no speech drafts
with audio off. Audio follows the film's **voice policy** (always `native`,
recorded in `film.json.voicePolicy` — nothing to decide) — and *how the approved voice
reaches the picture* is settled before the first dialogue take, not at finishing:
see the next section. **Every video generation is submit-and-poll**:
`async: true` + `picsart_job_status` (the server defaults every media mode to
async now, so this holds even if you forget) — a synchronous video call dies at
the host's ~60s tool window while the render keeps running and charging, with
no handle left to recover the result. A host "isn't responding" error is therefore never a failed
generation: poll the job, never re-submit on that signal.
`picsart_preflight` the batch, **give the user the quoted total, and dispatch
only on their yes** (the law at the top of this skill) — surprise spend is the
one unrecoverable mistake.
After dispatching, put the batch's job handles on `picsart_render_monitor`
(when the server has it): it polls the jobs itself, shows live per-shot
progress, and **reports the finished takes back into the conversation
automatically**. Never ask the user to wait, check back, or "ping me in five
minutes" — that is the monitor's job. Without the monitor, poll
`picsart_job_status` yourself; if a render outlives the turn, say plainly
what's running and check it first thing next turn.
## Step 3 — the scene's pictures: one board for all scenes (2026-09-08)
Read `../film-assets/references/ASSET-EFFICIENCY.md` for scheduling and changes:
independent ready scene chains advance without waiting for unrelated retries;
an upstream correction triggers a content-impact check, not a blanket rebuild.
Scene pictures still use the full scene style prefix, unlike neutral asset plates.
**Every scene gets its pictures before its run, and nothing else is generated
between the shot list and the run.** Until 2026-09-08 stills were on request
and the run's only picture of a place was a clean, empty location panel. The
handbook does it the other way round, with a reason that stands: *the model is
trained on films with actors in them — an empty location renders unreal, so
make the scene first and take the location from it.* A scene's pictures are one
dependency graph: wide first, opening crop and optional map derived from it. They
are what the run's `imageUrls` carries for that scene — the scene picture as
`START FRAME`, the wide and the map as `SPACE` — so the model never has to
guess the room. A `FRAME REFERENCE for cut N` rides along only when a frame
exported from an already-approved run supplies it (step 6); none is authored
ahead of time. Character views ride beside them (step 2).
**Wide first, then cut the scene picture out of it, then the map — one approved batch (2026-09-23).** Two generations and one free crop:
1. **The wide is generated first**, at 4K, with the cast in it from their
identity and wardrobe views; the scene-picture craft below (whose cast
opens the scene, the prompt lines, the three planes) applies to it.
2. **The scene picture is cut out of the wide** with `picsart_media_export` (the crop
recipe, `../film-assets/references/ASSET-SHEETS.md`, *The crop*): a box
around the opening shot at the film's ratio, no credits, the run's `START
FRAME`. Its short side must clear the video's resolution (1080 px for
1080p), else the wide itself is the start frame. In a vertical film a
two-shot barely zooms, so a scene opening on two usually starts on the wide.
3. **The room map is generated from the wide**, when needed (item 3 below).
Quote the wide and the map as one intended batch. Preflight each concrete
payload, obtain approval for its cost, and use `picsart_generate` asynchronously.
The map waits for the actual wide URL and its visual check; if its exact quote
could not be obtained in advance, show that quote before dispatch. The opening
crop is free to render. Present wide, crop and map together for one scene review.
A scene starts as soon as its own cast is approved. A request to shoot now can
authorize the prerequisite pictures and run together only when their scope and
cost are explicit; preserve all dependency and asset checks.
**The chain, per scene** (a scene = one place at one time of day; a scene that
moves rooms is two chains). **Model (2026-09-23): the wide on a model that
renders 4K (`gemini-3.1-flash-image` today, `resolution: "4K"`; check the enum
with `picsart_model_params`); the room map, square and empty, on the GPT Image
family — ids as recorded in `film.json` (`model.pictures` — `people`,
`map`), read off `picsart_model_catalog` once at Stage 4
(`../film/references/PIPELINE.md`, *Image models are families*).**
On *The Last Drop* (2026-09-08) Nano Banana lost faces in two-shots made from
whole sheets and Seedream held them; with cut views (2026-09-23) Nano Banana
held both. If a two-shot fails on faces again, try Seedream for that wide,
accept the smaller cut, and write the finding here. The
order below is the order things are attached, because the handbook's prompts
say *the 2nd photo*. Every prompt opens with the two film lines
(`../film-assets/references/ASSET-SHEETS.md`, *Every image prompt carries the
film*).
**Before either generation dispatches, run the prompt-verify step
(`references/PROMPT-VERIFY.md`, 2026-09-13) — it is mandatory for a still
exactly as it is for a run, and the still row of its governing-files table
names what to open.** A scene picture, a wide or a
map is still a generation with subjects tagged
in it, and the same failure the gate exists to catch on video happens on
stills just as easily: a character named in the shot but written into the
prompt only as the target of someone else's reaction, with no pose or emotion
of their own. Check the literal text about to be sent, not a recollection that
the rule is known.
1. **The scene picture** — the handbook's *base image*, the scene as its first
frame. **CUT from the wide since 2026-09-23** (above): what follows is the
craft of the wide's prompt and of where the cut falls. Every head in the cut
at least a tenth of its frame tall.
**"The scene as its first frame" means the cast of `shots[0].assets` —
read it, never the scene's dramatic centre (2026-09-13).** A scene whose
cast changes as it plays (someone arrives on a footsteps cue, a knock, a
door) is *about* the pairing that arrives, but its FIRST shot is whoever
is already in the room — and the scene picture is the first shot, not the
scene's throughline. Built from the throughline instead, a three-person
confrontation scene got its base image as the two-shot of the arriving
character and the one already there, when the shot list's own `1A` named
only the two who open it — the run would have opened on someone who has
not entered yet. Before writing `Subject #1`/`#2`, open the approved shot
list and copy `shots[0].assets` verbatim; if that list disagrees with
whichever pairing feels like the scene's centre, the shot list wins.
Prompt: the handbook's
thirteen lines, in its order, each filled from the film — *describe only
what the camera sees*:
```
Visual tone: <bible.stylePrefix, verbatim>. Skin matte and textured with visible pores, no gloss or shine. A frame of live-action film — real people, real fabric, real light; not an illustration, not animation, not a 3D render.
Subject description: <one distinguisher per present character — "Subject #1 — @cal, worn dark-blue work jacket"; the face comes from the attached view, not from words>
Shot size: <the card's size fragment>
Camera angle: <the card's angle fragment; "Eye-level." when the card is neutral>
Composition: <the card's arrangement or composition fragment, or N/A>
Pose & action: <the card's action — what each subject is physically doing in frame one>
Emotion: <the card's feels line, per visible face>
Gaze: <each visible face's gaze target — in the scene, never at camera>
Positioning in the frame: <each subject's placement from the location map — left third, right third, centered>
Visible / Not visible: <what must stay in frame, what may crop>
Foreground, Midground, Background elements: <all three, named — what sits closest to the lens, the plane the subject is on, what falls away behind them>
Setting: <the location descriptor's setting line — place, condition, time of day>
Aspect ratio: <the film's ratio>
```
**The skin clause rides on `Visual tone`, and is ours (2026-09-11).** The
prefix compiles the camera (grain rides in its stock) and the lens family,
and a camera fragment says how its stock renders skin *colour* — none of them ask
for skin *texture*, which is the one instruction that most reliably fights
the render look on faces (2026-09-07). It was in the video prompt's quality
line and nowhere in the still that sets the film's look. It is appended to
line one rather than added as a fourteenth line, because the thirteen are
the handbook's, in its order, and the only deliberate departure from them is
the aspect-ratio substitution below. **Where the light comes from is not
asked for here, and that is now a decision, not an omission (decided
against 2026-09-11).** Lighting is per-shot by decision (2026-09-07), so it
cannot ride the prefix, and the handbook's thirteen have no lighting slot;
a scene picture takes its light from the time of day on `Setting` and from
the plate it was derived from. The course argues a named light source is
the largest single realism lever there is, and it may well be right — the
case is kept in `research/ai-video-bootcamp/ANALYSIS.md` §4.12. It was put
to the user on 2026-09-11 and declined. Do not re-raise it unopened.
**The still says what medium it is, and bans the others (2026-09-11).**
Appended to `Visual tone` after the skin clause, and taken word for word
from what the character sheets already carry, so the two describe the same
film: *"A frame of live-action film — real people, real fabric, real light;
not an illustration, not animation, not a 3D render."* A film set up as
animated says its own medium instead — the line is whatever the film is,
never a fixed string. Until now this guard existed only on the character
sheets: the sheets refused the render look while the picture that sets the
whole scene's look asked for nothing, and every frame of the scene is
derived from that picture.
**They go to the compiler as `space` (`foreground`, `midground`,
`background`), the same in every prompt of the scene; it refuses a run or
a scene picture without all three (2026-09-23).**
**All three planes are named, and `N/A` is an argued exception (2026-09-12).**
The line used to end *"or N/A"*, and an escape offered in a template is the
value that gets written. The course's sharpest demonstration is a matched
pair — same model, same subject, same place — where the only difference is
whether a foreground, a midground and a background were written down, and the
version without them renders the person pasted onto the backdrop like a
sticker. The claim is that the flat look **is** the missing layers, not a
model weakness, and it is the same reason the handbook's own location plate
carries the three slots. So the default inverts: a frame nearly always has
something close to the lens — a shoulder, a doorframe, a railing, steam, the
edge of a table — and writing `N/A` means claiming it does not, which is
rare enough to be worth a sentence in the card's notes.
**This is the near plane only; it is not an instruction to fill the frame.**
A foreground object sits close to the lens and slightly soft, and it frames
rather than competes: one already in the location, never a prop invented for
the shot, and never something that crosses a face. Where the camera travels,
check it against the measured warning that a single large near object sweeps
the whole frame on a lateral or orbital move and drags the subject with it
(`references/PRESETS-CAMERA.md`, *If you are generating a start frame too*) —
many small cues beat one big one. The `Atmosphere` presets in that same file
are the other half of this: the planes give the eye somewhere to travel,
atmosphere is what physically separates them.
**Adapted from the Skool course's framing lesson, and not measured here**
(`research/ai-video-bootcamp/ANALYSIS.md` §10.3). It is free — it changes no
field and costs no call — which is why it is adopted on his demonstration
rather than held for a probe of ours.
**`negativePrompt`, where the image model's schema declares one.** These are
all image-model work, so the guardrail the sheets already use applies here
unchanged (`../film-assets/references/ASSET-SHEETS.md`): for live action, the
medium ban — the words that rule out drawing, animation, rendering and
plastic-looking skin. `picsart_film_compile_asset_prompt` returns it in
`negativePrompt`; take it from there rather than writing it. Never as prose,
never in a video block. The lettering ban below is scoped more narrowly than
this one.
**The lettering ban goes on the scene picture and the wide — NEVER on the
room map.** The map's prompt asks in as many words for a label
on each side, *A on the north side, B on the east side*, and those labels are
the only reason the map exists: they are read off it to write the geography
line that every prompt of the scene then carries. Banning lettering there
destroys the artifact. On the three that do take it, the compiler adds the
lettering ban — every form of on-image text, from signage to watermarks — to
the medium ban above.
**A film that needs a sign does NOT ask the model for it (corrected
2026-09-11).** A story with a readable shop name, a door number, a headline
on a screen or a figure on a phone still gets the ban — because the model
cannot hold clean typographic text, which is the same reason
`film-finishing` already refuses to generate the film's titles and makes
them as overlay tracks instead. In-world text is the twin that rule went
silent on. Keep the words out of the generation and **lay them in as a
compositor layer over the finished clip** (`../film-edit/SKILL.md`),
positioned so they read as part of the frame. The ban and the wanted text
are not in conflict: the ban stops the model inventing lettering, and the
layer supplies the lettering the film actually wants, clean.
An earlier version of this note said to name the exact string on the
*Visible* line and let the model render it. That was wrong, and the
practitioner evidence is explicit — numbers rendered into a generated shot
come back glitched, so they are typed out separately and laid over the clip
afterwards, where nobody can tell they were not always there
(`research/ai-video-bootcamp/ANALYSIS.md` §9).
**Why the lettering ban is worth its own words.** The video prompt has
carried the handbook's no-subtitles line on every generation for some time
(`references/PROMPT-BLOCKS.md`, item 7). The still that every one of those
videos is
built from carried no equivalent, so a model was free to invent signage,
labels and shopfront text in the picture, and the video then faithfully
reproduced whatever it invented. This is the same shape as the medium guard
above: a rule that held one end of the pipeline and went silent at the
other. What it is aimed at is **invented** lettering — the garbled pseudo-text
a model reaches for when it has to fill a sign it was never told about — and
not at text the film actually wants, which is why it has the two exceptions
above. That failure is not hypothetical: **the run QC below already rejects
"random pseudo-text" as an artifact**, beside hands and teeth. We were
catching it after a video had been paid for and rejecting the take; this
catches it one step earlier, in the picture the take is built from.
**The wide is the authored source picture.** Its compiler input carries
the locked medium, skin treatment, lettering constraints and all three
`space` planes. Its opening crop inherits those pixels. The map uses the
checked wide as its reference and the compiler's map template. Preserve
each compiler result's `negativePrompt` and matching `promptToken`.
Attached: the identity view **and** the wardrobe view of every present
character — both, always (rule 7, `../film/SKILL.md`) — and, for a real
place, the user's photographs of it. **Nothing else**: no room map, no prop
plate, no extra still. On 2026-09-08 five references went into a two-shot
and the faces were outvoted; the roll that passed carried the faces only. A
prop is named in words with its count on the *Visible* line (*"one flask,
on a cross-body strap"*). The handbook writes 16:9 or 9:16 here; ours is
the film's ratio — the one substitution. Recorded on the scene as
`pictures.scene`. **Looked at as soon as the plan lands**: each face
against its identity view on the preview URL (`film` rule 4);
a wide with one wrong face is regenerated, and its cut and map with it —
on 2026-09-08 three derived frames inherited one wrong face. **Two failures on faces in a row change
the reference set or the model, never a third roll of the same call.**
2. **The wide — generated FIRST since 2026-09-23**, from the cast's views and
item 1's craft, at the film's ratio and 4K.
`pictures.wide`.
3. **The room map — only when the scene needs one (2026-09-09)**: an
interior, or any scene whose cards cut between two or more walls behind the
people; a single outdoor place with one background gets no map, its wide is
the geography (two of three maps came back wrong on 2026-09-08 for a square
that needed none). When needed, from the wide — the handbook's *location
sheet*. Its prompt asks for a top-down view of the place in the photo with
every corner and side visible, no people in it, each side lettered A to D
clockwise from north, the colour and realism of the source kept, 1:1.
`picsart_film_compile_prompt` pastes it (a typo in the handbook's own
wording, "one" for "on", is corrected there, once). Attached: the wide. **One map per place and time of day**,
made from the first scene played there and reused by every later scene at
that place — the handbook makes one per scene; one per place is what keeps
the walls the same across scenes, and it is ours, deliberately. When the map
lands, read it and write its four sides into the location map (the geography line):
*"Side A — the shelving wall; Side B — the roller door; …"*. Recorded on the
location as its `map` view.
**Left and right are read off the scene picture, not off the map
(2026-09-09).** Who is frame-left and who is frame-right in the scene
picture goes into the geography line, and the sides never change inside a
scene (`references/SEAMS.md`, screen direction). The map says which wall is
behind each face — **the background side is the wall behind the face of the
person facing the camera**, read off the map, never copied from an example.
On 2026-09-08 a reverse was written with Nen's shoulder frame-right while
the master had her frame-left, and cost a round. **What a reverse changes**:
whose back is in the foreground, the background wall, and the pointing hand
becomes the other hand — say it in the shot block (*"Subject #2 hand
pointing should be the other hand"*), because the model confuses hands
across a reverse.
**Check each picture against the one before it as results land** — with
`picsart_view_image` on the preview URL (`film` rule 4), beside
showing it (`film-assets`, *Show it the moment it lands*) — the same faces as the
identity views, the same grain and colour, the same room — and re-dispatch on
drift. No picture becomes a start frame or a reference until its check is
back. On the
wide, the handbook's questions: did the room stay the same room; did the
characters keep their left and right; is anyone looking at the camera.
**When a picture comes back wrong, read it back to the line that made it
(2026-09-13).** The rule above says how many times to try — two failures on
faces in a row change the reference set or the model, never a third roll of the
same call. It does not say *what to change*, so a picture that came back plastic
and a picture that came back generic have been getting the same treatment: the
same prompt, rolled again. Every roll is a charged generation. Read the defect
back to the line of the thirteen that owns it, change that line, and only then
re-dispatch.
| What came back | The line that owns it | What to change |
|---|---|---|
| the person could be anyone; the face is not theirs | `Subject description`, and the attachments | the exclusive tell is missing or is not exclusive; or the identity and wardrobe views were not both attached (rule 7) |
| the whole frame reads as a render; skin is plastic | `Visual tone`, and `negativePrompt` | check the skin clause and the medium line are on line one **verbatim**, and that the ban field was actually filled. If both were there, this is not a wording problem — it is the reference set or the model |
| the place is a stock backdrop; it is nowhere in particular | `Setting` | thin setting line, or the location's anchor object was never named — a place without its anchor is "somewhere", and somewhere drifts |
| the people look pasted onto the background | `Foreground, Midground, Background elements` | a plane was left unnamed — most often the near one. This is the defect that line exists to prevent |
| the frame is inert; everyone is centred | `Positioning in the frame`, `Composition` | no placement was given, or the frame needed organising and the composition slot was left empty |
| invented lettering, garbled signs and labels | `negativePrompt` | the lettering ban was not added — and check it was not added to a room map, where it destroys the artifact |
| something the shot needs is simply absent | the whole prompt | it is overloaded. **Cut, do not add** — the model drops what it cannot fit, and another clause makes it worse |
| a prop is missing or there are two of it | `Visible / Not visible` | props are named there with their count, and every prop needs its plate |
**Two things this table deliberately does not do.**
- **It does not authorise more rolls.** It sits *inside* the two-failure cap, not
beside it: it is how you spend the second attempt well. A third roll of a
changed prompt is still a change of the reference set or the model.
- **It says nothing about where in the prompt a line sits.** The course argues
both sides — one lesson says move an ignored detail closer to the *beginning*,
its colour cheat-sheet says the model weights the *end* — and demonstrates
neither. The thirteen lines stay in the handbook's order.
**One row the course would add, and we do not have.** Its own answer to the
plastic-render row is that the light has no named source, and its fix is a
lighting instruction in the picture prompt. We have no lighting line here by
decision (2026-09-11), so the row above names the levers we actually own
instead. Do not re-raise it unopened
(`research/ai-video-bootcamp/ANALYSIS.md` §4.12).
**Adapted from the Skool course's prompt-diagnosis checklist and mapped onto our
thirteen lines; not measured here** (`research/ai-video-bootcamp/ANALYSIS.md`
§10.4). It changes no field and costs no call.
**One board for every scene's pictures at once** (user's choice, 2026-09-08,
as the cast board): `picsart_asset_review`, split past 12 tiles, one tile per
picture — `tag` the scene and the picture (`sc03 · scene picture`, `sc03 · OTS
over @cal`, `@garage · map`), `prompt` the picture's prompt, `info` the cuts it
serves, one `judge` line: scene picture *"the scene as the card designs it —
these faces, this room, real."*; wide *"the same room, the people small and
far."*; map *"the room from above, four sides labelled, nobody in it."*. Feedback per
`../film/references/WIDGET-FEEDBACK.md`: `approved[]` and `changes[]`, nothing
decided by silence. **A change repairs that picture and triggers an impact check
of its dependents** (`../film-assets/references/ASSET-EFFICIENCY.md`). Rebuild
only images whose required content became invalid: a facial-expression correction
does not remake an unchanged room map.
Geometry or lighting changes can affect many views; inspect rather than assume
reuse. Record the reuse/repair decision and source versions. Approved pictures are saved with the scene
(`film.json.scenes[].pictures`, the URLs the save hands back) and are what the
run carries; the map and the wide are the location's views
(`../film-assets/references/ASSET-SHEETS.md`, *The location*), saved through
`picsart_save_asset` as its row. Two adjacent cuts never open on the same
picture (`references/SEAMS.md`).
**The animatic stays on request** — *"let me see it as stills first"*: the
scene pictures cut in order at each shot's `sec` — a montage bootstrapped
with each picture as a clip (`content.asset.type: "image"`, `duration` = the
shot's `sec`) and opened as `scene` in `picsart_scene_editor` — played at the
film's real length, so the ±10% runtime gate is checked against the reply's
`duration` before anything renders; ask them to watch it once without stopping — playing finds pacing,
scrubbing finds frames. Rendering it to a file is charged and almost never
needed.
**Dialogue durations come from the words, not from a pre-generated line.** A
line's `sec` is its word count at ~2.5 words per second plus the audio line's one
second of silence, snapped to nothing — no line is generated to be measured
(retired 2026-09-04: the model treats a cut time as a share of running time, not
a frame-accurate mark, so the precision was never real). The run's total snaps
to what the model offers; the shots inside it keep their estimates.
**An `END FRAME` stays an editorial tool, on request, per run** — a second
composed image the run arrives on, for a designed transformation or a match cut
into the next run; generated FROM the scene picture (image-to-image), never rolled
fresh, and never on a held look or a line delivered in stillness, where you want
life rather than interpolation.
**Scene-level changes propagate by content.** A weather, light, or time-of-day
change updates the SCENE entity once and recompiles affected headers. Check its
picture dependencies under `ASSET-EFFICIENCY.md`; remake views whose required
illumination/state changed, not every file solely because it shares a scene ID.
Do not retain a reference whose pixels contradict the new state.
## Step 4 — one run before the rest
**With the shot list approved, the sheets locked and the scenes' pictures
approved, buy ONE run before dispatching the rest.** Not a sample of the batch — a test of the path. It answers, for the
price of a single generation, what a whole-film dispatch would answer
expensively and all at once: does the video path work end to end on this
deployment, does the chosen model hold the locked identity across its own cuts,
does it make the cuts it was told to (count and approximate times), does
lip-sync land on a spoken line, and is the recipe (model, resolution, run
length, the reference order, block order, how the cut list is phrased)
worth saving and reusing.
- **On a film that fits one run, the test run IS the film.** There is nothing
to hold back; buy it with care, judge it on the board, and the "recipe" you
save is the film's own prompt. On a longer film, pick the riskiest run — the
one with a *line* in it and the most cuts, since lip-sync and the cut count
are the two variables with the most ways to be wrong — never a throwaway.
- **Say the arithmetic once, in credits, not in theory**: "the film is one run
at ~120; a re-roll costs the same again" — or, on a longer film, "one run at
~100 instead of the whole film at ~400 — if it holds, the rest go out in one
batch." Then ask, and wait for the yes — the plan is yours, the purchase is
theirs. *(Amended 2026-09-07: this line used to end "that is a plan, not a
permission question; run it", which is how runs went out unquoted.)*
- **Then the conveyor.** A pass unblocks the whole batch — which is quoted and
confirmed like any other dispatch; a fail has cost one
run, and what it teaches (wrong model, a cut the model will not make, a
header it ignores, a descriptor too loose in motion) applies to every run
before any of them are bought.
- **This is not the "quick test shot" in *Traps*.** That one is a test *before
the assets lock*, which is the gate itself. This is after the lock — the last
cheap question before the expensive pass.
Save the winning recipe in `film.json`, per the handbook's own step for
this ("Generation tests: choose model/method per shot; save recipes"), and reuse
it for the batch rather than re-deciding per shot.
## Step 5 — iterations: edit, extend, or re-roll
For a note about the join between clips, route first to
`../film-edit/references/JOIN-REPAIR.md`. Its diagnosis may select a deterministic
edit or a separate connecting insert; the model-routing table below is not a
reason to regenerate accepted footage. Run the prompt-verify step before
dispatching the selected generative repair.
**The note's meaning is the route, and the route is a model call — never a
regeneration by reflex.** A note arrives with a selection — a stretch marked
on the scene editor's timeline (`scene_editor_feedback.timelineComments`, with
its seconds), a pin on a clip (`comments`, with its `layerId`), or a sentence in
chat about a shot — and the two together say
which of three things is being asked. Derive it; do not wait for the word
"edit" or "extend":
| What was selected + what the note asks | It means | The call |
|---|---|---|
| a **stretch** or a clip, and the note is about **how what is there plays** — *"make this more dynamic"*, *"he should look angrier here"*, *"slower"*, *"the mug should be white"*, *"the last 10 seconds are wrong"* | change what exists, inside its seconds | **edit** |
| a clip, and the note asks for **something that has not happened yet** and needs seconds the clip does not have — *"in this scene the copter must land"* when the clip ends with it still in the air, *"let him finish the sentence"*, *"hold on her a beat longer"* | continue the clip | **extend** |
| a clip, and the note asks for the event **instead of** what is there in the same seconds — *"the copter should land here, not hover"* | change what exists | **edit** |
| a note about the **whole run** — light, cast, the cut count — or the words *regenerate / redo / new take* | a different take | **re-roll** |
The test between the first two rows: **does the note ask for something after
the clip's last frame, or in place of what the frames show?** After → extend;
in place → edit. A range selection is almost always an edit (they marked *this*
stretch); a clicked clip with a new event is almost always an extend.
**When the intent is clear, go — no confirmation.** Asking "did you mean edit
or extend?" on a note that already says which is the ceremony this pipeline
keeps removing. **Ask only when the note genuinely reads both ways** — *"make
the ending better"* on a whole clip could be either — and then one short
question naming the two readings in the user's own terms (*"change how the
landing plays, or add the landing after what's there?"*), then the call. Never
two questions, never a menu of models.
The three calls:
| The user says | The call | What goes in |
|---|---|---|
| **edit · change · fix · replace · remove · "the last 10 seconds are wrong"** — anything about what is *in* the clip | **the edit sibling (`shoot.editModel`)** | `videoUrl` = the clip (the run's file, or the piece the shot lives in); `prompt` = the change and *only* the change, naming the shot and its seconds; `imageUrls` = the same numbered views and frames the run had, so identity does not move; `generateAudio` as the run had it |
| **extend · expand · longer · continue · "add a beat at the end"** — anything about *more* clip | **the extend sibling (`shoot.extendModel`)** | `videoUrls` = [the clip]; `prompt` = what happens in the added seconds, written as one more cut header (positions restated, the same references named by number); `duration` per the model's own definition — read `picsart_model_params` and preflight before the first use, and record which it is |
| **regenerate · redo · new take · "roll it again"** — or a note about the whole run: light, cast, the cut count | **a fresh roll of the run** | one header or block changed, the rest byte-identical; it costs the run, said in credits before it goes, and every other shot comes back different — a fresh roll is a fresh roll |
### Extend input gate — probe before preflight (measured 2026-09-12)
The live Seedance 2.5 extend path exposed provider checks that
`picsart_preflight` did not catch. Before dispatching that sibling, probe every
distinct input video and enforce both limits yourself:
- every input video is at least **1.8 seconds** long;
- the **sum of all input-video durations is at most 30.2 seconds**.
These are observations from the current `dreamina-seedance-2-5` r2v worker, not
timeless catalog doctrine: read `picsart_model_params` first and treat a newer
live schema or provider diagnostic as authoritative. Preflight still runs after
this gate for payload validity and price, but a green preflight alone is not
evidence that these two duration checks pass.
For a two-sided seam repair, never send the whole following run merely to show
the target pose. Make a deterministic excerpt of its opening, normally **2.0
seconds**: `picsart_media_apply_scene_template` with `mpscene://montage`, one
clip and the required trim → `picsart_media_validate_scene` →
`picsart_media_export` as mp4 → probe the exported excerpt again. If the source
side plus that excerpt still exceeds the total ceiling, trim the source input to
the shortest motion-bearing tail that the model accepts; keep the original
takes untouched.
The measured extend schema accepts `videoUrls` and no `imageUrls`. Do not attach
reference pictures when the live schema omits them. On hosts whose generic
`picsart_generate` surface exposes only singular `videoUrl`, put the model's
multi-video field in `extra: { videoUrls: [...] }`; the generate tool flattens
`extra` before model validation. Pass `videoUrls` directly to
`picsart_preflight`. `duration` is the requested generated continuation, not
the sum or trim length of the source videos.
Every retry gets a fresh returned job handle. Put that exact handle on the new
render monitor row; never reopen a failed handle or let an old monitor stand in
for the retry.
**Regenerating a clip the user wanted kept is the failure this section exists
for.** A selected clip with the note "expand" was answered with a new prompt
and a fresh roll (reported 2026-09-04): the footage they liked was gone and a
run's price was paid for a beat's worth of new seconds. The note said what to
do; the selection said where; nothing in it asked for a new take.
**What each call must carry so nothing breaks:**
- **The same references, the same numbers.** `imageUrls` for an edit is the
run's list verbatim — same sheets, same order, same roles in the prompt — so
the edited clip's faces are anchored by the same pixels the run was. Never a
fresh selection, never a re-ordering.
- **Verbatim is the floor, not the ceiling: an edit that opens the frame up
needs the place's pictures ADDED (2026-09-10).** The run's list anchors what
the clip already showed. The moment the edit changes what is *visible* — a
pull-back, a wider reframe, a camera move that reveals a skyline, a street, a
far wall — the newly revealed area is anchored by nothing, and the model
invents it. So before an edit like that goes out, ask what the new framing
will show that the old one did not, and put the **map and the wide** of that
place in `imageUrls` (appended, so the existing numbers do not move) with the
geography line in the prompt. **The failure this is written from
(2026-09-10):** clip 3 carried only a tight frame of its setting; the map and
the wide were not in the run and so were not in the edit either; the edit
pulled back, and the skyline it revealed was a new place. Rule 10.
- **The change alone, named to the second.** An edit prompt is *"cut 3
(13.0–19.0s): the mug on the bench is white ceramic, not steel; everything
else unchanged"* — not a re-description of the shot. A re-described shot is a
re-rolled shot wearing an edit's price.
- **An extension is a header.** The added seconds are written like any cut
header of the run — positions restated, the action in beats, the line in
quotes with its silence, the references by number — because the model reads
the continuation the same way it read the run.
- **Frames as references are exported at full size** (step 6, *Frames the model
reads*); a thumbnail is rejected or anchors a soft frame.
- **Preflight, quote, then wait.** Each sibling has its own rate; the number
goes to the user before the call and the call waits for the yes. A repair is
a purchase like any other.
**After the call:** a focused join candidate stays separate from the accepted
cut and follows `../film-edit/references/JOIN-REPAIR.md`'s comparison workflow.
Otherwise, the result goes into the cut and the whole cut goes back into
`picsart_scene_editor`, with one line naming the stretch that changed; an edit
replaces the clip's
url in `runs[].pieces` (the shots re-point to it, trims re-derived by the user
only), an extension appends a piece. Split the result at its actual cuts before
anyone judges it — an edit that changed the cut count is a failed take like any
other. Log which call it was, with its prompt and rate.
**Rules that hold across all three:**
- One change per call: one thing edited, one beat extended, one header
re-rolled. Two changes at once and you will not know which one worked.
- **Log every generation**: run or piece, which call, prompt version, what
changed, result URL, verdict per cut. `film.json` runs carry `promptVersion`,
`takes`, `editPasses`, `extends` and `pieces`; the prose log lives in
`docs/log.md` when there is a disk.
- A clip that will not take an edit in **two** tries, or a run that will not
land in **four or five** rolls, has a wording problem exactly never. Simplify
the header that keeps failing: drop an action, change the angle, lengthen
the beat.
## Step 6 — select and accept takes
**The board opens on the run as delivered — split at its cuts, untrimmed.**
When the batch lands, **split every run's take at its delivered cuts**: look at
the frames either side of each declared time (`picsart_media_contact_sheet`, or
the scene editor's own playhead), place a compositor split where the picture
actually changed, write the result to `runs[].cutTimesActual`, and treat a cut
count that disagrees with the cut list as a failed take before anything else is
judged. The split is bookkeeping over one source file and costs nothing; it is
what makes every shot of the run a clip again. Then open the board on exactly
that: every shot a cell bounded by the model's cut, no trims derived, nothing
shaved. **The automatic rough cut is off (2026-09-04)** — the model already made
the cuts, and a video edge is joined by the handbook's angle change
(`references/SEAMS.md`), so there is nothing to align;
`film-edit` keeps what the pass did and why it is parked. Trims are the user's,
made in the scene editor, and land as `trim` with `trimSource: "user"`. With
several takes competing for a run, you pick the stronger, splice it in and name
the other in a clause (below): the scene is one timeline and cannot hold two
versions of the same shot. Say nothing about cutting
before the board opens — there was no cut; say what came back, and open it.
### A batch that lands opens a board. Every time, without being asked.
**Generations coming back IS the trigger** — not the user asking to see them,
not the takes being good, not the batch being small. First pass, retake, single
shot, a re-roll after a model swap: material arrived, so a board opens in that
same turn. There is no state of the world in which the right response to a
finished generation is a paragraph about it.
This is a reported failure, not a hypothetical. Four takes came back; the reply
read *"1A, 2A, and 3A all check out clean on Seedance — matching their beats, no
issues. Only 4A still needs work"*, then offered a choice between a stronger
prompt and splitting the shot. No board was opened. The user's next message was
*"Why don't you open view review widget?"* — and by then they had been told
three of their four shots were fine without having seen a single frame of any of
them. Three separate rules broke at once:
- **The board never opened**, so nothing was reviewable.
- **The verdict was self-certified in prose.** "Matching their beats, no issues"
is a taste verdict on material the user has not watched. It is the same class
as the asset-sheet failure in `film-assets` ("never self-certify identity in
prose while the user has seen none of the frames"), and it is worse here,
because a take is what they are paying for. **You may say what you observed;
you may not say it passed.** "4A drifts the same way on a third model" is an
observation and belongs in the message. "1A, 2A and 3A check out clean" is an
approval, and approval is theirs.
- **The turn ended on a menu.** Two craft options were offered as a question
when the pipeline already answers it: a third take drifting the same way on a
second model is not a model problem and not a wording problem — step 5's rule
is that a shot which will not land is *simplified*, split in two or reduced to
one action. Do that, say you did it, and put it on the board. A question is
for a decision that is genuinely the user's; "which of these two repairs
should I try" is your job.
So the shape of that turn should have been: open the board with all four takes,
say in one line that 4A drifts toward calm on a third model and is being split
rather than re-worded, and let them verdict the other three themselves.
Review takes in **one `picsart_scene_editor` that carries the whole film,
by default** (rule 8, `../film/SKILL.md`). Focused join comparisons follow
`../film-edit/references/JOIN-REPAIR.md` instead, without promoting their preview
to the accepted cut. For ordinary review, not the batch that was just
dispatched — the film: every accepted take plus the new one, in playback order,
bootstrapped into one montage scene (`../film-edit/references/ASSEMBLY.md`) and
passed as `scene`. Two accepted videos and a third just delivered is a scene of
three, the new one in its story position. `videoUrl` is for a film that has
exactly one video and nothing else to play beside it.
On a run the scene's clips are the run's cuts, so a comment maps straight back
to the header that produced it — by the pin's `layerId`, or by its time
(`../film/references/REVIEW-FEEDBACK.md`, *Mapping a comment back to a shot*).
The editor carries no prompt or model, so keep that link in `film.json`. The
scene is **one** timeline, and that timeline is the film.
**Never one view per take**: three takes on three boards means three separate sends, and the
first send moves the conversation forward while the other two boards die
unanswered — the documented flunky-confirmation failure. One board, one send,
verdicts for the whole batch. The same rule covers the editor's own edits: when
the user trims or splits in it, that cut is theirs and already seen — record it
from the returned `document` and say so, never an editor per piece
(`film-edit`). If several boards are ever genuinely open at
once, one board's feedback is one item of the queue: act on it, return to the
queue, and advance nothing until the queue is empty or the user says move on.
**Every retake is seen before it becomes the cut — and the surface it goes on is
the scene editor (2026-09-07).** `picsart_video_compare` is out of this
flow: one surface judges picture. What survives from the old compare rule is the
part that mattered — the user sees **every** retake, not just the first, and
nothing becomes the cut behind their back. The failure above ran a shot through
two models and a third generation without the user seeing any of them, which is
how "still needs work" became something only I knew.
- **A retake goes INTO the cut, and the cut goes up.** Swap the new take in,
rebuild the scene, open the editor on the whole thing, and say in one line
what changed. Two versions of one shot are never both in the scene: it is the
timeline, so they would lay out end to end as two different shots of twice the
real length, with no way to say which wins.
This ordinary-review rule does not forbid explicitly labelled join comparison
previews under `JOIN-REPAIR.md`; those are not the accepted movie timeline.
- **With two takes of one shot in hand, you pick — and say so.** Which of two
candidates is stronger is a craft call, like which repair to try; make it,
splice it in, and name the other in a clause: it is in the log, one word away.
Asking the user to choose blind between two files is the old compare board's
job, and it is gone.
- **An edit or extend return is the same path** — into the cut, the whole cut
back on the board, one line naming the seconds that changed. That is where an
edit which fixed the hand and lost the light actually shows.
- **Going back stays free.** Every superseded url stays in the log, so "use the
first one" is one call and no credits. That is the honest replacement for a
lockstep A/B: the comparison happens in sequence, inside the cut, and the old
take is a word away.
- **A re-rolled run** replaces the run's take the same way: the new take split
at its own cuts, its shots as the scene's clips, and one line on what you
changed between the takes.
- If a shot is on its third attempt, say the attempts are converging on nothing
and that the shot needs splitting. The board is where that gets said.
Contract in `../film/references/REVIEW-FEEDBACK.md`.
**Frames the model reads are exported at full size, never thumbnailed
(2026-09-04).** `picsart_media_contact_sheet` renders thumbnails — 480 px wide
by default — for *looking*; fed to the model as a frame, one came back 480×270
and Seedance rejected it (it refuses a picture with **either side** under 300 px
— width counts as much as height — and a small frame that is accepted anchors a
small, soft composition). A frame that will
travel in `imageUrls` is extracted with `picsart_media_export`: a one-layer
scene of the run, `mediaType: "png"`, `startTime` at the wanted second, at the
run's native size (`picsart_media_probe_media` the run first for width, height
and fps). Then **probe the exported frame**: if its width or its height is below the
run's, you have a thumbnail — stop and re-extract; **and neither side may be
under 300 px**, which is the check a 252-px-wide crop got past on 2026-09-09. It is an export (a render wait, a
Drive file, and it counts against the reference byte budget), and it is the
only way a frame from a take becomes a `START FRAME`, `END FRAME` or `FRAME
REFERENCE`.
**Kept frames are anchors, not notes.** The scene editor has no keep-frame
button: a pin whose `instruction` asks to keep what is on screen (*"keep this
face"*, *"this frame is right"*) is a kept frame at its `time` — a second on
the scene's timeline, so map it to the take's own second first
(`../film/references/REVIEW-FEEDBACK.md`). Each one survives pixel-for-pixel:
export that frame
from the take at native size (above — never a re-render, never a thumbnail) and
feed it back. On a run it
goes into the re-roll's `imageUrls` labelled as that cut's frame (*"IMAGE 9 —
FRAME REFERENCE for cut 3: shot 3 as approved, hold this face and this
framing"*), named in the references header and in that cut's header, or as the identity
reference for an edit pass on that stretch; two kept frames in one cut label as
its opening and closing frames. A user who wants a clean rebuild says so, or
removes the pin before sending: if a keep pin is there, honour it. Kept frames
can also ride on an approved cut, where they are simply on the record for
whatever gets regenerated later.
**When the face is right but the shot is wrong, keep the frame.** Do not throw
away an identity the model just got right: save the best frame of that take and
carry it into the re-roll as that cut's labelled `FRAME REFERENCE`, with the
header's motion rewritten and nothing else — the action, the camera, the
progression, and nothing that re-describes what the frame already shows. This
is the handbook's own frame-reuse technique, and it is also how a good frame
from one shot becomes the `FRAME REFERENCE` of a later one.
**When a run changes a place, its frames become the next run's pictures of
that place — automatically (2026-09-08, the handbook's continuity rule).** The
written prompt cannot carry state: a room wrecked in run A, a character covered
in dust, exists only in run A's frames, and the approved scene pictures now
show a clean room that *fights* them. So: the story says where the
story changes a place (the fire, the fight, the flood); every later run at that
place is **dependent** and waits for run A's accepted take, and every other run
dispatches together as now. When run A's take is accepted, pull the frames
without a stop: list every angle the dependent run will see; for each,
`picsart_media_contact_sheet` at the times of run A's last beat on that angle
(up to eight thumbnails, free) and pick the frame that is sharp, mid-action
where the next run continues the movement, and shows the place in its new
state; export each pick at native size (`picsart_media_export`, above) and
probe it. **One frame per angle** — a frame is one camera angle and carries the
state of the scene, not the geography of the room; an angle with no usable
frame means run A holds that angle for a beat (an extend) or the dependent run
is not ready. The exported frames **replace** that place's pictures for the
dependent run — scene picture, and the map when the room's shape
changed (a new map from the widest frame with the handbook's map prompt) —
never attached beside them: two versions of one room is exactly the
contradiction the rule removes. **The same for a person the earlier run
changed**: the frame that shows the state becomes that person's state view and
replaces their wardrobe view in the dependent run (rule 7, 2026-09-10) — a
clean coat beside a torn one is the same contradiction. Record them as `pictures.<state>` on the scene,
name them in the `notes` line when run A's scene opens in the scene editor so
the user sees which were chosen and can swap one, and dispatch the dependent run — its charge was quoted
with run A's in one batch and approved once, so nothing waits on a second yes.
A take is accepted against the checklist, not vibes:
- Characters and location match their references — face, costume, space.
- No artifacts: hands, teeth, extra fingers, drifting objects, random pseudo-text.
- **Every declared cut landed as a cut** — the right count, each near its
time, a hard cut and not a whip pan, a morph or a dissolve. A run that made
the wrong cuts is rejected whole, whatever else it got right: its shot
boundaries are not where the plan says, so nothing downstream lines up.
- Camera movement is what the shotlist ordered. **When the camera is wrong, it
is a camera-change retake — and an ANCHORED one.** Swap exactly the move
preset (one block-7 recompile of that shot's header) and never re-prompt the
whole shot over a camera verdict. On a run this is a re-roll with one header
changed — a camera move is motion, which an edit pass does not change — and
the anchoring is the same numbered references, so nothing else in the call
moves.
- The order arrives as a comment that asks for a different camera move and
nothing else. The editor has no preset panel, so read the words; a move
named in them is the shotlist board's own vocabulary, so it recompiles to
exactly one block.
- **Anchor it.** Take a frame from the start of that shot's source (the
commented clip's source url) and
send it as a *reference image* beside the shot's locked asset references —
all of them as references together — then name the opening frame in the
prompt. Cast, wardrobe, set and light survive as pixels; only the camera
changes. Not a first-frame role (a frame role and reference images are
alternatives, and the pair is rejected after the wait), and never the old
take as a reference video (a reference video supplies camera motion, so it
reinstates the move being changed).
- A note that moves the camera **and** something else is an ordinary
regeneration — an opening-frame anchor would fight a new lighting note.
- **For a user-requested join repair, distinguish a crop from a new camera
move.** Existing-pixel reframing follows `film-edit`'s compositor guidance
after checking the live operation; it is not a generative camera change.
The old crop-path implementation was removed (2026-08-31). This
routed a dead-but-usable framing note to a crop-path push-in in the export,
free instead of a retake; the export half of crop-path was never wired up,
the code is deleted. Do not infer that all compositor crops are unavailable;
genuine new camera motion still needs a generative repair.
- The performance fits the task; the line reads; lip-sync holds. **"The line
reads" has a method** when the classic Picsart API plugin is installed:
`video-transcribe-audio` the take and diff against the scripted line — it
catches lip-sync saying the wrong words and verifies the one-second silence
tail. Without that plugin, judge by ear and say so.
- **Look INSIDE accept candidates before promoting**: a take's first frame
hides mid-clip morphs. On the takes you intend to accept (only those —
contact sheets cost render time, not generation credits), render 3–4 frames across the take
(~25/50/75%), view them in one batched `picsart_view_image` call, and check
identity and artifacts at each.
- It will cut with its neighbours: a movement written to carry across a cut
ends mid-move and is picked up; a look that answers a thing leaves frame on
the right side; the cause is shown before the answer. At a video edge, the
last shot ends in the middle of its movement and the next video's first shot
is a clearly different angle (`references/SEAMS.md`). If a join fails, inspect
whether existing footage can be recut before deciding it needs new material
(`../film-edit/references/JOIN-REPAIR.md`).
- Palette and light match the world.
Accepted: the run's URL and its `cutTimesActual` into `selects/scNN/` (and
`picsart_drive` — CDN links expire), its prompt saved as the final version,
every shot in it status `final`.
## Step 7 — run it as a conveyor
Work in scene batches, never scattered shots — a scene keeps light and continuity
in one head. A run at a place an earlier run changed is dependent and waits for
that run's frames (step 6); every other run goes out together. While scene N iterates, shotlist N+1 and hand scene N−1 to
`film-edit` for parallel assembly (that is where reshoot orders come from). Track
daily output in shots-final-per-day against the target and say so when the pace
will not make it.
Gate out (per scene block): every run's take accepted and split at its delivered
cuts · all shots `final` in selects · final prompts versioned · log complete ·
the run watched on the board at its cuts and its run edges (the ten-second
version of the edit's join QC, before problems compound).
## Costs
| Free | Charged |
|---|---|
| shotlist, shot design on the cards, run grouping, prompt assembly, preflight, splitting a delivered run at its cuts, splicing a repaired piece back, animatic review on the board when requested, the handoff frames of a changed place (contact-sheet thumbnails to choose, full-size exports to use — render time, not credits), the 1280 px check copies of every picture (`picsart_media_export`), frame exports for anchors (`picsart_media_export` — render time and a Drive file, not credits, 2026-09-07), `picsart_shotlist_board` / `picsart_scene_editor` (renders nothing) | every scene's pictures — scene picture, wide, coverage, a room map when needed (image rates, one board for all scenes), cut-point and take-QC contact-sheet frames (per frame), every draft and re-roll (`picsart_generate`, video rates — billed at the generated length, which is the reason everything upstream of this skill exists), every edit or extend call (each sibling's own rate — preflight first) |
## Traps
- Dispatching on a number the user never saw, or on a yes that covered an
earlier call. Every charged video call carries its own quote and its own yes;
the forecast is not a purchase.
- Generating a "quick test shot" for an unlocked scene. That is the gate, and it
exists because half of early material gets redone.
- Pasting a descriptor into the prompt, whole or shortened. Since 2026-09-09
the pictures carry identity and the prompt names them by number
(`references/PROMPT-BLOCKS.md`); a paragraph beside the pictures makes the
model average words and pixels.
- Dropping the geography line or the map to save tokens — characters swap
sides between shots and the scene stops cutting.
- Dispatching a prompt that points at a panel of a bigger picture. That is a
lint error, not a phrasing choice: the reference is wrong, and the crop that
fixes it is free.
- A run without its scene's pictures, or a place generated empty from its
descriptor. The handbook's order is scene first, place from it — an empty
location renders unreal, and a run without the pictures asks the model to
invent the room (2026-09-08).
- Attaching the approved scene pictures beside frames from a run that changed
the place. Two versions of one room; the frames replace the pictures.
- Cropping, mapping or using a wide before its visual check has passed.
- A third roll of the same two-shot after two failures on faces. Change the
reference set or the model.
- Iterating two variables at once. When it improves you will not know why.
- Re-submitting a generation because the call "timed out". The render survived
the severed call and already charged — poll `picsart_job_status` first,
always.
- Letting accepted takes sit in the raw pile — the editor must only ever see
selects.
- Generating a scene shot by shot out of habit. Measured worse (2026-09-03):
the run is the initial-production unit; a scoped connecting insert between
accepted clips is the repair exception, not a new production default.
- Treating the run ceiling as a reason to make one long shot. A 30s run should
usually contain several 3–8s shots; one 30s shot is a long take with its
reason on the card, not the default meaning of "one run."
- Filling the `startFrame` field on any video — a run, a five-second bridge, a
one-shot reshoot. It locks out `imageUrls`, and a frame shows only the people
in it (the 2026-09-08 bridge: one face in the frame, no picture of the other
woman, a long coat and two flasks). The start frame goes in *with* the
references, labelled `START FRAME` in the tagging header — every image
numbered with its role.
- A person in a shot block without their identity and wardrobe views in `imageUrls`, or
an object named in two places ("on her strap" and "in her hand" is two
flasks).
- A shot block that opens without its shot type and camera move. The model
guesses both (the handbook: *"Tell it clearly."*).
- A prompt that refers to the video before it — "continuing from the previous
scene", "as before", "again". The model never sees that video; write what is
in the frame now (`references/PROMPT-BLOCKS.md`, first language law).
- A contact-sheet thumbnail used as a reference, a descriptor's picture or a
start frame. Thumbnails are 480 px previews for choosing; the frame is
exported at full size first (the 2026-09-08 reshoot failed on two of them).
- Splitting a delivered run at its PLANNED cut times. The model cut near them,
not on them — split where it actually cut, or every trim downstream is off by
the drift.
- Regenerating when the note asked for a change or a continuation. "Make this
more dynamic" on a marked stretch is an edit; "the copter must land" on a
clip that ends mid-air is an extend — with or without the words *edit* and
*expand*. A regeneration in their place throws away the clip they wanted to
keep (reported 2026-09-04).
- Re-describing the whole shot in an edit prompt. An edit names the change and
the seconds, nothing else; a re-described shot is a re-roll at an edit's
price.
- Feeding the model a contact-sheet thumbnail as a frame. A frame the model
reads is exported at the run's native size and probed before it goes.
- Polishing re-roll 8 of a run whose failing header should have been simplified
at re-roll 4.
SHA-256: 50007d2715b2ac4ccd11d622575d0613353508c5d648fd98f6b5060b659c5221