DPL plan format

Specification and schemas: licence to be confirmed. The rules that do the checking run on our servers and are not published.

Source revision: ddd20338847df7d1f7922a4a8c1f5a37781716f7. Download the specification (Markdown), with internal development notes removed.

JSON Schemas

DPL plan format — dpl.plan/1

Status: first version. Last updated 18 October 2026.

A DPL plan describes a film the way a director plans it: every scene and every shot, what each is for, where the audience's attention goes, and what is heard. It is useful on its own: a crew could shoot from it, a person can read its shot list, and tools can read its shots in industry terms. It depends on nothing else in this repository. Converting a plan to other formats is done by separate tools, which this format does not depend on.

How to read this page. Section 1 is the shape of the file, with two complete plans you can copy. Section 2 goes through every part of a plan (the work and its house style, the world, the structure, the shots, the picture layers, the sound and the transitions) and says what each part is for, so you know when to use it. Section 2.10 is the short-form profile for phone and small-crew shoots. Section 3 lists the details that switch the edit-readiness checks on. Section 4 has the camera terms. Section 5 is validation and how to read its diagnostics.

1. Shape

One JSON document, UTF-8. These rules hold everywhere:

Schema. The exact members, terms and requirements are published as a JSON Schema (draft 2020-12), contracts/dpl/dpl.plan-1.schema.json; print it with dpl schema plan. It matches the reader member for member and is held to it by tests. contracts/dpl/README.md says what each schema covers and what only the validator can check. This page says what the members are for.

Reading the tables. Each object in section 2 has a table with its members in the schema's order. Type says what goes there: text, a whole number, a number, true or false, a list, another object (named in code font, and described in its own table), or one of a short list of terms. required marks a member that must be present; nothing else needs to be. Times are milliseconds unless the meaning says otherwise.

The smallest plan

One scene with one shot:

{"format": "dpl.plan/1", "work": {"id": "w", "title": "W"},
 "scenes": [{"id": "s1", "purpose": "Open.", "start_ms": 0, "end_ms": 2000,
   "shots": [{"id": "a", "purpose": "Show the door.", "subject": "A door.", "start_ms": 0, "end_ms": 2000,
              "camera": {"size": "wide", "movement": "hold"}}]}]}

A small plan to copy: two people talking

A dialogue scene with the details the edit-readiness checks look for: a line of action (axis), the people placed in every shot (staging), who speaks to whom (lines, one of them turning the scene), the job of each shot (coverage) and the set-up each is filmed from (setup). It validates with no diagnostics and dpl readiness finds nothing to report. Change the names and the words, keep the shape.

{
  "format": "dpl.plan/1",
  "work": {"id": "kitchen-short", "title": "The Kitchen", "thesis": "A marriage turns on one sentence about money.", "target_runtime_ms": 14000},
  "characters": [
    {"id": "MAYA", "description": "Maya, forties, has just learned the truth."},
    {"id": "TOM", "description": "Tom, her husband, who hid it."}
  ],
  "locations": [{"id": "KITCHEN", "description": "A small kitchen at dusk."}],
  "scenes": [
    {
      "id": "S1",
      "purpose": "Maya tells Tom what she knows; he cannot answer.",
      "change": "We know that she knows.",
      "start_ms": 0,
      "end_ms": 14000,
      "location": "KITCHEN",
      "axis": {"left": "MAYA", "right": "TOM"},
      "lines": [
        {"id": "L1", "speaker": "TOM", "to": "MAYA", "start_ms": 500, "end_ms": 2500, "text": "You're home early."},
        {"id": "L2", "speaker": "MAYA", "to": "TOM", "start_ms": 3500, "end_ms": 6500, "text": "I went to see your brother."},
        {"id": "L3", "speaker": "MAYA", "to": "TOM", "start_ms": 7500, "end_ms": 10000, "turn": true, "text": "He told me about the money."},
        {"id": "L4", "speaker": "TOM", "to": "MAYA", "start_ms": 12000, "end_ms": 13500, "text": "It's not what you think."}
      ],
      "shots": [
        {
          "id": "K1", "purpose": "Where they are: Maya at the door, Tom at the sink.", "subject": "KITCHEN",
          "start_ms": 0, "end_ms": 3000, "camera": {"size": "wide", "movement": "hold"}, "source": "footage",
          "characters": ["MAYA", "TOM"],
          "coverage": {"role": "establishing", "priority": "must"},
          "staging": [
            {"subject": "MAYA", "side": "left", "facing": "right"},
            {"subject": "TOM", "side": "right", "facing": "left"}
          ],
          "setup": "A"
        },
        {
          "id": "K2", "purpose": "Maya, as she says where she has been.", "subject": "MAYA",
          "start_ms": 3000, "end_ms": 7000, "camera": {"size": "medium", "movement": "hold"}, "source": "footage",
          "characters": ["MAYA"],
          "coverage": {"role": "single", "priority": "should"},
          "staging": [{"subject": "MAYA", "side": "left", "facing": "right"}],
          "setup": "B"
        },
        {
          "id": "K3", "purpose": "Tom takes it in.", "subject": "TOM",
          "start_ms": 7000, "end_ms": 9000, "camera": {"size": "medium", "movement": "hold"}, "source": "footage",
          "characters": ["TOM"],
          "coverage": {"role": "single", "priority": "should"},
          "staging": [{"subject": "TOM", "side": "right", "facing": "left"}],
          "setup": "C"
        },
        {
          "id": "K4", "purpose": "Maya says the sentence the scene turns on.", "subject": "MAYA",
          "start_ms": 9000, "end_ms": 11000, "camera": {"size": "medium_close_up", "movement": "push_in"}, "source": "footage",
          "characters": ["MAYA"],
          "coverage": {"role": "single", "priority": "must"},
          "staging": [{"subject": "MAYA", "side": "left", "facing": "right"}],
          "setup": "D"
        },
        {
          "id": "K5", "purpose": "Tom's face as it lands: he has no answer.", "subject": "TOM",
          "start_ms": 11000, "end_ms": 14000, "camera": {"size": "close_up", "movement": "hold"}, "source": "footage",
          "characters": ["TOM"],
          "coverage": {"role": "reaction", "priority": "must"},
          "staging": [{"subject": "TOM", "side": "right", "facing": "left"}],
          "setup": "C2"
        }
      ]
    }
  ]
}

Larger complete plans are in tests/corpus/ (a kitchen scene with a broken glass, a rooftop chase, a waking scene) and the fixture tests/contract/VideoEditor.Dpl.Plan.Tests/Fixtures/the-beacon.dpl.plan.json.

Examples below that are not complete plans are fragments: each is marked with the place it belongs, such as scenes[0].shots[0]. They are checked against that part of the schema by a test, so a term or member that is wrong in an example fails the build.

The top level

Plan (the plan itself)

Member Type Meaning
format required "dpl.plan/1" Always "dpl.plan/1". Any other text is DPL-FORMAT.
work required Work The film's identity and intent. See "The work".
characters list of Character The people (or beings) the story needs. Shots, lines and staging name them by id.
locations list of Location The places the scenes happen in. A scene names one.
props list of Prop Objects the story depends on (the lamp that must be relit). Naming them lets the checks follow them from shot to shot.
continuity_rules list of ContinuityRule Rules the picture must keep across the film (a rule of light, a costume). Shots cite them by id.
must_not list of text Things the whole film must never show or do, as plain sentences. A shot has its own must_not too.
sequences list of Sequence Optional grouping of scenes into larger movements of the story, each with its own direction.
journey Journey Where the whole film travels, for the scenes no sequence's own journey governs.
none list of Absence What the whole film deliberately does not have, said outright: today journey (the camera travels nowhere). See "Saying no".
scenes required list of Scene The film, in time order. Each scene says what it is for and holds its shots. At least one scene is needed.
transitions list of Transition Joins between shots that were decided on purpose. A join that is not listed is an unremarked cut.
sound Sound Everything heard: carriers, spoken lines, and how they sit together over film time.
delivery Delivery Short-form profile: the picture shape and runtime limit the work is delivered in. See 2.10.
kit Kit Short-form profile: the cameras, supports, sound gear and lights the crew has.
people list of Person Short-form profile: the cast and crew, their roles and when they are there.
schedule Schedule Short-form profile: the shoot days.
slice_of SliceOf Present only on a slice that dpl slice cut from a larger plan. See "Slices".

2. What each part is for

2.1 The work

work is the film's identity and intent. Give it a thesis (what the film argues or makes the audience feel), so each scene can be asked what it does for that. Give target_runtime_ms and the validator warns when the scenes do not add up to it. design_notes, approach and quality_floor are for the director's own reasoning and the bar the finished film must clear; they are read by people and by review, not by the edit checks.

Work (work)

Member Type Meaning
id required text A short id for the film. Findings and exported files carry it.
title required text The film's title.
house_style HouseStyle The film's look, rhythm and mix targets. See "House style".
thesis text What the film argues or makes the audience feel, in one or two sentences. Say it, so each scene can be asked whether it serves it.
target_runtime_ms whole number The planned length. If the scenes end at some other time, DPL-RUNTIME warns. Must be above 0.
approach text How the plan approaches the film: its method, not its content.
design_notes list of DesignNote Choices made on purpose, each against what an ordinary plan would do.
quality_floor list of text The minimum the finished film must achieve, whatever else changes, as plain sentences.
motion_share number The share of screen time (0 to 1) that should be in motion: recorded or generated video, not a camera move across a still. Less than this gives DPL-MOTION.
motion_counts_animation true or false Whether animation counts toward motion_share (a diagram while it evolves, a layer drifting). Absent means video only. Say true for a film that moves by drawing.
profile one of film, short What kind of plan this is: film (the default, and every plan written before the short-form profile) or short, which opts in to the short-form rules about kit, people, light and the shoot day (2.10).

DesignNote (work.design_notes[])

Member Type Meaning
id required text A short unique id.
problem required text The problem the choice answers.
choice required text What the plan does about it, against what an ordinary plan would do.
outcome text What came of it, once known.

2.2 House style

work.house_style holds the choices that belong to the whole film rather than to a scene: how its constructs look, how tightly picture follows the words, what structure it opts into, and how it is mixed. Every part is optional. A part you leave out switches its checks to report only.

HouseStyle (work.house_style)

Member Type Meaning
map text The film's map look, in plain words, for people and for picture briefs. The colours a renderer applies are in map_palette.
highlight text The look of a highlight over a document, in plain words.
chapter_card text The look of a chapter card, in plain words.
map_palette MapConstructStyle Map colours and named places the pictures can use.
highlight_palette HighlightConstructStyle Colours of the highlight drawn over a page.
chapter_palette ChapterConstructStyle Colours, type and timing of chapter cards.
drawing_sounds DrawingSoundStyle The paper-and-pencil sounds that go with drawn constructs (highlight, circle, route and so on).
presenter PresenterStyle The on-screen presenter's identity and the longest the audience goes without seeing them.
timing TimingStyle Picture rhythm targets: how closely cuts follow the words, and how long shots run.
structure StructureStyle Opt-ins for a cold open, a sponsor spot, a subscribe prompt and an end card.
sound SoundTargetStyle Mix targets: how far the bed sits under the voice, loudness, how many cut effects.
readiness ReadinessStyle Where this film's craft differs from the usual conventions the readiness checks start from (how long an insert, reaction, cutaway or neutral shot may be held).

Constructs and colours. map, highlight and chapter_card describe the film's map, highlight and chapter card in plain words. The structured palettes are optional beside them. Colours are CSS hex strings. These fields travel with the realisation document. A bound picture may override the drawing sounds with drawing_sound: false, or a drawing_sound object with enabled, per-kind switches and gain_db. Bindings provide the page image and normalised highlight rectangles, map vector polygons and place pin assets, split-screen pane assets and quoted text. bindings.word_timing carries eil.words/1 when a construct follows spoken words. A new engine release is required before production films can render these constructs.

MapConstructStyle (work.house_style.map_palette)

Member Type Meaning
sea text; default "#102938" Sea colour (CSS hex).
land text; default "#d3c5a7" Land colour (CSS hex).
border text; default "#61747a" Border line colour (CSS hex).
label text; default "#ffffff" Place-name text colour (CSS hex).
accent text; default "#e4b75e" The accent colour (CSS hex).
highlight text; default "#e4b75e" The colour a highlighted region takes (CSS hex).
places list of MapNamedPlace Named places with a position, reusable by every map picture in the film.

MapNamedPlace (work.house_style.map_palette.places[])

Member Type Meaning
id required text A short unique id for the place.
label required text The name shown beside the pin.
lon number; default 0 Longitude in degrees.
lat number; default 0 Latitude in degrees.
emblem text A small mark for the pin, by name. Pictures are bound to the name later.

HighlightConstructStyle (work.house_style.highlight_palette)

Member Type Meaning
colour text; default "#f4ce55" The colour of the highlight (CSS hex).
surface text; default "#253039" The colour of the surface the highlight sits on (CSS hex).

ChapterConstructStyle (work.house_style.chapter_palette)

Member Type Meaning
ground text; default "#101820" Background colour of the card (CSS hex).
accent text; default "#e4b75e" Accent colour (CSS hex).
ink text; default "#ffffff" Text colour (CSS hex).
font_family text The type family for the card. Absent means the renderer's own.
entrance_ms whole number; default 700 How long the card takes to arrive.
exit_ms whole number; default 500 How long the card takes to leave.

DrawingSoundStyle (work.house_style.drawing_sounds)

Member Type Meaning
enabled true or false; default true Whether drawn constructs make a sound at all.
gain_db number; default -18 How loud, in dB relative to the voice. A negative number sits under it.
highlight true or false; default true A sound as a highlight is drawn.
circle true or false; default true A sound as a circle is drawn.
route true or false; default true A sound as a route is drawn on a map.
pins true or false; default false A sound as map pins land.
chapter true or false; default false A sound as a chapter card arrives.
subscribe true or false; default false A soft sound as the subscribe prompt arrives.

The presenter (playbook Part 1 §1.1–1.2). presenter sets who the presenter is and the longest the audience goes without seeing them. The checks count the gap from the film's start and to its end, and also report a presenter who never appears.

PresenterStyle (work.house_style.presenter)

Member Type Meaning
id required text The presenter's id, as pictures of them are bound.
max_gap_ms whole number The longest the presenter may be absent from the picture. If absent, 120000 is used by the checks.

ReadinessStyle (work.house_style.readiness)

Member Type Meaning
hold_insert_ms whole number The longest an insert (a detail glance) may run before RDY-HOLD flags it, apart from speech inside it.
hold_reaction_ms whole number The longest a reaction may run, apart from speech inside it.
hold_cutaway_ms whole number The longest a cutaway may run, apart from speech inside it.
hold_neutral_ms whole number The longest a neutral (bridging) shot may run, apart from speech inside it.
reaction_window_ms whole number How long after a turning line ends the listener may first appear and still count, for RDY-REACTION, as answering it. Default 1000.

Every member is optional. A member left out keeps the check's own figure. Without hold_*_ms, a hold limit is a multiple of the film's own pace (its median shot length, or timing.body_median_ms when declared), scaled by the shot's size: insert and cutaway 2 times the pace, reaction 2.5, neutral 1.5, times 1.25 for an extreme long shot falling to 0.75 for an extreme close-up. The reaction window is 1000 ms. A film cut slowly on purpose raises them; a very fast one lowers them. Whatever the limit, speech inside the shot is added to it: a reaction played under the other person's line, or an insert over the narration that reads the clause, lasts as long as the words need.

Picture timing (playbook Part 1 §1.3). timing sets how closely cuts follow the spoken words, and how long shots run. Omitting the whole object makes render verification report only. An explicit null for a median switches off that section's length gate. Slower musical films may choose their own targets.

TimingStyle (work.house_style.timing)

Member Type Meaning
lead_ms whole number The planner's target for how far a picture change leads the word it belongs to. Default 50 when timing is present.
word_window_ms whole number The window, around a word's start, inside which a picture change counts as on that word. Default 250.
paragraph_window_ms whole number The same window for the start of a paragraph. Default 250.
max_shift_ms whole number The most a picture boundary may be moved to meet a word. Default 500.
min_onset_share number The least share of rendered word onsets that must be met. Default 0.84.
min_paragraph_share number The least share of paragraph starts that must be marked by a picture change. Default 0.57.
hook_median_ms whole number Target median shot length in the opening hook. Default 1400. null switches this gate off.
body_median_ms whole number Target median shot length in the body. Default 2300. null switches this gate off.
presenter_median_ms whole number Target median length of presenter shots. Absent means no target.
shot_median_tolerance_ms whole number How far a median may be from its target. Default 500.

Structure on screen (playbook §1.4). structure opts into individual checks, all off unless set. A subscribe prompt is a caption overlay with style: "subscribe" over B-roll. An end card is a caption overlay with style: "end_card", a recommendation in text, and a built-in subscribe prompt; realisation binds its recommendation picture as the overlay's content: {kind: "image", asset: "..."} and the renderer shows it as a thumbnail. The end card may run across the shots of its scene. drawing_sounds.subscribe: true adds a soft local paper-grain entry sound to the small prompt. dplkit.subscribe_prompt, dplkit.end_card and dplkit.structure_style author these; dplkit.add_structure places both on timed shots without changing sound. The sponsor-loop check observes the fixed words and never changes them.

StructureStyle (work.house_style.structure)

Member Type Meaning
cold_open true or false; default false Opt in to the cold-open check: the presenter holds back at the start.
sponsor true or false; default false Opt in to the sponsor checks.
subscribe true or false; default false Opt in to the subscribe-prompt check.
end_card true or false; default false Opt in to the end-card check.
presenter_after_ms whole number; default 15000 When the presenter may first appear.
cold_open_max_ms whole number; default 60000 How long a cold open may run (or until the first new_act).
subscribe_from_ms whole number; default 40000 Start of the window for the subscribe prompt.
subscribe_to_ms whole number; default 70000 End of that window.
end_card_ms whole number; default 18000 How long before the end the end card must be on screen.

Sound targets (playbook §1.5). sound sets how far the bed sits under the voice and how loud the finished mix is. The pipeline carries a plan's sound object into the house-style view used by mixing and verification; the separate style file remains unchanged on disk. With it, the pipeline attenuates the bed during speech (smoothly: down in 40 ms, back over 450 ms) and normalises the finished mix. Verification allows 3 dB bed-depth tolerance, 1 LUFS loudness tolerance, 0.2 dBTP true-peak tolerance, and at most 15% of cuts with transients for few (zero for none). Bed depth verification reports the median voiced-window depth and its p10 separately, and judges the median. With no sound object, these checks report only.

SoundTargetStyle (work.house_style.sound)

Member Type Meaning
bed_under_voice_db number; default 21 How far the bed (music and ambience) sits under the voice while it speaks, in dB.
drawing_sfx_under_voice_db number; default 18 How far the drawing sounds sit under the voice, in dB.
bed_presence_cut_db number; default 0 While the voice speaks, cut the bed's middle band (250 Hz to 5 kHz) by this many dB, so music keeps body and air without masking the words. 0 is off.
bed_hold_ms whole number; default 0 The duck stays down across any pause shorter than this, so the bed does not surge at every breath.
bed_lifts list of BedLift Authored moments where the bed comes up.
loudness LoudnessTarget Target loudness of the finished mix.
cut_sfx text; default "few" How many cut effects: "few" (the default) or "none". Any other text is DPL-SOUND.

BedLift (work.house_style.sound.bed_lifts[])

Member Type Meaning
after text; default "" The id of a spoken line (sound.speech). The bed comes up from the end of that line.
ms whole number; default 0 For how long, undimmed and uncut. Must be above 0.

LoudnessTarget (work.house_style.sound.loudness)

Member Type Meaning
integrated_lufs number; default -14 Target integrated loudness in LUFS.
true_peak_dbtp number; default -1 Highest true peak in dBTP. Must be 0 or less.

2.3 The world: characters, locations, props, rules

The world is what the story is made of. Declare each thing once and name it by id everywhere else, so the checks can follow a person, a place or an object from shot to shot. A character, a prop and a location share one namespace, because staging, attention and the camera's path can name any of them.

Character (characters[])

Member Type Meaning
id required text A short unique id. It shares one namespace with props and locations.
description required text Who they are in the story.
appearance text What they look like in a picture, apart from what they mean. Needed when a generated character is in two or more shots (DPL-APPEARANCE warns if it does not fix the look).
costume text What they wear.
performance text How they act and move.
rig CharacterRig Makes the character a cut-out puppet that staging actions can move. See "Rigs".

Location (locations[])

Member Type Meaning
id required text A short unique id. It shares one namespace with characters and props.
description required text What the place is like.
parts list of text Named parts of the place (the door, the sink). A scene's entry and a camera path can name them.
time_of_day text When it is.
light text How it is lit.
setting one of indoor, outdoor Short-form profile: indoors or outdoors. Outdoors, the shots are held to the usable light.
usable_light list of TimeWindow Short-form profile: when there is light enough to film, as clock times.
sun text Short-form profile: where the sun is, if known ("low from the west after 16:00").
access list of TimeWindow Short-form profile: when the crew may be at the place (it opens, closes, is booked). Without any, always.
acoustics one of quiet, controllable, fixed Short-form profile: how the place sounds while people speak; fixed noise cannot be switched off.
quieter_position true or false Short-form profile: whether a speaker may move somewhere quieter.

Prop (props[])

Member Type Meaning
id required text A short unique id. It shares one namespace with characters and locations.
description required text What the object is and why the story needs it.
appearance text What it looks like in a picture, apart from what it means.

ContinuityRule (continuity_rules[])

Member Type Meaning
id required text A short unique id. Shots cite it in their continuity.
domain text What kind of rule it is (light, costume, geography).
rule required text The rule, as a sentence.
measures list of RuleMeasure What the rule means in the rendered picture, measured on every shot that cites it.

RuleMeasure (continuity_rules[].measures[])

Member Type Meaning
kind required one of min_brightness, max_shadow_share What is measured: min_brightness means mean brightness at least value; max_shadow_share means the share of the frame in deep shadow at most value.
value required number The fraction (0 to 1) to hold to.
{"id": "light-of-the-father", "domain": "light", "rule": "The Father of lights: no heavy shadow.",
 "measures": [{"kind": "min_brightness", "value": 0.4}, {"kind": "max_shadow_share", "value": 0.2}]}
Rigs

A character can be a cut-out puppet, so a shot can move it. rig: {"body": "figure"} is the standard jointed figure of ten parts: torso, head, upper_arm_l, upper_arm_r, forearm_l, forearm_r, thigh_l, thigh_r, shin_l and shin_r. {"body": "own", "parts": [...]} is a rig of parts cut from your own art, with exactly one root; a part that is named as one of the figure's roles is the one the actions move, and roles maps a role to a part where the names differ (the roles the validator accepts are the ten above and foot_l and foot_r). A shot then gives the character's staging a list of actions, section 2.6. The realiser turns the actions into the rig layer's keys (its port of tools/eil-prep/puppet.py, held to it by a parity fixture) and binds each part's picture from the character's binding: roles["role:<id>"].rig = {part: picture}. A part left unbound is reported (unbound_rig), never drawn half-bound. The figure stands on its staging side of the frame.

CharacterRig (characters[].rig)

Member Type Meaning
body required one of figure, own figure is the standard jointed figure of ten parts. own means the rig's parts are its own.
parts list of RigPart For own: the parts, with exactly one root. A figure rig must not give parts.
roles map from role to part id Maps an action role (such as head or thigh_l) to one of this rig's part ids, so the actions move the right parts.
ground list of [x, y] points The ground line the figure stands on: at least two [x, y] points with x ascending, each from 0 to 1.
mirror true or false; default false Reflect the painted figure about its root when its travel faces against the art.

RigPart (characters[].rig.parts[])

Member Type Meaning
id required text The part's id.
parent text The part it hangs from. Leave out for the single root.
size required [width, height] The part's picture as fractions of the rig's box: [width, height].
pivot required [across, down] Where it turns, as fractions of its own picture: [across, down].
at required [across, down] Where its pivot sits: on its parent's picture (fractions), or for the root on the rig's box.
sole [across, down] For a painted shin: its opaque sole point in its own image, two fractions.
min number The least it may turn from neutral, in degrees. Must not exceed max.
max number The most it may turn from neutral, in degrees.
z whole number; default 0 Drawing order: higher is in front.
secondary RigSecondary Makes the part trail its parent (a cloak, a braid).
attach RigAttachment Fixes the part to another part (a staff in a hand).

RigSecondary (characters[].rig.parts[].secondary)

Member Type Meaning
lag_ms whole number; default 120 How far behind its parent the part follows. Must be above 0.
damping number; default 0.35 How quickly the trailing settles, from 0 to 1.

RigAttachment (characters[].rig.parts[].attach)

Member Type Meaning
to required text The part it is attached to.
at required [across, down] The point on that part, two numbers.
upright true or false; default false For a walking staff: keep its painted shaft at its rest angle in the world.
{"body": "own",
 "parts": [
   {"id": "body", "size": [0.3, 0.6], "pivot": [0.5, 0.5], "at": [0.5, 0.6]},
   {"id": "head", "parent": "body", "size": [0.2, 0.2], "pivot": [0.5, 0.9], "at": [0.5, 0.05], "z": 1}],
 "roles": {"torso": "body", "head": "head"},
 "ground": [[0, 0.9], [1, 0.9]]}

2.4 Structure: sequences, journey, scenes

The structure says how the film is built. A scene is the unit: one place, one job, a run of shots. A sequence groups scenes into a larger movement and can say which way it is heading. A journey says where the camera travels across a sequence or the whole film.

Purpose everywhere. Every scene and every shot must say what it is for (purpose), not only what it shows (subject). A scene may also say what is different for the audience at its end (change). A plan with no purposes is a shot list; a plan with purposes can be edited, replanned and judged.

Scenes. Scenes run in time order, do not overlap, and between them cover the film; a gap is a warning (DPL-GAP). Within a scene, the shots do the same. Most of a scene's members are explained below or in the sections that follow: its lines, axis, travel and state_changes in 2.6 (they are what the readiness checks reason over), and its sound, hearing and phrases in 2.8.

Scene (scenes[])

Member Type Meaning
id required text A short unique id.
purpose required text What the scene is for.
change text What is different for the audience at the end of the scene.
functions list of SceneFunction The scene's dramatic job in typed form, and which shot or sound carries it. One of each function per scene.
start_ms required whole number When the scene starts, in ms from the start of the work.
end_ms required whole number When it ends (exclusive). Scenes run in order and must not overlap.
location text The id of one of the plan's locations.
entry SceneEntry How the audience arrives in the scene's world.
shots required list of Shot The scene's shots, in time order. At least one.
attention list of AttentionBeat Who or what holds the audience, and when.
sound list of SceneSound What each kind of sound is doing in this scene.
hearing Hearing Whose hearing the scene takes and how the world sounds to it.
phrases list of Phrase How each heard sound's phrase runs through this scene: enters, carries, changes, returns or ends.
treatments list of Treatment The directions considered for the scene, with the one taken and why. A plan says what it could have been, not only what it is.
strands list of StrandPart What words, sound and picture each do in this scene. One leads; the others answer, support or rest.
removals list of Removal Things taken away at a moment (a picture layer, a part of the music), so picture and sound can lose something together on the same word.
axis Axis The line of action: who is on the left of frame and who on the right, from the camera's side of the line. The checks need it to catch crossed-line cuts.
travel one of left, right, toward, away, none Which way travel runs across the screen in this scene (a chase, a journey), kept from shot to shot. Leave it out when nothing travels: none is refused here (DPL-RANGE), though it is allowed in a shot's moving.
lines list of DialogueLine The spoken lines of the scene: who says each, to whom, when.
state_changes list of StateChange Things that change state during the scene (a glass breaks, a door opens), and whether the audience must see it.
accepts list of Acceptance Departures from editing convention that the plan chooses on purpose, each with its reason.
none list of Absence What the scene deliberately does not have, said outright: spoken_lines (nobody speaks on screen) and line_of_action (staged without a line). See "Saying no".
journey_stage text The id of the journey stage this scene is at. Needs a journey (the plan's or its sequence's) that governs the scene.
provenance Provenance Who or what set this scene. Inert: no rule reads it (2.10).

Functions. functions is the scene's dramatic job in typed form, led by one shot or sound carrier of the scene and supported by others: propulsion, evidence, contrast, emphasis, reset, retention, humour, dread, anticipation, release or rest. These words are owned by DPL.

SceneFunction (scenes[].functions[])

Member Type Meaning
type required one of propulsion, evidence, contrast, emphasis, reset, retention, humour, dread, anticipation, release, rest The dramatic job.
lead required text The shot of this scene, or the sound carrier, chiefly responsible.
support list of text Other shots or carriers that help.

Entry. entry says how the audience arrives in the scene's world, and into which part of the location. Use return or continue for a scene that is back in a place the audience knows; the geography check then does not ask for the people to be placed again.

SceneEntry (scenes[].entry)

Member Type Meaning
how required text How the audience arrives, in a word: for example open, transport (taken somewhere new), return (back to a known place) or continue. The geography check is skipped for return and continue.
from_part text The part of a location the audience leaves, if any.
to_part text The part of the scene's location the audience arrives in. Must be one of that location's parts.
established_by text The id of the shot in this scene that establishes the arrival.
note text Anything else worth saying about the arrival.

Attention. Who or what should hold the audience at each moment: a primary and what comes after it. A beat can name its target and the effect it has on attention (concentrate it, hide something, disorient). Say so when the plan means to disorient or withhold, because the readiness checks then treat the departure as planned.

AttentionBeat (scenes[].attention[])

Member Type Meaning
start_ms whole number When the beat starts. Give both times or neither.
end_ms whole number When it ends. Without times the beat covers the whole scene.
primary required text Who or what should hold the audience, in words.
secondary list of text What comes after the primary, in words.
target text The character, prop, location or sound carrier that holds attention, when it is one. Give target and effect together, or neither.
effect one of concentrate, suppress_competition, intensify_recognition, reveal, withhold, disorient, waking, trance, sleep, distort_hearing, restore_clarity, alter_scale What the beat does to the audience's attention. A scene whose attention disorients or withholds is not faulted for showing singles before the people are placed.
over text What the target leads while it holds attention (a character, prop, location or sound carrier).
resolves_to text What attention settles on afterwards, in words.
[{"primary": "Maya's face", "secondary": ["the letter in her hand"], "start_ms": 0, "end_ms": 6000},
 {"primary": "the lamp", "target": "lamp", "effect": "reveal", "over": "TOM", "resolves_to": "Tom's hands", "start_ms": 6000, "end_ms": 14000}]

Treatments. A scene can show the directions that were considered and the one taken. Exactly one is chosen; a single treatment is a warning (DPL-TREATMENT), because one direction means nothing was weighed.

Treatment (scenes[].treatments[])

Member Type Meaning
id required text A short unique id within the scene.
angle required text The angle, in a few words ("stay on his face and close in").
idea required text What the audience would see and hear, and why it could work.
source text Where the idea comes from: prior art, a reference, an owner note.
chosen true or false; default false Whether this is the direction taken. Exactly one treatment is chosen.
why required text Why it was taken, or why not.
[{"id": "t1", "angle": "stay on his face and close in", "idea": "One slow push on Tom while Maya speaks off screen.", "chosen": true, "why": "The scene is about what he cannot say."},
 {"id": "t2", "angle": "keep them both in the wide", "idea": "Hold the two of them apart across the kitchen.", "source": "owner note, 12 Oct", "why": "It spends the closeness we need for the last shot."}]

Strands. The three strands a film tells its story on are words, sound and picture. In a scene, give each strand exactly one part: one leads, the others answer, support or rest. A unison is all three striking together on one moment, and then all three are unison. A sequence's strands run across the sequence, with no one required to lead, and a sequence that gives strands also needs its direction. If one strand leads every scene of a sequence of four or more, the validator warns (DPL-STRANDS).

StrandPart (scenes[].strands[], sequences[].strands[])

Member Type Meaning
strand required one of words, sound, picture Which strand: words, sound or picture. Each appears exactly once.
role one of lead, answer, support, rest, unison; default "support" What it does: lead, answer (call and response), support, rest, or unison (all three strike together; rare, and then all three are unison).
does required text What the strand does here, in its own terms.
at_ms whole number When the strand makes its move (a hit), for example the onset of the word a unison lands on. A unison gives one moment.

Removals. Subtraction is a decision. A removal takes away a picture layer or one sound carrier (or one stem of it) at a moment, so picture and sound can lose something together on the same word.

Removal (scenes[].removals[])

Member Type Meaning
at_ms required whole number The moment, inside the scene.
layer text A layer (layers[].id) of a shot in this scene to take away. Give layer or carrier, not both.
carrier text A sound carrier to take away.
stem text The part of the carrier removed: drums, bass, other or vocals. The whole carrier when absent. Only with carrier.
why text Why it goes here.
[{"at_ms": 9000, "layer": "mist", "why": "the air clears on the word"}, {"at_ms": 9000, "carrier": "MUSIC", "stem": "drums", "why": "the drums drop out with it"}]

Accepts. A scene can accept a departure from editing convention, with its reason (a scene played in one take). The finding is then reported as overridden, not as a fault.

Acceptance (scenes[].accepts[])

Member Type Meaning
code required text The finding code accepted, for example RDY-COVERAGE.
shot text The shot it applies to. Every shot in the scene when absent.
why required text The reason. An accepted finding is reported as overridden, not as a fault.

Sequences. A sequence groups scenes by id. Use one when the film has movements that each head somewhere.

Sequence (sequences[])

Member Type Meaning
id required text A short unique id.
purpose required text What the sequence is for.
scenes required list of text The ids of its scenes, in order.
direction text Where the sequence is heading: the one direction words, sound and picture all move in (for example "from vast to one"). Needed when strands are given.
strands list of StrandPart What words, sound and picture each do across the sequence. Exactly one part per strand.
journey Journey Where the sequence's camera travels, stage by stage. See "The journey".
none list of Absence What the sequence deliberately does not have: journey (no route of its own). See "Saying no".
{"id": "q1", "purpose": "From the whole sky to one man.", "scenes": ["S1", "S2"], "direction": "from vast to one",
 "strands": [
   {"strand": "words", "role": "lead", "does": "narrows from the heavens to a name"},
   {"strand": "sound", "role": "support", "does": "thins from a chord to one voice"},
   {"strand": "picture", "role": "answer", "does": "closes from the horizon to a face"}]}
The journey

A sequence, or the whole plan, can say where its camera travels (brief c, 5 Oct 2026; owner, 4 Oct: "Beats are silver; a journey is gold"). The axis says what the route measures: height for a ladder, distance out from home, inward toward a destination. The stages are the route in order. Each has an id, a value on the axis, and the place's name when a place is visited again (a place visited again is a new stage with the same name and a return reason, as M7's "down again to earth"). The destination is the stage where the route ends, with why. Each scene then names its journey_stage; its location, parts and entry stay as they are.

The plan validates the route's shape: at least two stages, a destination that is one of them, and a stage for every scene that names one (DPL-JOURNEY). Edit-readiness holds a plan that declares a journey to it (section 3). A plan with no journey gets no journey finding. With direction, the journey is carried into the editing stage (editorial.journey_stage@1). Fixtures: tests/corpus/journey/.

Journey (journey, sequences[].journey)

Member Type Meaning
axis required one of height, distance, inward What the stages measure: height is a ladder, distance is out from home, inward is toward a destination.
stages required list of JourneyStage The route, in order. At least two.
destination required JourneyDestination Where the journey ends, and why.

JourneyStage (journey.stages[])

Member Type Meaning
id required text A short id. Scenes name it in journey_stage.
name text The place as it is called on screen. A place visited again is a new stage with the same name.
value required number Where the stage is on the axis: a height, a distance out, or how far in.
return text Why the route comes back to a place it has been ("down again to earth").

JourneyDestination (journey.destination)

Member Type Meaning
stage required text The id of the stage where the journey ends.
why required text Why it ends there, in the owner's words.
{"axis": "height",
 "stages": [{"id": "earth", "value": 0}, {"id": "heaven", "value": 3}, {"id": "earth2", "name": "earth", "value": 0, "return": "down again to earth"}],
 "destination": {"stage": "heaven", "why": "the whole climb is to see him"}}

2.5 Shots

A shot is a continuous run of picture. Say what it is for (purpose) and what it shows (subject); give its camera; name the characters and props in it. Everything else on a shot is optional and earns its place when a check or a maker needs it: coverage, staging, setup, states for the readiness checks (2.6); overlays, layers and window to build the picture (2.7); image_brief and motion_brief for whoever makes the picture, whether a crew or a generation model.

Shot (scenes[].shots[])

Member Type Meaning
id required text A short id, unique across the whole plan. Transitions and sound name shots by it.
picture ShotPicture What kind of picture the shot is, for picture suggestions and the beat checks.
purpose required text What the audience should read from the shot.
subject required text What the shot shows.
start_ms required whole number When it starts. Shots run in time order and stay inside their scene.
end_ms required whole number When it ends (exclusive).
camera required Camera Size and movement, and the rest of the camera.
source one of footage, still, graphic, typography, generated, generated_video, recall What the picture is made from. A camera move on a still is realised as a move across it.
characters list of text Ids of the characters the shot shows. The first one is taken to hold the frame.
props list of text Ids of the props it shows.
path list of PathPhase A travelling camera's phases.
introduces list of ShotIntroduction Subjects that first come into view in this shot, and how.
visual_state text What must be true in frame (the state of the world, light, props).
continuity list of text Ids of the continuity_rules this shot must honour.
image_brief text A brief for whoever makes the picture (crew or generation model).
motion_brief text A brief for how the picture moves.
recall Recall For a recalled shot: the earlier movement and shot whose approved media this reuses.
motion_ramp MotionRamp A change of the picture's speed inside the shot: the clip slows to stillness on a word.
must_not list of text What this shot must never show or do.
overlays list of Overlay Layers over the picture for part of its length: an inset, a nameplate, words that land, a diagram.
layers list of Layer The shot built in depth: background, middle and foreground, each with its own timing and motion.
window list of LayerKey The camera as a window travelling over the shot's painted picture, as keys of offset and scale. Every layer follows it at its own parallax.
coverage Coverage What the shot gives the edit and how much it matters.
staging list of Staging Where each subject is in frame, which way they look and move.
setup text A name for the camera set-up the shot is filmed from. Shots that share a name are shot together.
crosses_line true or false True when the camera crosses the line of action on screen, taking the audience with it.
states list of PropState The state of each prop that matters, as seen in this shot.
filming Filming Short-form profile: how the shot is filmed (its timing role, takes, whether it is a one-take moment).
provenance Provenance Who or what set this shot. Inert: no rule reads it. (Not called source, which a shot already has.)

Source and recall. source says what the picture is made from. generated is a still made for the shot; generated_video moves (image to video); footage is recorded; still, graphic and typography are designed. A camera move on a still is realised as a move across it. recall reuses the approved picture or clip of an earlier movement (the same file, not a regeneration that looks different): set source to recall and name the movement and shot. Only a recall carries a recall member (DPL-RECALL).

Recall (scenes[].shots[].recall)

Member Type Meaning
movement required text The earlier movement's id (for example m3, opening).
shot required text The shot in that movement whose approved media is reused.

Motion ramp. motion_ramp is an authored slowing of the picture to stillness inside a shot, on a word (the storm on "be still"). It is not a freeze: the hold after it is the plan's intent. Only moving picture (generated_video, footage or recall) can ramp.

MotionRamp (scenes[].shots[].motion_ramp)

Member Type Meaning
to required text What the picture ramps to. Today only "still".
at_ms required whole number The moment the motion has stopped, in film time. Inside the shot.
why text Why the picture comes to rest here.

The camera. size and movement are required, in DPL's own terms (section 4). angle, lens and perspective are optional. perspective says whose view the shot takes. A subjective shot also names whose eyes it is, and the person whose eyes they are is never seen in it. eyeline says where eyes go: who looks at what, or that no one meets the lens. focus says how sharp the shot is, which can carry meaning (narrowed, disoriented, recovering). motion describes the character of a moving camera.

Camera (scenes[].shots[].camera)

Member Type Meaning
size required size term (section 4) How much of the subject is in frame.
movement required movement term (section 4) What the camera does during the shot. hold is still.
angle angle term (section 4) Where the camera looks from.
lens lens term (section 4) The lens, which sets the feel of depth.
perspective perspective term (section 4) Whose view the shot takes.
note text Anything else about the camera.
focus one of clear, selective, narrowed, disoriented, recovering How sharp the shot is, which can carry meaning: a narrowed or disoriented focus is a character's state, recovering is coming back from it.
whose text For a subjective view: the character or prop whose eyes the camera is. They are not seen themselves.
eyeline text Where eyes go: who looks at what, or that no one meets the lens. Plain text.
motion MotionFeel The feel of a moving camera.
lens_multiplier number Short-form profile, for a phone: the lens as a multiplier of the main camera (0.5, 1, 3).
focal_mm number Short-form profile, for a camera: the lens's focal length in millimetres.
support one of handheld, gimbal, tripod, clamp, slider, shoulder, dolly, jib, crane, steadicam, drone Short-form profile: what carries the camera in this shot.
device text Short-form profile: the kit camera that films it (a camera id of the kit); any camera that can when absent.
frame_rate number Short-form profile: frames per second, when it is not the usual rate (slow motion).
orientation one of portrait, landscape, square Short-form profile: how the camera is held, which decides the frame's shape.

MotionFeel (scenes[].shots[].camera.motion)

Member Type Meaning
path required one of onward, meander, rise, settle, orbit, stationary The shape of the path it follows.
variation required one of organic, controlled, still Whether the motion is natural and uneven (organic), exact (controlled) or none (still).
weight required one of buoyant, ballistic, resisted, weighty, controlled How heavy it feels.
force required one of wind, gravity, contact, current, self_propelled, none What drives it.
energy required one of still, low, building, high, decaying How its energy runs over the shot.
irregular true or false; default false True when the motion is not steady.

A travelling camera's path. A camera that travels gives its path: phases in time order, each with a movement, the size it arrives at, how it moves relative to a character, prop or location, on which side, and the part of the location it carries the viewer into. The relation (relation) is one of from, around, past, over, through, toward, into, away_from and with; give it together with the subject it is relative to. The human shot list spells the path out in industry terms, for example "0:03 ≈ Boom Shot (rise) from table → 0:04.5 Arc Shot around reader (over right shoulder) → 0:07 Drone Shot through window into garden" (fixture the-fly.dpl.plan.json).

PathPhase (scenes[].shots[].path[])

Member Type Meaning
at_ms required whole number When the phase starts. Inside the shot, in time order.
movement required movement term (section 4) How the camera moves in this phase.
size size term (section 4) The framing this phase arrives at. The shot's own size when absent.
relation one of from, around, past, over, through, toward, into, away_from, with How the camera moves relative to the subject. Give relation and subject together, or neither.
subject text The character, prop or location the phase moves relative to.
side one of none, left, right, above, below, behind, front, over_left_shoulder, over_right_shoulder; default "none" Which side of the subject the camera is on.
into text The part of the scene's location the phase carries the viewer into.
note text Anything else about the phase.
[{"at_ms": 0, "movement": "rise", "size": "medium", "relation": "from", "subject": "table"},
 {"at_ms": 1500, "movement": "arc", "relation": "around", "subject": "MAYA", "side": "over_right_shoulder"},
 {"at_ms": 4000, "movement": "drone", "relation": "through", "subject": "window", "into": "garden"}]

Introductions. introduces says what first comes into view in a shot, and how: an entrance, a discovery, a light_reveal, an emergence, a return or a cause. Say why it appears there. Converting tools carry it on as story-critical or (with minor) contextual.

ShotIntroduction (scenes[].shots[].introduces[])

Member Type Meaning
subject required text The character, prop or location coming into view.
how required one of entrance, discovery, light_reveal, emergence, return, cause How it arrives.
minor true or false; default false True when the arrival is only context, not story-critical (converting tools carry it on as contextual).
why required text Why it appears here.

Picture kinds. A shot's picture names what kind of picture it is: source_document, official_document, map, portrait, reconstruction, footage, presenter, chapter_card, visual_pun, quote_text, split_screen, sponsor_set or other. serves names the beat ids (section 2.8, sound.beat_functions) the shot answers. source_shown records evidence visible in another kind of shot, and note explains the choice. suggest-pictures prints defaults with reasons and whether a shot explicitly serves each beat. For a map, or a map-backed portrait, map_camera gives from and to geographic views [west, south, east, north] and a start_ms/end_ms interval inside the shot; the adapter carries that timing to realisation, which applies it to the bound map.

ShotPicture (scenes[].shots[].picture)

Member Type Meaning
kind required one of source_document, official_document, map, portrait, reconstruction, footage, presenter, chapter_card, visual_pun, quote_text, split_screen, sponsor_set, other What kind of picture the shot is.
map_camera MapCameraPlan For a map (or map-backed portrait): a zoom from one view to another.
serves list of text Ids of the beat_functions this shot answers.
source_shown true or false True when the evidence for a claim is visible in this shot, even though it is not a source document.
note text Why this picture was chosen.

MapCameraPlan (scenes[].shots[].picture.map_camera)

Member Type Meaning
from required [west, south, east, north] The view at the start: [west, south, east, north] in degrees.
to required [west, south, east, north] The view at the end, in the same form.
start_ms required whole number When the zoom starts. Inside the shot.
end_ms required whole number When it ends.
{"id": "M1", "purpose": "Show how far the road runs.", "subject": "The road from Jerusalem to Jericho.",
 "start_ms": 0, "end_ms": 6000, "camera": {"size": "extreme_wide", "movement": "drift", "angle": "high", "lens": "wide",
   "perspective": "objective", "focus": "clear",
   "motion": {"path": "onward", "variation": "organic", "weight": "controlled", "force": "wind", "energy": "low"}},
 "source": "graphic", "props": ["lamp"],
 "picture": {"kind": "map", "serves": ["b1"], "note": "a map shows the distance faster than the words can",
   "map_camera": {"from": [30.0, 28.0, 38.0, 34.0], "to": [34.5, 31.2, 35.6, 32.0], "start_ms": 500, "end_ms": 5500}},
 "image_brief": "An aged map, warm paper, the road inked in red.", "motion_brief": "A slow push toward the city.",
 "must_not": ["modern roads"]}

2.6 Live-action facts: coverage, staging, lines, states

These are the facts the edit-readiness checks reason over (added 1 Oct 2026, docs/capability/EDIT_READINESS.md). All are optional. They let a plan answer, before anything is shot or generated, whether the edit will have what it needs. Section 3 says which detail switches which check on. Fixtures: tests/corpus/readiness/.

Coverage says what a shot gives the edit and how much it matters. role is one of establishing, master, two_shot, single, over_shoulder, reaction, insert, cutaway, pov or neutral. priority is must, should or nice; a must cannot be dropped without losing the scene's job, and dpl replan never drops one.

Coverage (scenes[].shots[].coverage)

Member Type Meaning
role required one of establishing, master, two_shot, single, over_shoulder, reaction, insert, cutaway, pov, neutral What the shot gives the edit.
priority one of must, should, nice; default "should" How much the edit depends on it: a must cannot be dropped without losing the scene's job.

The line of action (axis) is the line between two subjects. It says who is on the left of frame and who is on the right, from the camera's side of the line, and every shot keeps them there unless the camera crosses on screen (crosses_line). The checks need it to catch crossed-line cuts. Travel (travel) is the way travel runs across the screen in a scene, for a chase or a journey: left, right, toward or away. It is kept from shot to shot.

Axis (scenes[].axis)

Member Type Meaning
left required text The subject on the left of frame, from the camera's side of the line.
right required text The subject on the right. Must differ from left.

Staging puts each subject in the frame: its side of frame (left, centre, right), where it looks (facing: left, right, camera, away) and which way it moves (moving: left, right, toward, away, none). A shot stages each subject once. The setup of a shot is a name for the camera set-up it is filmed from (A, B); shots that share a name are shot together, which is how the checks see a jump cut and how a replan finds a whole set-up to drop.

Staging (scenes[].shots[].staging[])

Member Type Meaning
subject required text The character, prop or location. A shot stages each subject once.
side required one of left, centre, right Where in the frame: left, centre or right.
facing one of left, right, camera, away; default "camera" Where the subject looks, on screen: left, right, camera or away.
moving one of left, right, toward, away, none Which way the subject moves on screen: left, right, toward, away or none.
actions list of StagingAction For a rigged character: what they do in this shot, one after another. The rig stands in the frame on the subject's side.

Lines are the spoken lines of a scene as the edit sees them: who says each (speaker), to whom (to), when, and turn when how the listener takes it is part of the moment, so the audience must see them. A turning line needs to. A speaker is a character, and a line is not said to its own speaker. to is a character, or one of three typed targets for a line that no single character takes: camera, audience or group (see "Lines to the camera, the audience or a room" below). Lines here are separate from the sound.speech lines that carry the recording (2.8). A scene where nobody speaks on screen says so with none (see "Saying no").

DialogueLine (scenes[].lines[])

Member Type Meaning
id required text A short id, unique in the scene.
speaker required text The character who says it.
to text Who it is said to: a character (not the speaker), or camera, audience or group. A character whose id is one of those three words is the character, so do not give characters those ids.
among list of text For a line said to the group: the characters in the room, when they are individually known. Not the speaker. Leave it out when the group is a crowd.
start_ms required whole number When it starts. Inside the scene.
end_ms required whole number When it ends.
turn true or false; default false True when the line turns the scene: how the listener takes it is part of the moment, so the audience needs to see them. A turning line needs to, and not camera or audience: nobody on screen takes those.
text text What is said.
Lines to the camera, the audience or a room

A presenter talks to the lens, a vox-pop answers an interviewer who is off screen, a safety video speaks to whoever is watching, a best man toasts the whole room. None of these has one character to look at, so to takes three typed targets instead of a character id:

to Meaning What the checks do
camera Direct address: the speaker talks to the viewer, at the lens. The speaker should face the camera (facing: camera). No other character is expected to react, so the reaction rule and the pair-of-singles eyeline rule leave the line alone. A line said to the camera cannot turn.
audience The same, but off the lens: the speaker talks to the viewers (a stage, a lecture, an aside) without looking down the camera. As camera: no character reaction is expected.
group A room, a crowd or several characters at once. among lists them when they are individually known. No single listener, so no reaction or pair eyeline is expected for the line. A group line can turn; the plan then says the moment is how the room takes it, and it is for the director: readiness does not yet look for the room's reaction.

dpl missing does not ask "who is this said to?" about a line that gives one of these targets, and it offers them as answers when it does ask.

[
  {"id": "L1", "speaker": "host", "to": "camera", "start_ms": 1000, "end_ms": 4000, "text": "Welcome back. Today: how to change a flat tyre."},
  {"id": "L2", "speaker": "host", "to": "audience", "start_ms": 4500, "end_ms": 7000, "text": "And yes, you can do this in a dress."},
  {"id": "L3", "speaker": "best_man", "to": "group", "among": ["bride", "groom", "mother"], "start_ms": 8000, "end_ms": 12000, "text": "Raise your glasses."}
]
Saying no

A plan that is silent about something and a plan that says there is none are different. A scene with no lines might be a silent scene or a scene nobody has described yet; dpl missing cannot tell, so it asks. none is the way to answer: a list of things the scene, the sequence or the film deliberately does not have, each with an optional why.

Absence (none[], scenes[].none[], sequences[].none[])

Member Type Meaning
kind required one of spoken_lines, line_of_action, journey What there is none of. In a scene: spoken_lines or line_of_action. In the film or a sequence: journey. A kind in the wrong place is DPL-NONE; the same kind twice is DPL-DUPLICATE.
why text Why there is none ("a silent scene", "360-degree master: the camera circles the table", "the film stays in one room"). Required for line_of_action, which departs from editing convention (DPL-REQUIRED); optional for the others.
[{"kind": "spoken_lines", "why": "A silent scene: only the wind."},
 {"kind": "line_of_action", "why": "360-degree master: the camera circles the table, so no side of a line is kept."}]
[{"kind": "journey", "why": "The film stays in the one room."}]

Why a list of terms, not a flag per fact. Each absence carries its own reason, the list is one place to look, a new kind of "none" is one more term and not another member on another type, and the empty list is still the default, so a plan that says nothing reads exactly as before. A fact that is left out is not yet answered; only an entry in none is an answer.

State changes and states. A prop that changes (a glass breaks, a door opens) is recorded as a scene state_changes entry, with shown set when the audience must see it happen. A shot's states say what state each prop is in as the shot shows it. Together they let the checks catch a prop shown whole after it broke, or a change nobody sees.

A shot's states describe what is seen in it; a shot that contains a change may show either side of it. A shot that runs across a state_changes entry (the glass breaks at 23,200 ms inside a shot that runs 22,800 to 24,500) can truthfully be described by the state before the change or the state after it, so the checks accept either from or to for that prop in that shot. A shot that does not contain the change shows the state the prop is in at that time. No separate field says which.

StateChange (scenes[].state_changes[])

Member Type Meaning
prop required text The prop that changes.
from required text Its state before.
to required text Its state after. Must differ from from.
at_ms required whole number When it changes. Inside the scene.
shown true or false; default false True when the audience must see it happen.

PropState (scenes[].shots[].states[])

Member Type Meaning
prop required text The prop.
state required text Its state in this shot, in a word or two.
{"id": "K7", "purpose": "The glass slips from his hand and breaks.", "subject": "glass",
 "start_ms": 22800, "end_ms": 24500, "camera": {"size": "detail", "movement": "hold"}, "source": "footage",
 "props": ["glass"], "coverage": {"role": "insert", "priority": "must"}, "setup": "E",
 "states": [{"prop": "glass", "state": "broken"}]}
Rig actions

A shot's staging of a rigged character can name its actions, one after another inside the shot. Each kind is one of walk, argue, turn_head, kneel, look_up, point, climb and stumble.

An action is timed in one of two ways. Give start_ms and end_ms, which must fall inside the shot and follow the action before. Or give at, a word of a measured spoken line (line, word, and on: "stress" to land on the stress rather than the start), with a duration_ms: the hit lands on that word and the start is worked out from the duration. The line needs source_ms and a words entry for that word (2.8). The reader accepts at on any kind, but it is meant for point and climb, whose hit has a contact moment. Only a character with a rig can act (DPL-RIG).

StagingAction (scenes[].shots[].staging[].actions[])

Member Type Meaning
kind required one of walk, argue, turn_head, kneel, look_up, point, climb, stumble The action.
start_ms whole number When the action starts. Give start_ms and end_ms, or at with duration_ms.
end_ms whole number When it ends. Inside the shot, and after the action before it ends.
at ActionWordAnchor Lands the action on a spoken word instead of a time (needs the line's source_ms and the word's measured timing). Any kind of action may use it; it is meant for point and climb, whose hit lands on the word.
duration_ms whole number With at: how long the action takes. The start is derived from it.
side one of left, centre, right For argue and point: the arm, left or right. Right when absent. centre is read but refused (DPL-RIG).
to number, or list of 4 numbers For walk: where to, either a frame x from 0 to 1, or a destination box of four numbers, each from 0 to 1 (the reader checks only the count and the range). For turn_head, look_up and point: an angle in degrees. Not for the other kinds.
distance number For walk: how far, as a fraction of the frame width, from -1 to 1. Use distance or to, not both.
step_ms whole number For walk: the length of one step cycle, 1000 ms when absent. For climb: the length of one step, 900 ms when absent. Above 0. Not for the other kinds.

ActionWordAnchor (scenes[].shots[].staging[].actions[].at)

Member Type Meaning
line required text The id of a spoken line (sound.speech).
word required whole number The one-based index of a word of that line. The line must carry measured words and a source_ms.
on text Only stress is allowed: land on the word's stress (its stress_ms) instead of its start. Absent means the start.
[{"subject": "MAYA", "side": "left", "facing": "right", "moving": "right",
  "actions": [
    {"kind": "walk", "start_ms": 0, "end_ms": 2000, "distance": 0.3, "step_ms": 800},
    {"kind": "point", "at": {"line": "L1", "word": 2}, "duration_ms": 1000, "side": "left", "to": 20},
    {"kind": "stumble", "start_ms": 4000, "end_ms": 5500}]}]

2.7 Picture layers and overlays

Two ways to build a picture beyond a single image. Overlays put something over a shot's picture for part of its length: an inset, a nameplate, words that land, a counter, a diagram. Layers build the shot in depth: the room behind, anything between, the subject in front, each with its own timing and motion, so they can drift apart or slide off different ways. Without layers the shot is one picture.

Overlays. An overlay's kind must match its members: an inset shows a subject; a nameplate or caption has text; words has its words; a counter has a count running from one number to another; a diagram has a diagram. Only a diagram has nodes. A words, caption or nameplate on screen for under 800 ms is a warning, as too brief to read. A caption with timing starts on a spoken moment, so it needs an anchor; timing gives the allowed range for its end (held long enough, cleared in time), and its start is never moved to fit. style names a technique in lower-case words joined by underscores; realisation draws it. backing is the shape behind text (solid, accent, band, none), chosen per use.

A diagram is a simple animation over the picture that explains the point: labelled boxes placed on the frame, links that draw on between them, and markers that travel. Positions are fractions of the frame; times are film milliseconds, each tied by the plan's author to a word. It may run on across the following shots of its scene, since an argument drawn over a cut must not restart.

Overlay (scenes[].shots[].overlays[])

Member Type Meaning
id required text A short id, unique in the shot.
kind required one of inset, nameplate, words, caption, counter, diagram What it is. An inset shows a subject; a nameplate or caption has text; words lands words one by one; a counter runs between two numbers; a diagram draws an animation.
start_ms required whole number When it appears. Inside the shot. If it has an anchor, this must agree with it.
end_ms required whole number When it goes. Inside the shot, except that a diagram or an end_card may run on to the end of its scene. A words, caption or nameplate should stay on at least 800 ms to be read.
purpose required text What it does for the story.
position one of centre, top_left, top_right, bottom_left, bottom_right, lower_third, upper_third; default "centre" Where on the frame it sits.
subject text For an inset: the character, prop or location it shows.
text text The text of a nameplate or caption; the label of a counter.
subtitle text A second line under the text.
words list of TimedWord For words: each word and when it lands.
style text A named technique for how it arrives, in lower-case words joined by underscores (for example soft_rise). Realisation draws it. A caption can use subscribe or end_card.
count Count For a counter: the number it runs from and to over its time.
anchor SpeechAnchor The spoken moment it appears on. A member that has timing needs one.
timing CaptionTiming The allowed range for its end (a caption held long enough, cleared in time).
backing one of solid, accent, band, none The shape behind the text. Absent means the house style's default for that technique.
diagram Diagram For a diagram: the nodes, links and movers.

TimedWord (scenes[].shots[].overlays[].words[])

Member Type Meaning
text required text The word.
at_ms required whole number When it lands. Words land in order, inside the overlay.
highlight WordHighlight One word of the text made brighter and heavier on its spoken moment.
page_break true or false On the narrator's page (the page technique): this word begins a new page. The card stays and the words before it clear.
turn text How what was said before leaves as this word's page begins: beneath, card_left, card_right, card_up, fold, lift, file_away, drop, slide_left or slide_right. Any other text is DPL-OVERLAY. Absent, the renderer varies it.

WordHighlight (scenes[].shots[].overlays[].words[].highlight)

Member Type Meaning
word required text A whole word of the overlay's text.
at_ms required whole number When it lights. On or after the text lands and before the overlay ends.

Count (scenes[].shots[].overlays[].count)

Member Type Meaning
from required whole number The number it starts on.
to required whole number The number it ends on.

CaptionTiming (scenes[].shots[].overlays[].timing)

Member Type Meaning
min_hold_ms whole number The least time the caption stays.
max_hold_ms whole number The most time it stays. Not below min_hold_ms.
clear_before SpeechAnchor It must be gone by this spoken moment.
within_shot true or false True when it ends with its shot at the latest. Default true.

Diagram (scenes[].shots[].overlays[].diagram)

Member Type Meaning
nodes required list of DiagramNode Labelled boxes placed on the frame. At least one.
links list of DiagramLink Links that draw on between two nodes.
movers list of DiagramMover Markers that travel between two points.

DiagramNode (scenes[].shots[].overlays[].diagram.nodes[])

Member Type Meaning
id required text A short id, unique in the diagram.
label required text The words in the box. At most 24 characters.
x required number Across the frame, from 0.04 to 0.96 (the box's centre).
y required number Down the frame, from 0.04 to 0.96.
at_ms required whole number When it appears, in film time. Tie it to a spoken word.
out_ms whole number When it leaves. After at_ms.
tone one of ink, claim; default "ink" ink is the house ink; claim is the colour for what the scene asserts.

DiagramLink (scenes[].shots[].overlays[].diagram.links[])

Member Type Meaning
from required text The id of a node.
to required text The id of a different node.
at_ms required whole number When it starts drawing on. It should come after the two nodes it joins have appeared (DPL-OVERLAY warns if not).
draw_ms whole number; default 600 How long it takes to draw.
out_ms whole number When it leaves.
tone one of ink, claim; default "ink" ink or claim.

DiagramMover (scenes[].shots[].overlays[].diagram.movers[])

Member Type Meaning
id required text A short id, unique in the diagram.
label text A label on the marker.
from required [x, y] Where it starts: [x, y], each from 0.04 to 0.96.
to required [x, y] Where it ends, in the same form.
at_ms required whole number When it starts to move.
dur_ms required whole number How long it takes.
out_ms whole number When it leaves.
[{"id": "ov1", "kind": "nameplate", "start_ms": 500, "end_ms": 3000, "purpose": "Name the speaker.", "position": "lower_third", "text": "Maya", "subtitle": "Tom's wife", "backing": "band"},
 {"id": "ov2", "kind": "counter", "start_ms": 3000, "end_ms": 5000, "purpose": "Show the debt growing.", "text": "pounds owed", "count": {"from": 0, "to": 40000}},
 {"id": "ov3", "kind": "words", "start_ms": 5000, "end_ms": 8000, "purpose": "Land the sentence word by word.", "style": "soft_rise",
  "words": [{"text": "the", "at_ms": 5000}, {"text": "money", "at_ms": 5400, "highlight": {"word": "money", "at_ms": 5800}}]},
 {"id": "ov4", "kind": "caption", "start_ms": 8000, "end_ms": 11000, "purpose": "Subtitle the quote.", "text": "He told me about the money.",
  "anchor": {"line": "L3", "boundary": "onset"}, "timing": {"min_hold_ms": 1500, "max_hold_ms": 4000, "within_shot": true}},
 {"id": "ov5", "kind": "diagram", "start_ms": 11000, "end_ms": 14000, "purpose": "Show where the money went.",
  "diagram": {"nodes": [{"id": "a", "label": "Tom", "x": 0.25, "y": 0.5, "at_ms": 11000}, {"id": "b", "label": "Brother", "x": 0.75, "y": 0.5, "at_ms": 11500, "tone": "claim"}],
              "links": [{"from": "a", "to": "b", "at_ms": 12000, "draw_ms": 800}],
              "movers": [{"id": "m", "label": "cash", "from": [0.25, 0.5], "to": [0.75, 0.5], "at_ms": 12500, "dur_ms": 1000}]}}]

Layers. A layer has a depth (background, intermediate, foreground), a subject, and a purpose. A foreground layer's subject must be a character or prop in the shot; a subject in front with no background layer is a warning, because the shot's own picture is then the background. A layer moves in three ways, which combine: a single motion (a hold, a drift, a rise, a slide, a push, a pull, a parallax, or a converge where layers travel into one frame and settle at at); keys, which animate it (offset, scale, rotation, opacity and which way it faces, eased between keys, and a key can land on a spoken moment); and actions, which repeat (a walk's bob, a breath, a flicker). parallax is how much the layer follows the shot's window, the camera as a window travelling over the painted picture.

Layer (scenes[].shots[].layers[])

Member Type Meaning
id required text A short id. Removals name layers by it.
depth required one of background, intermediate, foreground Where it sits in the shot's depth. A foreground layer's subject must be a character or prop in the shot.
subject required text The character, prop or location the layer shows.
purpose required text What this layer does for the story.
start_ms whole number When the layer is present, inside the shot. Without times, the whole shot.
end_ms whole number When it goes.
motion LayerMove A single move the layer makes.
presence one of faint, present, full; default "full" How strongly it shows.
entrance one of cut, fade, emerge, slide_in; default "cut" How it arrives.
exit one of cut, fade, dissolve, slide_off; default "cut" How it leaves.
region one of full, upper, lower, left, right; default "full" Where in the frame it sits; the rest is left to the layers behind.
style text A named technique for how it appears and behaves, in lower-case words joined by underscores (for example vision_swell).
at LayerPlace Where a converging layer settles: its centre and size, as shares of the frame. Needed with motion converge.
keys list of LayerKey The layer animated by keys (a cut-out figure crossing a painted landscape, a mist band sweeping across), eased between them. With a motion, the motion runs first, then the keys.
actions list of LayerAction Repeating movements over the keys (the bob of a walk while the keys carry the figure along).
parallax number How much the layer follows the shot's window: 1 moves with the picture behind, more than 1 is nearer, less is farther. From 0 to 4. By depth when absent: background 1, intermediate 1.25, foreground 1.6.
pivot [x, y] The point the layer turns and scales about, as fractions of the frame: [0.5, 0.92] is a figure's feet. Absent, the centre of its subject's box, else the frame's centre.

LayerMove (scenes[].shots[].layers[].motion)

Member Type Meaning
kind required one of hold, drift, rise, descend, slide_in, slide_off, push, pull, parallax, converge What the layer does: hold, drift, rise, descend, slide_in, slide_off, push, pull, parallax or converge.
direction one of none, left, right, up, down, toward, away; default "none" Which way. A slide, drift or parallax needs one; a converge says which way it travels in.
amount one of subtle, moderate, strong; default "subtle" How much, by the house style's measure.
distance number How far exactly, as a share of the frame (above 0, up to 1), in place of amount. A drift travels this far one way, then the same the other.

LayerPlace (scenes[].shots[].layers[].at)

Member Type Meaning
x required number Centre across the frame, 0 (left) to 1 (right).
y required number Centre down the frame, 0 (top) to 1 (bottom).
scale required number The layer's width as a share of the frame's, from 0.05 to 1.

LayerKey (scenes[].shots[].layers[].keys[], scenes[].shots[].window[])

Member Type Meaning
at_ms required whole number When the key is reached. Keys run in time order, inside the layer's (or the shot's) time. If it has an anchor, this must agree with it.
anchor SpeechAnchor The spoken moment the key lands on (a step lands on a word).
x number Offset across, as a fraction of the frame from the layer's own place (up to 3 frames away).
y number Offset down.
scale number Size multiplier. Above 0.
rotation number Turn, in degrees.
opacity number From 0 to 1.
turn number Which way a cut-out faces: 1 as drawn, -1 mirrored. Between them it turns edge-on, as a shadow puppet is turned on its screen.
ease one of in_out, linear, in, out, hold, smooth; default "in_out" How the layer moves from the key before into this one. smooth carries the velocity through the key.

LayerAction (scenes[].shots[].layers[].actions[])

Member Type Meaning
kind required one of walk, bob, sway, breathe, flicker, flutter The repeating movement: walk, bob, sway, breathe, flicker or flutter.
start_ms whole number When it starts. Without times, the whole layer.
end_ms whole number When it ends.
amount one of subtle, moderate, strong; default "subtle" How much.
rate number Cycles per second (a walk's steps), from 0 to 6. By kind when absent.
[{"id": "sky", "depth": "background", "subject": "KITCHEN", "purpose": "The room behind.", "motion": {"kind": "drift", "direction": "left", "amount": "subtle"}},
 {"id": "maya", "depth": "foreground", "subject": "MAYA", "purpose": "Maya crosses the room.", "start_ms": 500, "region": "lower", "entrance": "fade", "exit": "fade",
  "pivot": [0.5, 0.92], "parallax": 1.6,
  "keys": [{"at_ms": 500, "x": -0.3, "turn": 1}, {"at_ms": 2500, "x": 0.1, "ease": "smooth"}],
  "actions": [{"kind": "walk", "amount": "moderate", "rate": 1.5}]}]
[{"at_ms": 0, "x": 0, "scale": 1.2}, {"at_ms": 4000, "x": -0.2, "scale": 1.2, "ease": "in_out"}]

2.8 Sound

Sound is planned at two levels. Per scene, sound[] says what speech, music, ambience, effects and authored silence are doing, hearing says whose ears the scene takes, and phrases says how each heard sound runs through it. Across the work, the top-level sound object places everything in film time: the carriers, the spoken lines, which carrier owns the foreground span by span, how sound crosses a change of picture, and the rules that protect moments such as an authored quiet.

Here is what the parts of sound are for:

Sound (sound)

Member Type Meaning
carriers list of SoundCarrier The sources of sound the film uses: a voice, a song, a room tone, an effect, a planned silence.
speech list of SpeechLine The spoken lines, placed in film time. The words are fixed; nothing in the plan changes them.
beat_functions list of BeatFunction What the fixed spoken words are doing at each span (a claim from a source, a place, a new act), so pictures can be chosen to serve them.
beats list of SoundBeat Which carrier owns the foreground, span by span.
bridges list of SoundBridge How sound crosses a change of picture or world.
rules list of SoundRule Protections for moments, such as an authored quiet: what to withhold, when, and how a reviewer checks.
events list of SoundEvent Sounds that happen at a moment (a hit, a chime, a landing), placed in time like spoken lines.
pauses list of SpeechPause Pauses in the speech that give a sound event or a picture join room (the plan's times already include them).
intensity list of IntensityPoint The intensity lever: where a music carrier's drums come forward or sit back while its song plays on.
takeovers list of Takeover A carrier rising on one straight line in dB over a span, with nothing ducking it, not even the voice.

SoundCarrier (sound.carriers[])

Member Type Meaning
id required text A short unique id. Beats, phrases, events and removals name carriers by it.
kind required one of speech, music, ambience, effect, silence What it is.
identity text Which voice, song or place it is.
job required text What this carrier does for the story.
constraints list of text Limits on how the sound may be made or used (its source, the number of takes, the allowed cues).
pulse Pulse A measured beat grid, for music with a steady pulse (explained below).
message CarrierMessage What the carrier says, when it speaks (explained below).

A pulse is a measured beat grid for music with a steady pulse. It carries on in the listener's head after the music stops, so later moments can land on it: a spoken line or an event with lands_on starts on a beat or bar of the carrier's pulse, within 40 ms, and a carrier with no pulse has nothing to land on (DPL-RHYTHM). A message is for a carrier that speaks (a talking drum, a sung line in another language): it is part of the story, so its phrases are never cut part-way and never buried.

Pulse (sound.carriers[].pulse)

Member Type Meaning
period_ms required whole number The length of one beat. Above 0.
phase_ms required whole number Film time of one beat on the grid (the first downbeat).
beats_per_bar whole number; default 4 Beats in a bar.

CarrierMessage (sound.carriers[].message)

Member Type Meaning
language required text The language of the message.
words text The message as it is said (in its own language), when known.
meaning required text What it means.
phrases list of MessagePhrase Where each statement of the message falls in the carrier's own recording.

MessagePhrase (sound.carriers[].message.phrases[])

Member Type Meaning
in_ms required whole number Where the statement starts in the carrier's recording (media time).
out_ms required whole number Where it ends. Later than in_ms.

Speech and anchors. A spoken line is placed in film time, and, when the recording is measured, in its own recording as well (source_ms, and per-word offsets in words). A speech anchor names a spoken moment: a line's onset or offset, plus a signed offset. A sound event, an overlay, a layer key or a caption's clear_before can use one, and the authored time must agree with it, so the item follows the words when the speech is placed differently (docs/realisation/SPEECH_ANCHORS.md).

SpeechLine (sound.speech[])

Member Type Meaning
id required text A short unique id. Anchors, pauses and bed lifts name lines by it.
carrier required text The speech carrier that says it.
text required text The words, exactly as they are said.
start_ms required whole number When the line starts in film time.
end_ms required whole number When it ends.
direction text How it is delivered.
lands_on LandsOn The line starts on a beat (or bar) of a carrier's pulse, within 40 ms.
source_ms whole number Where the line starts in its recording, so the recording can be placed line by line and a pause put between lines without losing sync with the face that speaks them.
words list of SpeechWord Measured words: one-based, with offsets in this line's recording. Anything anchored to a word needs them (and the line's source_ms).

SpeechWord (sound.speech[].words[])

Member Type Meaning
index required whole number The word's number in the line, from 1. Unique in the line.
start_ms required whole number Where the word starts, as an offset from the start of the line, less than the line's length.
stress_ms whole number Where its stress falls, from start_ms up to the line's length.

SpeechAnchor (sound.events[].anchor, scenes[].shots[].overlays[].anchor, ...overlays[].timing.clear_before, layers[].keys[].anchor, window[].anchor)

Member Type Meaning
line required text The id of a line in sound.speech.
boundary one of onset, offset; default "onset" Which edge of the line: onset or offset.
offset_ms whole number; default 0 A signed offset from that edge.

LandsOn (sound.speech[].lands_on, sound.events[].lands_on)

Member Type Meaning
carrier required text A sound carrier that has a pulse.
unit one of beat, bar; default "beat" Land on a beat or a bar.

BeatFunction (sound.beat_functions[])

Member Type Meaning
id required text A short unique id. A shot's picture.serves names it.
function required one of claim_from_source, law_or_official_fact, where, who, unfilmed_event, action, opinion_or_joke, new_act, figure_of_speech, quote, promise_or_question, sponsor, call_to_action The job the words do there.
start_ms required whole number When the span starts. Beat functions run in time order and do not overlap.
end_ms required whole number When it ends. Inside the work.
speech list of text The ids of the speech lines it covers. Each must overlap the span.
words text A readable excerpt of what is said.
source text The evidence cited, when the words rest on one.
note text Anything else worth saying.

The function of a beat function is one of claim_from_source, law_or_official_fact, where, who, unfilmed_event, action, opinion_or_joke, new_act, figure_of_speech, quote, promise_or_question, sponsor or call_to_action.

SoundBeat (sound.beats[])

Member Type Meaning
start_ms required whole number When the span starts. Beats run in time order and do not overlap.
end_ms required whole number When it ends.
foreground text The carrier in the foreground, or null when nothing owns it.
supporting list of text Carriers heard behind it.
withheld list of text Carriers held back on purpose. A carrier has one role in a beat.
purpose required text Why the sound is arranged this way.
note text Anything else.

SoundBridge (sound.bridges[])

Member Type Meaning
id required text A short unique id.
at_ms required whole number When the change of picture or world happens.
from text The shot before the change.
to text The shot after it.
retained list of text Carriers that carry on across it.
exiting list of text Carriers that stop.
entering list of text Carriers that begin.
rule required text How the crossing is made.

SoundRule (sound.rules[])

Member Type Meaning
id required text A short unique id.
rule required text The rule, as a sentence.
withhold list of text Carriers to hold back.
allow list of text Carriers that may sound anyway.
spans list of SoundSpan When the rule applies.
fails_if list of text What would break the rule, in words.
check text How a reviewer tells whether the rule was kept.
quiet QuietDesign Makes the rule an authored quiet: how it begins and ends.

SoundSpan (sound.rules[].spans[])

Member Type Meaning
name required text A name for the span.
start_ms required whole number When it starts.
end_ms whole number When it ends. Open-ended when absent.

QuietDesign (sound.rules[].quiet)

Member Type Meaning
begins required one of hold_back, cut_off hold_back (sounds are held back from starting) or cut_off.
ends required one of return, reveal, reset return (the same sounds come back), reveal (something new) or reset (the world resets).
must_hold true or false; default false True when nothing may break into the quiet.

SoundEvent (sound.events[])

Member Type Meaning
id required text A short unique id. A pause's for names it.
carrier required text The carrier it is heard on.
at_ms required whole number When it happens, in film time.
what required text What is heard and why it happens here.
lands_on LandsOn Puts the event on a beat or bar of a pulse.
length_ms whole number How long the sound needs to be heard complete. Needed with clear_of_speech.
clear_of_speech true or false; default false True when the sound must not overlap any spoken line; it has its own room.
sync_to text The id of the picture it must match: a shot or layer that starts on it (within 80 ms).
lead_ms whole number The sound anticipates its picture: it is already heard building this long before at_ms, and peaks on it. Needs sync_to. More than 0, at most 4000.
anchor SpeechAnchor The spoken moment it belongs to, so it follows the words when the speech is placed differently. at_ms must agree with it.

SpeechPause (sound.pauses[])

Member Type Meaning
after_line required text The id of the spoken line the pause follows.
length_ms required whole number How long the pause is. The next line must start at least that long after.
for text The sound event the pause is for. Give for or for_join.
for_join text The shot id that a picture join enters, when the pause is for the join. A travel join (a climb, a descent) needs silence to move in, with no sound made for it.
why text Why the pause is there.
hides_speaker true or false; default false True when the speaker's window fades out for the pause (an interlude: the scene plays, then they return).

IntensityPoint (sound.intensity[])

Member Type Meaning
carrier required text A music carrier.
at_ms required whole number From this moment the drums are at this level. Points run in time order.
level required one of rest, low, mid, high, peak How far forward the drums come: rest, low, mid, high or peak.
why required text Why feeling rises or settles here.
ramp_ms whole number; default 1200 How long they take to reach the level, before at_ms.

Takeover (sound.takeovers[])

Member Type Meaning
carrier required text The carrier that rises.
start_ms required whole number When the rise starts.
end_ms required whole number When it ends, later than the start.
from_db required number The level at the start, relative to the carrier's bound level; 0 dB is the voice's level.
to_db required number The level at the end. Above from_db.
why required text Why the sound takes over here.
{"carriers": [
   {"id": "VOICE", "kind": "speech", "job": "The narrator."},
   {"id": "DRUM", "kind": "music", "identity": "a talking drum", "job": "Calls the town.",
    "pulse": {"period_ms": 500, "phase_ms": 0, "beats_per_bar": 4},
    "message": {"language": "Yoruba", "meaning": "Come home.", "phrases": [{"in_ms": 0, "out_ms": 2000}]}}],
 "speech": [
   {"id": "L1", "carrier": "VOICE", "text": "He told me about the money.", "start_ms": 1000, "end_ms": 3000, "source_ms": 0,
    "words": [{"index": 1, "start_ms": 0}, {"index": 5, "start_ms": 1200, "stress_ms": 1300}]},
   {"id": "L2", "carrier": "VOICE", "text": "It's not what you think.", "start_ms": 6000, "end_ms": 7500, "lands_on": {"carrier": "DRUM", "unit": "beat"}}],
 "beat_functions": [{"id": "b1", "function": "claim_from_source", "start_ms": 1000, "end_ms": 3000, "speech": ["L1"], "words": "He told me about the money.", "source": "Tom's brother"}],
 "beats": [{"start_ms": 0, "end_ms": 4000, "foreground": "VOICE", "supporting": ["DRUM"], "purpose": "The voice leads; the drum is under it."}],
 "bridges": [{"id": "br1", "at_ms": 4000, "retained": ["DRUM"], "exiting": [], "entering": ["VOICE"], "rule": "The drum carries over the cut."}],
 "rules": [{"id": "r1", "rule": "Nothing under the confession.", "withhold": ["DRUM"], "spans": [{"name": "confession", "start_ms": 1000, "end_ms": 3000}],
            "quiet": {"begins": "hold_back", "ends": "return", "must_hold": true}}],
 "events": [{"id": "e1", "carrier": "DRUM", "at_ms": 3500, "what": "A single hit as the glass lands.", "length_ms": 800, "clear_of_speech": true,
             "anchor": {"line": "L1", "boundary": "offset", "offset_ms": 500}}],
 "pauses": [{"after_line": "L1", "length_ms": 2000, "for": "e1", "why": "Give the hit room."}],
 "intensity": [{"carrier": "DRUM", "at_ms": 3500, "level": "high", "why": "Feeling rises here.", "ramp_ms": 1000}],
 "takeovers": [{"carrier": "DRUM", "start_ms": 6000, "end_ms": 7500, "from_db": -18, "to_db": 0, "why": "The drum takes the room as he stops speaking."}]}

In the scene. The per-scene parts tell a reader why the sound is as it is.

SceneSound (scenes[].sound[])

Member Type Meaning
kind required one of speech, music, ambience, effect, silence Which kind of sound.
intent required text What it is doing in the scene.
must_not list of text What it must not do.

Hearing (scenes[].hearing)

Member Type Meaning
mode required one of objective, subjective, contrast, silence objective (what is in the world), subjective (what a character hears), contrast (the two against each other) or silence.
quality required one of open, near_body, narrowed, off_axis, muffled, expanding, silent How the world sounds: open, near_body, narrowed, off_axis, muffled, expanding or silent.
whose text For subjective hearing: the character or prop whose hearing it is.
why required text Why the scene is heard this way.

Phrase (scenes[].phrases[])

Member Type Meaning
carrier required text The sound carrier whose phrase this is. One phrase per carrier per scene.
move required one of enter, carry, transform, reprise, exit, foreground What the phrase does: enter, carry on across the cut, transform, reprise, exit or foreground.
timing required one of rhetorical, breath, musical, emphasis What its timing follows: rhetorical, breath, musical or emphasis.
keeps required one of motif, tempo, harmony, motif_tempo_harmony, environment, deliberate_break What stays recognisable: motif, tempo, harmony, all three (motif_tempo_harmony), environment or a deliberate_break.
what required text What the phrase is, in words.
register_from required text Its register at the start.
register_to required text Its register at the end. A carry keeps its register (the same text as register_from); a changed register is a transform (DPL-PHRASE).
placement one of with_picture, before_picture, across_picture, after_picture; default "with_picture" Where it sits against the picture: with_picture, before_picture, across_picture or after_picture.
side one of centre, left, right, both Where it is heard across the stereo field. both is two placements answering each other.
motif text For music: the motif the phrase plays.
shape one of sustain, build, resolve For music: where the cue is heading: sustain, build or resolve.

The kind of a carrier or of a scene's sound is one of speech, music, ambience, effect or silence.

2.9 Transitions

A transition records a join that was decided: what the audience learns across it, what stays the same, the simpler alternatives that were considered and why they were not chosen. A join between shots that is not listed is an unremarked cut. Join only neighbouring shots: from is a shot and to is the shot directly after it, including across a scene boundary.

kind is how the two shots join: cut, match_cut, jump_cut, smash_cut, dissolve, fade, wipe or hold. A hold keeps the subject and framing intent, so the join is felt as a hold. need says why the picture must change here (existing_sufficient, new_world, distinct_planes, comparison, attention_transfer, deliberate_break); simpler is the simplest join that was considered instead (none, hold, reframe, cut). serves says whether the change moves the story on (story) or only moves attention (attention). A join that serves the story needs a purpose saying what happens. If every change in a sequence only moves attention, the validator warns (DPL-MOMENTUM); three joins in a row with the same device is DPL-VARIETY.

With all of this direction, converting tools carry the plan's direction into other formats.

Transition (transitions[])

Member Type Meaning
from required text The id of the shot before the join.
to required text The id of the shot after it. Must be the shot that directly follows.
kind required one of cut, match_cut, jump_cut, smash_cut, dissolve, fade, wipe, hold How the two join.
detail text How the join is played beyond its kind (for example a cut that then holds).
purpose text What the audience learns across the join.
keeps list of text What stays the same across the join.
considered list of ConsideredAlternative Simpler or different joins that were considered, and why each was not taken.
need one of existing_sufficient, new_world, distinct_planes, comparison, attention_transfer, deliberate_break Why the picture must change here.
simpler one of none, hold, reframe, cut The simplest join that was considered instead.
persisting list of text Characters, props or locations that stay in view across the join.
style text A named technique that plays the join beyond its kind (for example analogue_channel_change, inset_expand, light_point_reveal), in lower-case words joined by underscores. Realisation decides how to draw it.
duration_ms whole number How long the join takes, when it is not instant. Above 0. A cut, jump_cut or smash_cut is instant, so has none. A spoken line should not start inside the join (DPL-SPEECH-JOIN).
serves one of story, attention Whether the change moves the story on (story: something happens, is learned or transformed) or only moves the audience's attention (attention).

ConsideredAlternative (transitions[].considered[])

Member Type Meaning
choice required text The join that was considered.
why_not required text Why it was not taken.
[{"from": "K1", "to": "K2", "kind": "dissolve", "purpose": "The room gives way to Maya's face.", "keeps": ["MAYA"], "need": "attention_transfer",
  "simpler": "cut", "considered": [{"choice": "cut", "why_not": "A cut loses the slow turn from room to person."}],
  "persisting": ["MAYA"], "style": "light_point_reveal", "duration_ms": 600, "serves": "story"}]

2.10 Short-form profile

The short-form profile is for shoots made on a phone, or with a small crew and real cameras, in a few hours: a promo, a Short, an interview, a two-person scene. It adds what the first market's constraints need: what the crew shoots with, who is there and when, the light, the shoot day, and where the work is delivered. It is opt-in. A plan says work.profile: "short"; a plan that does not (film is the default, and what every plan written before the profile is) reads, validates and is checked exactly as it was, and none of the rules below run on it. Every member below is optional and additive, and reading is as strict as everywhere else: an unknown member or a misspelt term is an error.

Shoot Plan (the Shoot Plan app's own planner) plans the same kind of shoot for people. The short-form rules are ported from its rules (planner rules 2026-10-06.r6) and cite them, so the two agree; tools/dpl/import/shoot_plan_to_dpl.py turns a Shoot Plan plan into this profile (see "From Shoot Plan" below).

A complete short-form plan: one presenter, a phone, one morning. It validates with no diagnostics. The kit, the people, the location's light, the delivery and the day are what the short-form rules read.

{
  "format": "dpl.plan/1",
  "work": {"id": "first-loaf", "title": "The first loaf", "profile": "short", "target_runtime_ms": 9000},
  "delivery": {"aspect": "9:16", "max_runtime_ms": 30000, "platform": "Instagram Reels"},
  "kit": {
    "cameras": [{"id": "phone", "kind": "phone", "description": "Main phone", "lens_multipliers": [0.5, 1, 3], "frame_rates": [24, 30, 60]}],
    "supports": ["handheld", "tripod"],
    "sound": ["phone_mic", "lav"],
    "lights": ["reflector"]
  },
  "people": [
    {"id": "maya", "name": "Maya", "roles": ["talent"], "character": "MAYA", "available": [{"from": "08:30", "to": "11:00"}]},
    {"id": "sam", "name": "Sam", "roles": ["camera", "sound"]}
  ],
  "characters": [{"id": "MAYA", "description": "Maya, who runs the bakery."}],
  "locations": [{
    "id": "FRONT", "description": "The bakery's front step in the morning.",
    "setting": "outdoor", "usable_light": [{"from": "07:30", "to": "16:30"}],
    "sun": "Low from the south-east until about 10:00", "acoustics": "quiet"
  }],
  "scenes": [{
    "id": "S1", "purpose": "Maya shows the first loaf of the day.", "start_ms": 0, "end_ms": 9000, "location": "FRONT",
    "provenance": {"by": "human"},
    "lines": [{"id": "L1", "speaker": "MAYA", "to": "camera", "start_ms": 500, "end_ms": 6000, "text": "First loaf of the day."}],
    "shots": [
      {
        "id": "S1A", "purpose": "Maya says it to the camera.", "subject": "MAYA", "start_ms": 0, "end_ms": 6000,
        "camera": {"size": "medium", "movement": "hold", "lens_multiplier": 1, "support": "tripod", "device": "phone", "orientation": "portrait"},
        "source": "footage", "characters": ["MAYA"], "coverage": {"role": "single", "priority": "must"}, "setup": "A",
        "filming": {"speech": true},
        "provenance": {"by": "human"}
      },
      {
        "id": "S1B", "purpose": "The loaf, close.", "subject": "The loaf on the board.", "start_ms": 6000, "end_ms": 9000,
        "camera": {"size": "detail", "movement": "hold", "lens_multiplier": 3, "support": "tripod", "device": "phone", "orientation": "portrait"},
        "source": "footage", "coverage": {"role": "insert", "priority": "should"}, "setup": "B",
        "provenance": {"by": "human"}
      }
    ]
  }],
  "schedule": {"days": [{
    "id": "day1", "date": "2026-10-24", "start": "09:00", "end": "10:00", "locations": ["FRONT"],
    "setups": [{"id": "A"}, {"id": "B", "not_before": "09:20"}],
    "tasks": [{"id": "tone-front", "kind": "room_tone", "location": "FRONT"}]
  }]}
}

Clock times are "HH:MM", 24-hour, with two digits each ("09:30", never "9:30" or "9.30am"); anything else is DPL-CLOCK. A window (from, to) is a span of clock time on a shoot day; with a day (a day id of the schedule) it applies on that day, without one on every day.

Work. work.profile is film (the default) or short. A plan with short-form members and no short profile gets one DPL-PROFILE warning and nothing else: the members are read and kept, and no short-form rule runs.

Delivery (delivery)

Member Type Meaning
aspect required one of 9:16, 16:9, 1:1, 4:5 The picture shape the work is delivered in. A vertical frame (9:16, 4:5) is filmed with the camera upright, a 16:9 frame sideways, and a 1:1 frame is cut from either.
max_runtime_ms whole number The longest the finished work may run, in milliseconds (a platform's limit). Must be above 0.
platform text Where it is posted (free text).

Real crews are served as well as phones: a camera is a phone (lenses as multipliers) or a camera (lenses in millimetres). A kit that lists nothing for a thing (a camera with no lenses, no supports, no frame rates) says nothing about it, so the check for that thing does not run, and dpl missing asks.

Kit (kit)

Member Type Meaning
cameras list of KitCamera The phones and cameras the crew has.
supports list of one of handheld, gimbal, tripod, clamp, slider, shoulder, dolly, jib, crane, steadicam, drone What can carry the camera. Hands are always there for a handheld shot. handheld, shoulder, gimbal and steadicam need an operator holding the camera; the rest stand on their own.
sound list of one of phone_mic, lav, shotgun, recorder The sound gear.
lights list of one of none, practical, led_panel, reflector The lights. none says there are none and cannot be listed with another.

KitCamera (kit.cameras[])

Member Type Meaning
id required text A short id, unique among the kit's cameras. A shot's camera.device names it.
kind required one of phone, camera A phone has lens_multipliers; a camera (mirrorless, DSLR, cinema) has lenses.
description text The device in words ("iPhone 15", "Sony FX3").
lens_multipliers list of number For a phone: its lenses as multipliers of the main camera, for example [0.5, 1, 3].
lenses list of KitLens For a camera: its lenses.
crop_factor number For a camera: the sensor's crop factor against full frame (1 full frame, 1.5 APS-C, 2 Micro Four Thirds). Used to say what a focal length frames like.
sensor text For a camera: the sensor in words ("full frame", "Super 35").
frame_rates list of number The frame rates it records, in frames per second.

KitLens (kit.cameras[].lenses[])

Member Type Meaning
mm number A prime lens's focal length in millimetres.
min_mm number A zoom's shortest focal length in millimetres. Give min_mm and max_mm together.
max_mm number A zoom's longest focal length.

A lens is a prime (mm) or a zoom (min_mm and max_mm), never both and never neither (DPL-KIT).

Camera terms for the profile. A shot's camera has, besides the DPL terms of section 4: lens_multiplier (a phone's lens, for example 3) or focal_mm (a camera's lens in millimetres), never both; support (what carries the camera, from the kit's supports); device (a kit camera's id, so the shot is checked against that camera's lenses; any camera that can film it otherwise); frame_rate (frames per second, for a rate that is not the usual one, such as slow motion); and orientation (portrait, landscape or square: how the camera is held, which decides the frame's shape). The industry vocabulary (section 4) has no term for a support, an orientation or a multiplier. It does describe lenses by focal length (a wide-angle lens is 18 to 35 mm on the 35 mm frame it measures against), so dpl shot-list names a focal_mm lens with the nearest MovieLabs lens term, as an approximate match, after the crop factor; the vocabulary's one other overlap, Gimbal Shot as a synonym of Steadicam Shot, is why a gimbal is accepted for the steadicam move.

People are the cast and crew, each with roles and the times they are there.

Person (people[])

Member Type Meaning
id required text A short id, unique among the people.
name text Their name.
roles required list of one of talent, camera, sound, director, helper What they do on the shoot. At least one. One person may have several.
character text For talent: the id of the character they play, so a shot that shows the character needs this person.
available list of TimeWindow When they are on hand. Without any they are on hand all day, every day.

TimeWindow (people[].available[], locations[].usable_light[], locations[].access[])

Member Type Meaning
day text The shoot day (a day id of the schedule) it applies to; every day when absent.
from required text When it starts ("HH:MM").
to required text When it ends ("HH:MM"), after from.

Locations. The existing time_of_day and light stay prose for the people reading the plan. The profile adds typed facts beside them: setting (indoor or outdoor), usable_light (windows by clock time when there is light to film in; outdoors it is the daylight, indoors say it only when daylight is what lights the room), sun (where the sun is, in words, if known), access (windows when the crew may be at the place; without any, always), acoustics (quiet, controllable: the noise can be switched off, or fixed: it cannot) and quieter_position (true when a speaker may move somewhere quieter).

The schedule is the shoot days. A shot points to its day through its setup (the existing grouping of shots filmed from one camera position): the day lists the set-ups it films, in the order they are filmed. A shot whose set-up is on no day goes to the day that uses its scene's location. Shot ids and set-up ids are the keys a later take log (dpl.takes/1) records takes against, so none is made from order.

Schedule (schedule)

Member Type Meaning
days required list of ShootDay The shoot days. At least one.

ShootDay (schedule.days[])

Member Type Meaning
id required text A short id, unique among the days. A window's day names it.
date text The calendar date, YYYY-MM-DD, when it is known.
start required text When the day starts ("HH:MM").
end required text When it ends ("HH:MM"), after start.
locations list of text The locations the day uses (location ids).
setups list of DaySetup The set-ups filmed this day, in the order they are filmed.
moves list of Move How long it takes to travel between two locations (either way).
tasks list of CaptureTask Filming that makes no picture: room tone, a voiceover.

DaySetup (schedule.days[].setups[])

Member Type Meaning
id required text A set-up id: the setup of the shots filmed from it. A set-up is filmed on one day.
not_before text The set-up cannot begin before this clock time (the place opens, a person arrives). The crew waits.
at text The set-up must begin at this clock time: an event that happens then, ready or not. The day is late if the crew is not. Not with not_before.

Move (schedule.days[].moves[])

Member Type Meaning
from required text A location id.
to required text A location id.
minutes required whole number How long the move takes. 0 or more.

CaptureTask (schedule.days[].tasks[])

Member Type Meaning
id required text A short id, unique among the tasks.
kind required one of room_tone, voiceover What is recorded. Room tone goes last before leaving a place.
location required text Where it is recorded (a location id).
minutes whole number How long it takes, when not the profile's own figure for this kind.

filming on a shot says how it is filmed, when that is not what its coverage role implies.

Filming (scenes[].shots[].filming)

Member Type Meaning
role text A timing role of the profile's timing file (contracts/dpl/profiles/short-timing-1.json): Shoot Plan's own role names, such as MASTER, SINGLE and INSERT. When absent, the shot's coverage.role picks one.
takes whole number How many takes are planned, 1 or more. The role's own number when absent; a once shot is one.
record_ms whole number The recording that must be usable, in milliseconds, when it is more than the role's minimum. Absent, it is the role's minimum or the shot's length in the film, whichever is longer.
speech true or false The shot records people speaking. When absent it does if a line of its scene is spoken during it.
once true or false The moment happens once and cannot be filmed again, so it is recorded in one go with a margin either side.
preroll_ms whole number For a once shot: how long before the moment the recording starts. The profile's figure when absent.
postroll_ms whole number For a once shot: how long after it ends the recording runs on.
with text A shot of this plan filmed at the same time, by a second camera. This shot takes no time of its own.

A scene or a shot may say who or what set it: provenance is { "by": ..., "ref": ... } with by one of human, draft_model, shoot_plan_planner, script_import or ingress, and an optional ref naming what it came from (a Shoot Plan shot id, a script line). It is inert metadata: no rule reads it. (It is not called source, which a shot already has: what the picture is made from.)

Provenance (scenes[].provenance, scenes[].shots[].provenance)

Member Type Meaning
by required one of human, draft_model, shoot_plan_planner, script_import, ingress Who or what set the element.
ref text What it came from, when that can be named.

How the day is worked out. The shoot day is added up the way Shoot Plan's scheduler does it, with its own figures (the timing file, each value citing its Shoot Plan rule and rules version): the day's preparation; then for each visit to a location a move, a wait for access, the location setup and, before the first speech there, a sound check; each shot takes its role's working time (its setup, then its takes, each of recording plus a pad either side, and a reset between takes); room tone and voiceover tasks go last before leaving; and the spare time is the larger of 5 minutes and 15% of the work done (waiting excluded). The day's committed time is the work plus the spare time, and it must fit between start and end. The order is the plan's: set-ups as the day lists them, shots in plan order inside a set-up. Nothing searches for a better order.

The short-form rules (dpl readiness; each finding says in its message which expectation breaks, and the rules are in docs/capability/EDIT_READINESS.md). They are production-feasibility findings, listed after the story and rhythm findings and before the eye-trace and space ones. Major means the shot cannot be filmed as planned.

Code Severity What it finds
RDY-PEOPLE major A person in the frame is not there for the whole shot; no camera operator is on hand; or one person would hold the camera and be in front of it.
RDY-LIGHT major A shot at an outdoor place (or one with light windows) is filmed outside its usable light.
RDY-KIT major A shot asks for a lens, a frame rate, a support or a camera move the kit does not have. The fix is the nearest alternative.
RDY-TIME major, minor A day does not fit: major when the work alone is over, minor when only the spare time is used; also a shot outside its place's access window, a late fixed start, and a shot on no day.
RDY-DELIVERY major, minor The work runs longer than delivery.max_runtime_ms (major), or a shot is held the wrong way for the aspect (minor).
RDY-SHORT-SOUND major Speech where the noise cannot be switched off, with only the camera's microphone and no quieter place. Mirrors Shoot Plan's sound method (test F02).
RDY-SHORT-ONCE minor A moment filmed once does not roll before and after it (Shoot Plan's INV-03), and no second camera has it.
RDY-SHORT-DIALOGUE minor A conversation lacks a wide two-shot or a single for each speaker (Shoot Plan's two-person recipe, rules r2).
RDY-SHORT-TONE minor Speech is filmed at a place with no room tone planned (Shoot Plan's INV-05).

Ask the plan what it is missing. A short-form plan with no kit, delivery, people or schedule gets no feasibility check at all, each rule returning without a word. dpl missing asks for them (kinds kit, delivery, people, schedule, light and sound), with the answer's shape.

From Shoot Plan. tools/dpl/import/shoot_plan_to_dpl.py plan.json [--intake intake.json] --out plan.dpl.plan.json reads a Shoot Plan plan (and, if given, the intake it was made from) and writes this profile. Every element carries provenance shoot_plan_planner; each Shoot Plan shot keeps its id; minute 0 of the shoot is put on the clock at --day-start (09:00 by default). What DPL has no place for is listed in an import report beside the plan, never dropped. The converted Shoot Plan examples are in tests/corpus/short/.

{"id": "FRONT", "description": "The bakery's front step in the morning.", "setting": "outdoor",
 "usable_light": [{"from": "07:30", "to": "16:30"}], "access": [{"from": "07:00", "to": "12:00"}],
 "sun": "Low from the south-east until about 10:00", "acoustics": "fixed", "quieter_position": false}
{"role": "MASTER", "takes": 1, "record_ms": 40000, "once": true, "preroll_ms": 60000, "postroll_ms": 30000, "speech": true}
{"id": "cam-b", "kind": "camera", "description": "Mirrorless body", "lenses": [{"mm": 35}, {"min_mm": 24, "max_mm": 70}],
 "crop_factor": 1.5, "sensor": "APS-C", "frame_rates": [24, 25, 50]}

3. Which details make the checks work

The edit-readiness checks (dpl readiness) read typed facts, not prose. A check whose facts are absent returns without a finding, which is not the same as passing: not_assessed in the findings, and dpl missing, say when that happened. So a plan that wants the checks to speak must give them the details below. The rules themselves, and the corrected table of what each one needs, are in docs/capability/EDIT_READINESS.md.

Give the plan this Where It switches on
The line of action a scene's axis, with the shots' staging of its two people RDY-AXIS: a cut across the line. A shot's coverage role neutral, or crosses_line, lets a deliberate crossing pass.
Who speaks to whom a scene's lines, with to on each (a character, or camera, audience or group), and turn on the line that turns the scene RDY-REACTION (a turning line's listener is seen as it lands, or in the second after it), RDY-SPEAKER (a speaker is seen during their lines, a speaker's first line is not played entirely over shots that do not show them, and a turning line is not played over neither speaker nor listener), RDY-EYELINE (two singles in conversation do not look the same way). With an axis on the pair, RDY-EYELINE steps aside for them. A line said to camera, audience or group has no character listener, so none of the three expects a reaction, a listener or a pair of eyelines for it.
Where people stand staging of two or more plan characters (side, facing) RDY-GEOGRAPHY: the audience is shown where everyone is before the singles. coverage roles only refine it. It is skipped for an entry whose how is return or continue, and overridden when the scene's attention disorients or withholds.
Which shots are the same set-up setup on the shots, or staging on the first RDY-JUMP: two shots with the same people in frame (the staged subjects, else characters) at the same size from the same set-up, joined by a plain cut.
What each shot is for coverage role and priority RDY-HOLD (an insert, reaction, cutaway or neutral held long past its job, relative to the film's pace; work.house_style.readiness sets absolute limits), and dpl replan, which never drops a must.
Which way things travel staging moving on the shots RDY-TRAVEL: screen direction reversed without a neutral shot or a turn seen on screen. A scene's travel alone does nothing: it only sets the direction the first moving shot is held to.
How props change states on shots and/or state_changes; at least two facts about one prop RDY-STATE: a prop shown in a state the changes contradict.
A change that must be seen a state_changes entry with shown: true, and the shots' props (or states) RDY-UNSEEN: a change with no shot of the prop as it happens.
A journey journey (the plan's or a sequence's), and journey_stage on the scenes it governs RDY-JOURNEY-UNANCHORED, -PROGRESS, -JUMP and -CARRIED: each change of stage is a move forward along the axis, and the route arrives. A plan with sequences but no journey is not held to one.
What the narration is doing sound.beat_functions, picture kind and serves on the shots the RDY-BEAT-* rules below. All return at once when beat_functions is empty. RDY-BEAT-PRESENTER also needs house_style.presenter.
The house structure work.house_style.structure the RDY-STRUCT-* rules below. The sponsor and cold-open rules also read sound.beat_functions.
A deliberate departure a scene's accepts, or attention with disorient or withhold the finding is reported as overridden, with your reason, not as a fault.

Beat functions and the house structure receive these findings (each scene can accept a code with a why):

Code Severity Meaning
RDY-BEAT-SOURCE major A sourced claim, official fact or quote has no visible source in its span
RDY-BEAT-ACT major A new act has no chapter card
RDY-BEAT-PRESENTER minor The house-style presenter is absent for longer than max_gap_ms (default 120,000), counting from the film start and to its end, or never appears
RDY-BEAT-SPONSOR minor The sponsor span includes a picture outside the sponsor set
RDY-BEAT-UNSERVED minor No overlapping shot explicitly declares the beat id in picture.serves
RDY-STRUCT-COLD-OPEN minor Presenter appears before the house-style hold-back time
RDY-STRUCT-SPONSOR-LOOP minor The fixed sponsor words do not immediately follow an open-question beat; advisory only
RDY-STRUCT-SPONSOR-RETURN minor Picture does not change near the first spoken word after the sponsor
RDY-STRUCT-SUBSCRIBE minor Prompt is missing, outside its window, or over presenter/evidence
RDY-STRUCT-END-CARD minor Closing recommendation and subscribe construct does not span the final window

Ask the plan what it is missing. dpl missing plan.json says, in the plan's own names, what to ask the person who knows the film so the checks can read it ("In scene S1, which side of the line between MAYA and TOM is the camera on, and where does each stand?"), with the paths the answer fills and the rules it unlocks. It exits 4 when a question blocks the assessment of a scene. Do not invent a detail to silence a question. When the honest answer is "none", say so with none ("Saying no", 2.6): a scene where nobody speaks declares spoken_lines, a scene staged without a line of action declares line_of_action with its reason, and a film that goes nowhere declares journey. The question is then answered and no longer asked.

4. Camera terms and the industry vocabulary

Plans use DPL's own camera terms (Terms.cs):

Field Terms
size extreme_wide, wide, full, medium_wide, cowboy, medium, medium_close_up, close_up, extreme_close_up, detail, macro
angle overhead, high, eye_level, shoulder_level, low, hip_level, knee_level, ground_level, worms_eye, dutch
movement hold, handheld_hold, pan, whip_pan, tilt, push_in, pull_out, track, dolly, crab, arc, orbit, zoom, dolly_zoom, vertigo, handheld, steadicam, boom, jib, crane, pedestal, roll, aerial, helicopter, drone, rise, drift, descend
lens fisheye, ultra_wide, wide, medium, telephoto, super_telephoto, anamorphic_ultra_wide, anamorphic_wide, anamorphic_medium, anamorphic_telephoto
perspective objective, subjective, witness, inspection, over_the_shoulder (DPL only)

They follow common industry usage, and each is mapped to the MovieLabs Creative Vocabulary in a pinned, versioned table (IndustryVocabulary/). The mapping says how close each match is:

MovieLabs' Establishing Shot is the one v1.0 term no DPL term maps to: in DPL, establishing is what a shot is for (its purpose, or its coverage role), not a size. perspective has no MovieLabs category.

Upgrading. Plans store DPL terms only, so a new MovieLabs version never invalidates a plan. Adopting one means adding a mapping class for it, checked by the tests against the published file, and listing it in IndustryVocabularies.All; renderings then use it by default, and earlier versions stay selectable (--vocabulary movielabs@1.0). The v1.0 mapping is checked against the pinned file (SHA-256 6bdbbec4…, from the 7 September 2026 design freeze): hash, version, every slug and every term name.

5. Validation

The schema (contracts/dpl/dpl.plan-1.schema.json) describes what the reader accepts. Reading is strict: an unknown member, a misspelt term ("Hold", "PushIn", "static-shot"), a missing required member, or a fractional millisecond is an error, never silently defaulted or ignored.

A plan that reads is then validated: ids are unique and every reference resolves, times run forward and stay inside their scene and the work, required text is not empty, and the editorial and sound rules hold. Each fault is reported with a DPL-* code, an error (the plan is unusable downstream) or a warning (for a director to look at). The full list of codes, with what each enforces, is the one table in contracts/dpl/README.md; it is checked against the code by a test, so this page does not repeat it.

Reading diagnostics

Each diagnostic has five parts: the code (the rule), the severity (error or warning), the path (a JSON path into the plan, such as $.scenes[1].shots[0].purpose), the message (what is wrong) and the fix (what to change next). dpl validate plan.json prints the first four, one line each, and exits 1 when there is an error. dpl validate plan.json --format json writes all five as dpl.diagnostics/1 (schema contracts/dpl/dpl.diagnostics-1.schema.json):

{
  "schema": "dpl.diagnostics/1",
  "plan_hash": "9f2c1e7ab04d58c3e6a1f20b97d4c85e3a6b1d0f2e8c7945a3b6d1e0f4c2a8b7",
  "valid": false,
  "summary": { "errors": 1, "warnings": 0 },
  "diagnostics": [
    {
      "code": "DPL-DUPLICATE",
      "severity": "error",
      "path": "$.scenes[2].shots[0].id",
      "message": "Shot \"SH01\" appears twice.",
      "fix": "Rename $.scenes[2].shots[0].id to an id no other shot uses, for example \"SH05\"; shot ids are unique across all scenes (first use: $.scenes[0].shots[0])."
    }
  ]
}

The other commands say what to do next in their errors too: dpl apply lists the finding ids, or the fix ids on that finding, when the one you gave does not exist; dpl replan says which limit could not be met, by how much, and what to relax; any input that cannot be read names what was expected there. Exit codes are unchanged.

Slices

dpl slice cuts some scenes of a plan, with everything they refer to, into a smaller plan of its own, so an agent can work on one scene without holding the whole film (docs/dpl/DPL_CONTEXT_TOOLS.md). A slice is an ordinary valid plan; the one thing that marks it is slice_of.

SliceOf (slice_of)

Member Type Meaning
plan_hash required text The revision of the whole plan the slice was cut from: SHA-256 of the whole plan in its standard layout, the same hash dpl readiness reports for it.
scenes required list of text The scenes the slice holds, in the whole plan's ids.
shots required list of text The shots the slice holds, in the whole plan's ids.
{"plan_hash": "9f2c1e7ab04d58c3e6a1f20b97d4c85e3a6b1d0f2e8c7945a3b6d1e0f4c2a8b7", "scenes": ["kitchen"], "shots": ["k1", "k2", "k3"]}

A slice keeps the whole film's clock (its first scene may start well after 0). Because a plan with slice_of is cut from a longer film, dpl validate does not report the time before its first scene as a DPL-GAP, RDY-JOURNEY-PROGRESS does not say it fails to arrive when it holds no scene at the destination, and RDY-STATE does not judge a prop against a state it only guessed from its first shot (docs/dpl/DPL_CONTEXT_TOOLS.md). A hand-written plan never needs slice_of; leave it out.

6. Renderings

Both are derived from the plan and add nothing to it. Neither is produced from a plan with errors.

7. Command line

dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- validate plan.json [--format json]   # exit 0 valid, 1 invalid; json: dpl.diagnostics/1 with a fix for each
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- shot-list plan.json [--format json] [--vocabulary movielabs@1.0]
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- suggest-pictures plan.json [--format json]  # advisory only
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- format plan.json         # standard layout
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- terms                    # DPL terms and industry names
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- readiness plan.json [--format json]   # edit-readiness findings
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- apply plan.json findings.json <finding> <fix>
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- replan plan.json constraints.json [--out revised.json] [--format json]   # dpl.replan/1
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- bench tests/corpus/readiness   # the benchmark (short-form mutants included)
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- missing plan.json [--format json]    # what to ask the human (dpl.missing/1); exit 4 when one blocks
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- takes validate plan.json takes.json    # the take log (dpl.takes/1) against the plan; see docs/dpl/DPL_TAKES.md
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- takes merge a.json b.json [--out merged.json]   # join two take logs by op_id; exit 6 on a conflict
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- coverage-status plan.json takes.json [--location L] [--format json]   # "did we get it?" (dpl.coverage-status/1); exit 5 while a must-have shot has no good take
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- draft start brief.json [--format json] [--plan-out skeleton.json]   # a valid skeleton plan, the layers to write it in, the first action (dpl.draft/1); see docs/dpl/DPL_DRAFTING.md
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- draft next plan.json [--brief brief.json] [--format json]   # the layer reached, what it lacks, the questions, tested fixes, one next action (dpl.draft-next/1)
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- draft gate plan.json [--format json]   # ready to shoot? pass or fail with a certificate (dpl.draft-gate/1); exit 7 on a fail
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- schema plan                 # JSON Schema: plan | findings | shot-list | constraints | diagnostics | missing | replan | bench | takes | coverage-status | brief | draft | draft-next | draft-gate | draft-grammar | summary | diff | dispositions
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- summary plan.json [--findings f.json] [--format json|markdown]   # the plan in about 300 words (dpl.summary/1)
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- slice plan.json --scene S1 | --shots a,b | --sequence Q    # a sub-plan with slice_of
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- diff old.json new.json [--old-findings f --new-findings g]   # what changed, by id (dpl.diff/1)
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- disposition plan.json <finding-id> accepted --reason "..." --by name   # dpl.dispositions/1
dotnet run --project tools/dpl/VideoEditor.Dpl.Cli -- readiness plan.json --dispositions d.json   # remembered decisions hold while the evidence is unchanged

- reads the plan from standard input. Exit codes: 0 success, 1 invalid plan, 64 usage, 65 not UTF-8 (or JSON that is not what the command expects, such as a malformed constraints file), 66 cannot read the file. readiness, reconcile and bench use 2, replan uses 3 when the constraints cannot be met, missing uses 4 when a question blocks the assessment of a scene, coverage-status uses 5 while a must-have shot in scope has no good or circled take, takes merge uses 6 when one op_id names two different takes, and draft gate uses 7 when the plan is not ready.

8. Not in this version