Project specification
A plain-text format for describing a film.
| Version | 1.5 — Draft |
| Date | 10 September 2026 |
| Format version | "filmopen": 1 |
| Status | Public draft. Open for comment. |
| Licence | This specification: CC-BY-4.0. The JSON Schemas derived from it: CC0. |
| Canonical URL | https://filmopen.ai/spec |
| Schemas | https://filmopen.ai/schema/1/ |
Abstract
Section titled “Abstract”A FilmOpen project is a folder of plain JSON files that describes a feature film, series or short completely: its characters, places, props and looks; its script; its shots and sound; and the media that realises them. The format is designed to be read and written by people, by scripts, and by AI systems; to reduce file conflicts when many contributors work on one film; and to remain fully meaningful as a bare folder of files with no software present.
It serves two directions equally. Forward: write a film in text and generate it with AI models. Reverse: analyse an existing film and describe it in text, so that it can be studied, adapted, translated or regenerated.
Changes in 1.5
Section titled “Changes in 1.5”- Kind.
kindis now one ofshort·feature·miniseries·series(§8.1). Readers read the 1.4 words as their nearest value:filmasfeature,franchiseasseries. - Every project declares its epochs, and every library entity has one.
epochsis required in the project file with at least one entry; the first in order is the project’s default epoch, the one an implicit reference falls back to (§6.1, §8.2). An epoch may carry ayear. A character may carry abirthYear; a reader proposesappearance.ageat each epoch from the two and the author overrides it (§9.1). The reserved tokendefaultremains valid as an epoch name. - Version label. The common header gains an optional
label: a short word for the version in version lists (§7). It does not travel with a fork. - The creator directs. A writer that creates a project lists its creator in
contributorswithrole: "director"(§8.3, §18.3). - Pick. The version an author marks with
preferin their commentary is their pick; an application shows it beside official and lets the author change it (§13.4). Removing an official pointer is done by deleting the pointer file (§13.2).
Changes in 1.4
Section titled “Changes in 1.4”- Project manifest. A project folder is identified by one file with a fixed name at its root,
filmopen-project.json(§4.4). It holds the settings that belong to the folder rather than to any author’s version of the film: the project tag and where the rendered media lives. It is not versioned, not authored and not creative content; it is the one file an application writes when it creates a project. - Media root. Rendered and imported media may live in a separate folder from the JSON — a folder synced by a different service, or a folder outside version control. The manifest names it with a typed locator (§4.4); takes are discovered there (§12.1) and media references resolve against it (§6.3). Absent a manifest, the project folder is its own media root, as in 1.3.
- Shared library location. Models, platforms and plugins are the application’s shared library (§14.5), installed and updated independently of any project and of the application itself. A project folder need not contain them; a project may still hold its own.
Changes in 1.3
Section titled “Changes in 1.3”- Authored projects.
pj_<tag>_<author>_v<n>.jsonuses the same author, version andforkedFromconventions as other spec entities. A remake can change language, title, delivery settings and story roots in its own complete project file (§4.1, §8.6). - Project selection. Opening an explicit project file selects it. Folder opening uses the project official pointer, a sole author’s highest version, or an explicit user selection. The selected project supplies the context for reference resolution and export.
- Portable references. Grouped reference media, epoch choices, plain paths and URLs remain supported. Story-root and child lists accept tags or full entity references.
- Consistent examples. The worked example has a resolvable style, a declared import batch, explicit ambience trim and frame-aligned timings. Provider definitions are identified as outside that example.
- Plugin contracts. Validation inputs and response timing are clarified. Code trust is an application decision; an official pointer is a creative selection, not permission to execute changed code.
- Editor handoff. Final Cut Pro 7 XML is distinguished from FCPXML; relinking and export guarantees are limited to supported, tested behavior.
The format identifier remains "filmopen": 1 during draft development. This is a revised draft, not a
promise that all previous draft projects validate unchanged. To update a 1.0/1.2 project, give its
pj_<tag>.json an author and version in the filename and header, update any explicit references to it,
and add an ordered story-root list (an empty list is valid for a blank project). No history records or
migration database are required. Grouped refs and fractional frame rates added in 1.2 remain optional.
Contents
Section titled “Contents”- Introduction
- Design principles
- Concepts and terminology
- Project structure
- Naming
- References and resolution
- Common header
- The project file
- Library entities
- Story structure and script
- Shots and cues
- Takes and render batches
- Versions, official, compare and commentary
- Extensibility: hooks, plugins, workspaces, shared library
- Timeline export and round-trip
- Interchange with existing standards
- Editing by hand or by machine
- Conformance
- Not in this version
Appendix A — Attribute vocabulary Appendix B — Worked example Appendix C — MovieLabs OMC correspondence
1. Introduction
Section titled “1. Introduction”1.1 Purpose
Section titled “1.1 Purpose”Film has mature interchange standards for the script (Fountain, FDX) and for the finish (ASC CDL, LUTs, OpenTimelineIO, EDL, FCPXML). It has nothing for the structured middle — the description of characters, places, props, looks and shots that an AI production pipeline needs, and that a collaborative team needs to share. This specification fills that gap.
1.2 Scope
Section titled “1.2 Scope”This document defines:
- the folder and file layout of a project;
- the filename grammar that makes every file self-describing;
- the JSON content of each file type, with a small required header and a large optional vocabulary;
- how files refer to one another and how references resolve;
- how versions, forks, official selections and commentary work;
- how rendered and imported media is recorded;
- how the project maps to a timeline for an editing application;
- how the format extends through hooks and plugins;
- how it maps to and from existing standards.
It does not define any application, user interface, storage service, or rendering model. Application conveniences — caches, indexes, autosave, job queues — never become mandatory project files.
1.3 Audiences
Section titled “1.3 Audiences”- Filmmakers, who may use an application or read and edit the files themselves, and must never be required to do the latter.
- Developers, who should be able to understand the entire format in an afternoon.
- Automated systems — scripts, pipelines and AI agents — that read and write projects directly.
1.4 Conventions
Section titled “1.4 Conventions”The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119. A reader is any software or person consuming a project. A writer is any software or person producing or modifying one.
Requirements define syntax and how a reader interprets data. They cannot stop anyone editing a file. Authorship and review conventions are human governance, not security features (§2, principle 8).
All examples are illustrative; some omit optional content. Field names in monospace are normative;
the values shown are not. Model and platform names in examples do not promise any provider’s current
capabilities.
2. Design principles
Section titled “2. Design principles”- Plain JSON, complete documents. Every file fully describes one thing. There are no deltas, overlays, inheritance, reserved key prefixes, canonical serialisation rules, or content-hash addressing of JSON. Any JSON tool works.
- One writer per file. The author’s handle is in the filename, and by convention nobody else edits that file. This reduces shared-folder conflicts and makes comparison meaningful. A delegated edit to someone else’s file is still a valid file; a reader warns, and the maintainer decides.
- Self-describing filenames. A filename states what a file is, whose it is, and which version. Directories organise; they carry no meaning.
- Fork is copy. Versions are whole files:
v1,v2,v3. Forking copies a file into your name. Files are edited in place; a new version is a deliberate act, not a side effect of saving. - Official is a pointer. A small
_official.jsonfile names the version the project has chosen. It neither locks that file nor authenticates its author. - Reference within, copy across. Inside one author’s work, files point at each other. Across authors, content is copied. Media is always referenced, never duplicated.
- Media sits beside the JSON, named so that any generated file traces back to its source. Imported media may keep its own name and is referenced by path.
- Warn, don’t enforce. Every file is editable text. Conventions are checked by readers and reported; nothing is locked. Whoever gatekeeps a shared repository makes the final call.
Git is optional. A project is a folder — on a disk, on a phone, or in a synced Drive or Dropbox folder. Principles 2 and 3 reduce conflicts; simultaneous edits can still conflict. Git is layered on when a team wants history or pull requests; history belongs to Git, and the format does not duplicate it.
3. Concepts and terminology
Section titled “3. Concepts and terminology”| Term | Meaning |
|---|---|
| project | A folder holding a film, series or franchise and its alternatives. An authored pj_ file at its root describes one complete project version. |
| author | A handle naming the writer of a file. A person (maria) or a workspace or plugin run within a person’s identity (maria.locale-th). |
| owner | The person behind an author handle: its first segment. |
| entity | Anything described by one JSON file: character, location, scene, shot, model, … |
| library entity | A reusable thing with an epoch axis: character, outfit, location, prop, style, misc, document. |
| epoch | How a library entity appears at a point in the story: 30yo, pre-war, 1990s, wrecked. Declared in the project file, at least one; the first is the default epoch. Each epoch of an entity is a separate, complete file that shares the entity’s tag. |
| story unit | A level of the script: season or installment, episode or act, sequence, scene. |
| block | One unit of script inside a scene: a line of dialogue, an action, a title. |
| shot | A visual generation spec covering one or more blocks. |
| cue | An audio generation spec: dialogue, narration, music, sound effect, ambience. |
| take | One rendered or imported output of a shot, cue or library entity. A media file. |
| render batch | The record of how a set of takes was produced, imported, or generated by a plugin. |
| media reference | A take stem, a project-relative path, or a URL (§6.3). |
| version | A whole file, v1, v2, … The highest is the author’s working copy. |
| official | The version the project has chosen for an entity, named by a pointer file. |
| prefer, pick | A version one author would choose, recorded in their commentary. An opinion, not a decision. |
| picks | Inside an entity, which take(s) its author chose. |
| commentary | An author’s likes, ratings, comments and preferences about an entity. |
| placement | Where a shot or cue sits on the timeline: track, anchor, offset, trim. |
| hook | A short JavaScript function inside a model, platform, style or project file. |
| plugin | A packaged JavaScript extension that transforms, analyses, imports or exports. |
| workspace | A derived author handle (john123.wild) that keeps a body of work separate from the owner’s main versions. Plugin runs are workspaces. A filename convention, nothing more. |
4. Project structure
Section titled “4. Project structure”4.1 The folder
Section titled “4.1 The folder”A project folder contains one project tag and one or more pj_<tag>_<author>_v<n>.json files at its
root. They are complete alternatives of that project, with an optional pj_<tag>_official.json pointer.
Other entity files may be organised in subfolders. External media may be referenced by URL.
Opening an explicit project file selects that version. When opening only a folder, a reader uses its project official pointer if present; otherwise it uses the highest version if there is exactly one project author handle. If several handles have project files, the reader asks which one to open (or a command-line caller supplies the filename), rather than guessing. An invalid official pointer is reported. The selected project supplies contributors, defaults, language, tracks and story roots for that view or export. Remembering that selection is an application preference, not a required film file.
A separate film with another project tag belongs in its own folder. A full entity stem is unique within the project; readers report duplicates rather than choosing the first file found.
Creative content and decisions live in JSON. Images, audio, video, fonts and LUTs are external files beside it. Plugin code is JavaScript. None of these is embedded into JSON to make the project “text”.
4.2 Reserved folders
Section titled “4.2 Reserved folders”| Folder | Purpose |
|---|---|
render/ |
Render batch records, and emitted workflows for offline rendering. |
conform/ |
Stable-name media slots for the editing application (§15). Generated; may be deleted and regenerated. |
_inbox/ |
Where people put material awaiting assignment. |
All other folder names are free. A reader MUST NOT move, rename or delete files it does not understand; it reports them. Application caches, thumbnails and indexes may live wherever the application chooses and are never the only copy of creative content.
4.3 Storage and collaboration
Section titled “4.3 Storage and collaboration”| Where the folder lives | Offline | Collaboration |
|---|---|---|
| Local disk, desktop or phone | yes | no |
| Drive / Dropbox / iCloud with offline sync | yes | yes — shared folder |
| Local folder that syncs to a cloud folder | yes | yes — also the desktop-to-phone path |
| Git repository | yes | yes — with history and review |
Because every file has one writer, a shared sync folder rarely sees a genuine conflict. The only files
with a shared-write role are _official.json files, normally written by directors (§8.3). Project
versions themselves follow the same author convention as other entities.
The remaining case is the same author editing the same file on two devices while both are offline. Sync
clients surface this as a sibling file (… (conflicted copy), … (1)). A reader SHOULD recognise
such a sibling of its author’s own file and present the two for comparison (§13.3); it MUST NOT
delete either silently.
Large media may live in the folder, in Git LFS, or in external storage reached by URL (§6.3). A clone holding only LFS pointers does not yet hold the video; a reader shows unavailable media clearly and lets the user fetch or relink. Keep API keys and machine-specific paths out of committed project data.
4.4 The project manifest and the media root
Section titled “4.4 The project manifest and the media root”Every other file in a project is named by its author and version, because it is somebody’s creative work. One file is not: the file that says “this folder is a FilmOpen project” and records the settings that belong to the folder itself. It has a fixed name so that any reader can recognise a project without scanning, and so that a project folder — which normally carries the film’s short name — is identified by its content and not by its name:
filmopen-project.json{ "filmopen": 1, "tag": "cartographer", "data": { "type": "local", "path": "../the-cartographer-data" }}| Field | Required | Meaning |
|---|---|---|
filmopen |
yes | The format version, as in every header (§7). |
tag |
yes | The project tag. The folder’s pj_<tag>_… files carry the same tag; a reader reports a disagreement. |
data |
no | Where rendered and imported media lives — the media root. Absent, the project folder is its own media root. |
library |
no | Reserved: a locator for the shared library the project was seeded from (§14.5). Readers ignore it in this version. |
note |
no | Free text. |
The manifest is not an entity: it has no author, no version and no official pointer. It is
shared-write in the way _official.json files are (§4.3) and changes rarely — normally only when the
project is created or its media is moved. It MUST NOT hold credentials, API keys or anything
specific to one machine (§4.3); a locator names where, never how to log in.
Locators. data is an object, not a path string, because the media may live somewhere that is not
a folder on this machine:
type |
path means |
Reader support in this version |
|---|---|---|
local |
a folder path with / separators, relative to the project folder (../the-cartographer-data, media) or absolute |
MUST support. Relative paths are portable and are what a writer SHOULD write; an absolute path is machine-specific and is reported. |
dropbox |
a path inside the user’s Dropbox | MAY support; otherwise report the media root as unavailable. |
google-drive |
a path inside the user’s Google Drive | as above |
onedrive |
a path inside the user’s OneDrive | as above |
icloud |
a path inside iCloud Drive | as above |
url |
a base URL; media references are appended to it | MAY support |
A reader that does not support a locator type MUST still open the project: the JSON is complete without the media, and unavailable media is shown as unavailable (§4.3), never as an error that hides the film. An application MAY remember a per-machine substitute for a locator it cannot reach; that memory is an application preference, not part of the project.
A project without a manifest is still a project (readers SHOULD warn, and continue, treating the folder as its own media root), so that a folder hand-assembled from files, or one written by a 1.3 writer, opens. A writer that creates a project MUST write the manifest.
Why a separate media root. The JSON of a whole feature is a few megabytes and diffs cleanly; its renders are gigabytes and do not. Keeping them apart lets the JSON live in Git while the media lives in a synced folder, and lets a collaborator clone the film’s text without its pictures. The media root is a plain folder: files in it are named exactly as they would be inside the project folder (§5.4), so moving media between the two changes nothing but the manifest.
5. Naming
Section titled “5. Naming”5.1 Case and character set
Section titled “5.1 Case and character set”Filenames are lowercase ASCII. macOS and Windows filesystems are case-insensitive by default; r8Af0
and r8af0 are one file there and two files on Linux. Lowercase everywhere removes that class of bug.
5.2 Tokens
Section titled “5.2 Tokens”| Token | Rule | Examples |
|---|---|---|
type |
two lowercase letters (§5.3) | ch lo sc |
segment |
[a-z0-9][a-z0-9-]{0,19} — at most 20 characters; readers SHOULD warn above 10 |
main-hero cafe seedance25 |
tag |
one or more segments joined by .; a dot expresses containment |
main-hero main-hero.suit 5.1 e2.1 |
epoch |
one segment; reserved default |
30yo pre-war 1990s |
author |
<owner>[.<workspace>]; each a segment; reserved owner official |
john123 maria.locale-th paul.wild |
v<n> |
version, integer ≥ 1 | v1 v2 |
r<id> |
render batch: r + a segment, unique per author. Generated ids are four lowercase hex digits; people may name batches |
r8af0 rstage0 |
<n> |
take number for one source and deliverable within a batch, integer ≥ 1 | 1 2 |
The 20-character limit applies to every segment. Readers SHOULD report filesystem path-length limits before writing rather than shorten names. Tags are unique within a type; the authors, epochs and versions of one entity deliberately share its tag.
5.3 Entity types
Section titled “5.3 Entity types”| Prefix | Entity | Grammar | Epoch |
|---|---|---|---|
pj |
project | spec; versions at the project root | — |
ch |
character | library | yes |
of |
outfit | library; tag <character>.<outfit> |
yes |
lo |
location | library; sub-areas as <location>.<area> |
yes |
pr |
prop | library | yes |
st |
style | library | yes |
mi |
misc — fonts, logos, title cards, licensed audio, reference files | library | yes |
dc |
document — treatment, series bible, pitch, research | library | yes |
mo |
model — a generative or analysis model | spec | — |
pl |
platform — where models run | spec | — |
pg |
plugin manifest | spec | — |
se |
season / installment | spec | — |
ep |
episode / act / arc | spec | — |
sq |
sequence | spec | — |
sc |
scene — contains the blocks | spec | — |
sh |
shot; tag <scene>.<n> |
spec | — |
cu |
cue; tag <unit>.<n> where unit is a scene, sequence or episode |
spec | — |
cm |
commentary | cm_<type>_<tag>_<author>.json |
— |
rd |
render batch | rd_<id>_<author>.json |
— |
5.4 Grammars
Section titled “5.4 Grammars”library entity <type>_<tag>_<epoch>_<author>_v<n>.jsonspec entity <type>_<tag>_<author>_v<n>.jsonofficial pointer <type>_<tag>[_<epoch>]_official.jsoncommentary cm_<type>_<tag>_<author>.jsonrender batch rd_<id>_<author>.jsontake (output) <deliverable>_<source stem>_r<id>_<renderer>_<n>.<ext>A parser splits on _, reads the first token, and dispatches. A take’s filename embeds the entire
stem of its source file and the batch and renderer that produced it, so a generated file traces to
its origin and to rd_<id>_<renderer>.json with no lookup. Imported media may instead keep its own name
and be referenced by path (§6.3).
5.5 Deliverable prefixes
Section titled “5.5 Deliverable prefixes”| Prefix | Deliverable | From |
|---|---|---|
cs |
concept sheet — character, location, prop, outfit, style board | ch lo pr of st |
sb |
storyboard frame — sketch-quality | sh |
ff |
first frame | sh |
lf |
last frame | sh |
kf |
keyframe — an intermediate frame | sh |
cl |
clip — video, with or without sound | sh |
vo |
voice — dialogue, narration | cu |
mu |
music | cu |
sx |
sound effect | cu |
am |
ambience, room tone | cu |
5.6 Workspaces and derived handles
Section titled “5.6 Workspaces and derived handles”An author handle may carry a second segment after a dot: john123.locale-th. The owner is the first
segment. Derived handles are used for:
- Plugin runs. A plugin invoked by
john123writes underjohn123.<plugin>[-<qualifier>], e.g.john123.locale-th. Everything one run produces starts atv1; a second run isv2. A run is therefore one glob:*_john123.locale-th_v1.*. The batch record lists the files (§12.4). - Personal workspaces.
john123.wildkeeps an experiment from inflating the owner’s main version numbers.
A reader treats a derived handle as a distinct author for versioning and as the owner’s for warnings. Derived handles are not listed in the project file.
5.7 Examples
Section titled “5.7 Examples”pj_cartographer_john123_v1.json John's project versionpj_cartographer_suda_v1.json Suda's remake; its own language and story rootspj_cartographer_official.json → the chosen project versionch_main-hero_30yo_john123_v2.json John's second version of the 30-year-old main heroch_main-hero_30yo_maria_v1.json Maria's fork of itch_main-hero_30yo_official.json → names one of the abovech_main-hero_50yo_maria_v1.json a different epoch: a distinct file sharing the tagof_main-hero.suit_30yo_john123_v1.json an outfit belonging to main-herolo_cafe_1990s_john123_v1.json the cafe as it looked in the 1990slo_cafe.kitchen_1990s_john123_v1.json a sub-area of the cafepr_car_wrecked_susan_v1.json the car, wreckedst_war-grade_default_maria_v1.json a lookdc_bible_default_john123_v3.json the series biblemo_seedance25_paul_v3.json a model, from the shared librarypl_fal_paul_v1.json a platformpg_locale_paul_v2.json a plugin manifest; its code is pg_locale_paul_v2.js beside itse_s1_john123_v1.json season 1ep_e2_john123_v1.json episode 2sq_e2.arrival_john123_v1.json a sequence within episode 2sc_5_john123_v1.json scene 5 and its blockssc_5_john123.locale-th_v1.json scene 5 as produced by a localisation plugin John ransh_5.1_john123_v1.json shot 1 of scene 5cu_5.1_john123_v1.json cue 1 of scene 5cu_e2.1_maria_v1.json a cue spanning episode 2 — scorecm_ch_main-hero_maria.json Maria's commentary on main-herord_8af0_maria.json Maria's render batch 8af0
cs_ch_main-hero_30yo_john123_v2_r8af0_maria_1.png concept sheet, take 1, Maria's render of John's v2ff_sh_5.1_john123_v1_r8af0_maria_2.png first frame, take 2, of shot 5.1cl_sh_5.1_john123_v1_r8af0_maria_1.mp4 clip, take 1vo_cu_5.1_john123_v1_r8af0_maria_1.wav voice, take 1ff_sh_5.1_john123_v1_r0001_john123_1.png a frame John extracted from an existing filmreferences/kira/front.png an imported reference, kept under its own name6. References and resolution
Section titled “6. References and resolution”Entities point at one another constantly. Three forms exist: short references and full references name entities; media references name files.
6.1 Short reference
Section titled “6.1 Short reference”A tag: "location": "cafe". The field determines the type. Resolved by the reader in three steps.
Step 1 — Epoch. Use the explicit epoch on the referencing entry if present; else the enclosing
scene’s epoch; else the enclosing unit’s; else default. An outfit takes its character’s resolved epoch
unless one is given. If the epoch was chosen implicitly and the entity has no file for it, fall back to
default and show that fallback. If the epoch was requested explicitly and does not exist, the
reference is unresolved: report it; never substitute a different age or state silently.
Step 2 — Author. Depends on the referencing file’s status:
A file that is not named by an
_official.jsonresolves author-first: the referencing file’s author’s highest version at that epoch; then, for a derived handle, the owner’s; then official.A file that is named by an
_official.jsonresolves through official only.
In plain words: a proposal sees its author’s world; official sees the official world. Maria’s fork of a scene previews with Maria’s fork of the cafe. A localisation plugin’s output is self-consistent the moment it is written. Once the director makes Maria’s scene official, it stops picking up her later experiments.
Step 3 — Fallback. If nothing is official and the selected project has a single contributor owner, use that owner’s highest version. Otherwise the reader MUST report an unresolved reference rather than guess.
Project-root references use the selected pj file as the referencing file, with its own author and
official status. Subsequent references use the file containing them. The selected project remains the
context for defaults and contributors; a full reference bypasses lookup.
This is a lookup over the current folder. Changing an official pointer or editing a referenced file changes what the project uses; readers SHOULD show the resulting selections when previewing a promotion. Historical states come from Git.
6.2 Full reference
Section titled “6.2 Full reference”A file stem: "scene": "sc_5_john123_v1". Exact; no resolution. It names an editable file, not frozen
content.
6.3 Media reference
Section titled “6.3 Media reference”One of:
- a take stem —
cl_sh_5.1_john123_v1_r8af0_maria_1— resolved to the unique file with that basename, or to a batch item naming it; - a media path including extension —
references/kira/front.png— using/, relative to the project’s media root (§4.4: the folder the manifest’sdatanames, else the project folder itself), never to the referencing file; - an external URL —
https://…— naming bytes outside the folder. Expiring signed URLs and credentials are not locators.
Generated takes carry their source, batch and renderer in the name. Imported and hand-supplied media keep their own names and are referenced by path; a batch item (§12) may describe them. A plain reference to a PNG or WAV is sufficient; no registry entry is required.
6.4 Where each is used
Section titled “6.4 Where each is used”- Project story roots and story-unit child lists accept tags or full references; the list key
determines the type (
seasons→se,episodes→ep,sequences→sq,scenes→sc). - Story units, scenes, shots and cues use short references to library entities. A scene’s
propsmay be tags or{ "prop": "car", "epoch": "wrecked" }; a scene may setlocationEpoch. - A shot or cue MAY carry a full reference to the scene version its block ids belong to. Absent, it means the resolved scene of that tag.
forkedFrom,preferandonuse full references or, foron, media references.picks,refs,preview,lut,fileand deliverable inputs use media references.
7. Common header
Section titled “7. Common header”Every entity file begins with the same fields. They repeat the filename deliberately: the file stays self-describing if renamed, and a reader can flag disagreement. Project versions use this common header without an epoch. Official pointers, commentary and render batches use the headers shown in their own sections.
{ "filmopen": 1, "type": "ch", "tag": "main-hero", "epoch": "30yo", "author": "john123", "v": 2, "name": "Kira Voss", "forkedFrom": "ch_main-hero_30yo_john123_v1", "created": "2026-09-05T18:04:11Z", "updated": "2026-09-06T09:40:00Z"}| Field | Required | Meaning |
|---|---|---|
filmopen |
yes | format version, integer |
type tag author v |
yes | as in the filename |
epoch |
library entities | as in the filename |
name |
yes | display name, any language |
label |
no | a short word for this version in version lists — goth, classic. Not copied by a fork |
created updated |
no | RFC 3339 UTC. Informational; never used for precedence |
forkedFrom |
no | stem this file was copied from. A note; nothing resolves through it |
by |
no | plugin stem, when a plugin produced this version |
source |
no | origin of imported material: { "batch": "rd_0001_john123" } |
license |
no | SPDX identifier or CC URL for this entity’s content, if it differs from the project’s |
notes |
no | free text for people; excluded from prompts unless a user explicitly includes it |
x |
no | an object for application-specific data. Readers preserve it; the format ignores it |
8. The project file
Section titled “8. The project file”{ "filmopen": 1, "type": "pj", "tag": "cartographer", "author": "john123", "v": 1, "name": "The Cartographer", "kind": "series", "genre": ["drama", "mystery"], "year": 2026, "logline": "A mapmaker discovers her charts are rewriting the coastline.", "synopsis": "…", "lang": "pt-BR", "rating": "12", "format": { "aspect": "2.39:1", "fps": 24, "resolution": "1920x804", "color": "rec709" }, "runtimeMin": 45, "credits": [ { "role": "writer", "name": "João Silva", "handle": "john123" }, { "role": "director", "name": "João Silva", "handle": "john123" } ], "epochs": { "default": { "label": "Present day", "order": 1, "year": 2026 }, "pre-war": { "label": "Before the war", "order": 2, "year": 1938 }, "mid-war": { "label": "During the war", "order": 3, "year": 1943 }, "post-war": { "label": "After the war", "order": 4, "year": 1947 } }, "contributors": { "john123": { "name": "João Silva", "role": "director" }, "maria": { "name": "Maria Costa" }, "susan": { "name": "Susan Park" } }, "tracks": [ { "id": "pic", "kind": "av", "name": "Picture" }, { "id": "pic2", "kind": "av", "name": "Picture 2" }, { "id": "dx", "kind": "audio", "name": "Dialogue" }, { "id": "vo", "kind": "audio", "name": "Narration" }, { "id": "sfx", "kind": "audio", "name": "SFX" }, { "id": "amb", "kind": "audio", "name": "Ambience" }, { "id": "mx", "kind": "audio", "name": "Music" } ], "seasons": ["s1"], "license": "CC-BY-SA-4.0", "hooks": { "validate": "(ctx) => ctx.entity.type !== 'sc' || ctx.entity.blocks.length > 0 || 'empty scene'" }}8.1 Kind
Section titled “8.1 Kind”kind ∈ short · feature · miniseries · series. It sets the labels of the story levels (§10.1)
— a mini-series and a series have seasons and episodes, a short and a feature have installments and
acts — and the story-root list an application starts a blank project with (scenes, sequences,
episodes, seasons respectively). Nothing else depends on it. Readers treat the 1.4 values film
as feature and franchise as series.
8.2 Epochs
Section titled “8.2 Epochs”Every project declares its epochs here, at least one, each with an optional label, order and
year. Readers order them by order (an entry without one comes first, in the file’s order); a writer
that reorders them renumbers order from 1. The first epoch is the project’s default epoch:
the one an implicit reference resolves to (§6.1) and the one a new library entity is created at. The
reserved token default may be used as an epoch name and is what a new project starts with.
Every library entity has an epoch — there is no “base” file outside the epoch axis. An epoch variant is a
separate, complete file that shares the entity’s tag and is treated as a distinct entity: nothing
propagates between epochs. A scene names an epoch and every library entity in it resolves to the
matching file (§6.1). Comparing two epochs side by side and copying attributes across (§13.3) is the
intended way to keep them consistent. year, when given, is the calendar year the epoch stands for;
readers use it to propose a character’s age at that epoch (§9.1). An epoch token appears in filenames,
so an application does not rename one; it adds a new epoch and the author forks files into it.
Readers SHOULD warn when a project file declares no epochs.
8.3 Contributors and directors
Section titled “8.3 Contributors and directors”contributors lists the people on the project by owner handle. role: "director" designates who
normally writes _official.json files. More than one director is allowed. Whoever creates a project
is its first director: a writer that creates a project lists the creator with that role (§18.3); how
a director appoints further directors is the project’s own business, edited in this file. Handles are names, not
identities: a file can be created under any handle, and a commit’s actor and a filename’s author are
different information a maintainer can compare. Readers SHOULD warn, and continue, when: a file is
modified by someone other than its author; an _official.json is written by a non-director; a commit
or sync introduces a file under a handle other than the current user’s. The repository maintainer
decides.
8.4 Tracks
Section titled “8.4 Tracks”The timeline tracks the project uses, in order, each with a kind and a display name. Shots are placed on
av tracks; cues on audio tracks; a video track holds picture with no sound. The list above is the
recommended default; a project may rename, reorder, add or remove. Placement (§11.3) refers to tracks by
id; the editing application sees name. Track numbers are an export artefact (§15.1) and appear
nowhere in a project.
8.5 Format and story roots
Section titled “8.5 Format and story roots”format describes the delivery target. fps is an integer for integer rates, or
{ "num": 24000, "den": 1001 } for fractional rates — never a rounded decimal. resolution, aspect
and color are strings; a project MAY add width, height, pixelAspect, colour primaries and
transfer, audio sampleRate and channels.
The project lists its story roots in order with exactly one of seasons, episodes, sequences or
scenes, whichever fits its structure. A short film can start with "scenes": ["1", "2"] and needs no
season or episode scaffolding. Entries are tags or full references of the indicated type. An empty list is valid while starting from
scratch. Order comes from these lists, not from sorting filenames.
8.6 Project alternatives and remakes
Section titled “8.6 Project alternatives and remakes”A project file is an ordinary spec entity: copy it into your author handle, set forkedFrom, and edit
its complete content. For example, pj_cartographer_suda_v1.json can name
pj_cartographer_john123_v1 in forkedFrom, change lang to th-TH, and change its display name,
credits and story roots. The tag remains cartographer so these are alternatives of the same project.
No settings are inherited from forkedFrom.
Copying a project file neither copies nor translates all its descendants. Existing media references can be reused. Full references in the copied root list can keep existing story units selected while the remake is developed; switching those references or using author-first tags selects new story versions when desired. A project language is a default, not an instruction to translate existing script text. Users may copy other entities selectively, run a localisation plugin, or fork the Git repository.
9. Library entities
Section titled “9. Library entities”A library entity is reusable across the story and has an epoch axis. Every one has the common header
and may carry refs, preview, picks and a prompt object. The required content is small; Appendix A
lists the recommended optional vocabulary. An entity with no references yet is valid.
9.0 References, picks and previews
Section titled “9.0 References, picks and previews”refs holds the media a model is shown when generating this entity. It is either a plain array of image
references, or an object of named groups:
{ "refs": { "sheets": ["cs_ch_main-hero_30yo_john123_v2_r8af0_maria_1"], "turnarounds": ["references/kira/turnaround.png"], "expressions": ["references/kira/expressions.png"] }, "voice": { "description": "low, unhurried, slight rasp", "refs": ["references/kira/voice-calm.wav", "references/kira/voice-raised.wav"] }, "preview": "references/kira/front.png"}Recommended group names — any may be used on any entity, and others may be added: images (generic),
sheets, turnarounds, expressions, poses, details, materials, floorPlans, panoramas,
lighting, motion, sound. Audio samples for a character’s voice live in voice.refs; an outfit has
no voice. Every group is an array. Each epoch file has its own groups.
preview names the media shown for this entity in a library view. Absent, a reader may use the first
sheet or image, then an image pick, then a placeholder. A preview is not automatically a model input.
picks selects generated takes by deliverable; a value is one media reference or an array when several
frames are chosen. A reference used in several files reuses the bytes and nothing else.
9.1 Character ch
Section titled “9.1 Character ch”{ "filmopen": 1, "type": "ch", "tag": "main-hero", "epoch": "30yo", "author": "john123", "v": 2, "name": "Kira Voss", "kind": "principal", "aliases": ["KIRA", "the cartographer"], "summary": "A cartographer who discovers her maps are rewriting the coastline.", "appearance": { "age": 30, "gender": "woman", "build": "lean, athletic", "skin": "olive", "hair": { "color": "black", "length": "shoulder", "style": "loose, centre-parted" }, "eyes": { "color": "dark brown", "notes": "heavy lids" }, "marks": ["burn scar along the left forearm"], "posture": "upright, still; moves only when necessary" }, "personality": { "summary": "Guarded, precise, allergic to being managed.", "traits": ["methodical", "dry humour", "conflict-avoidant until cornered"], "wants": "To prove the coastline is moving.", "speech": "Short sentences. Rarely finishes a question." }, "voice": { "description": "low, unhurried, slight rasp", "pitch": "low", "pace": "slow", "accent": "Lisbon", "lang": "pt-BR", "refs": ["references/kira/voice-calm.wav"] }, "relationships": [{ "character": "spouse", "relation": "married to, separating" }], "prompt": { "positive": "30yo woman, olive skin, black shoulder-length hair, lean athletic build, burn scar left forearm, upright posture", "negative": "cartoon, plastic skin, over-smoothed" }, "creatorNotes": "Never smiles with teeth. Keep the scar visible in any shot showing the left arm.", "picks": { "sheet": "cs_ch_main-hero_30yo_john123_v2_r8af0_maria_1" }, "refs": { "sheets": ["cs_ch_main-hero_30yo_john123_v2_r8af0_maria_1"] }, "preview": "cs_ch_main-hero_30yo_john123_v2_r8af0_maria_1"}kind∈principal·supporting·extra·group·narrator·creature·animal. Agroupis a crowd described once.birthYear— the character’s year of birth, an integer, the same in every epoch file of the character. When the project’s epoch has ayear(§8.2), a reader proposesappearance.age = epoch.year − birthYearfor a new epoch file, and the author may override it: a character born in 1950 is 50 at an epoch set in 2000 unless the file says 30.aliases— every name a script or transcript might use. Essential for import and for Fountain export.appearance,personality,voice— open objects. Readers display whatever keys are present. Appendix A.1 recommends a vocabulary; none of it is required.creatorNotes— for people; excluded from prompts unless a user explicitly includes it.
9.2 Outfit of
Section titled “9.2 Outfit of”{ "filmopen": 1, "type": "of", "tag": "main-hero.suit", "epoch": "30yo", "author": "john123", "v": 1, "name": "Charcoal business suit", "garments": [ { "item": "suit jacket", "color": "charcoal", "material": "wool", "fit": "tailored", "condition": "worn at the cuffs" }, { "item": "shirt", "color": "white", "notes": "open collar, no tie" }, { "item": "boots", "color": "brown", "material": "leather", "condition": "scuffed" } ], "accessories": ["steel wristwatch, left wrist"], "prompt": { "positive": "charcoal two-button suit, white open-collar shirt, worn brown leather boots, steel wristwatch" }, "picks": { "sheet": "cs_of_main-hero.suit_30yo_john123_v1_r7c21_john123_1" }}9.3 Location lo
Section titled “9.3 Location lo”{ "filmopen": 1, "type": "lo", "tag": "cafe", "epoch": "1990s", "author": "john123", "v": 1, "name": "Café Atlântico", "aliases": ["CAFE", "the café"], "kind": "interior", "geography": { "city": "Lisbon", "country": "PT" }, "description": "Tiled floor, ceiling fans, a long zinc bar, harbour visible through steamed windows.", "dressing": ["zinc bar", "six marble tables", "espresso machine, chrome", "framed harbour photographs"], "lighting": { "default": "late afternoon, warm, low sun through the windows", "practicals": ["pendant lamps over the bar"] }, "sound": { "roomTone": "tiled, lively reverb", "ambience": "espresso machine, harbour gulls, distant traffic" }, "areas": ["cafe.bar", "cafe.kitchen"], "prompt": { "positive": "1990s Lisbon café interior, tiled floor, zinc bar, ceiling fans, steamed windows, harbour beyond" }, "picks": { "sheet": "cs_lo_cafe_1990s_john123_v1_r7c21_john123_2" }}kind ∈ interior · exterior · both. Sub-areas are locations with tag <parent>.<area> and their
own epoch files.
9.4 Prop pr
Section titled “9.4 Prop pr”{ "filmopen": 1, "type": "pr", "tag": "chart", "epoch": "default", "author": "john123", "v": 1, "name": "The 1994 harbour chart", "kind": "document", "hero": true, "description": "Hand-drawn nautical chart on yellowed linen-backed paper, folded twice, ink faded to sepia.", "scale": "60 × 90 cm", "condition": "creased, one corner water-stained", "prompt": { "positive": "hand-drawn nautical chart, yellowed linen paper, sepia ink, fold creases, water stain" }, "picks": { "sheet": "cs_pr_chart_default_john123_v1_r7c21_john123_4" }}hero: true marks a prop the camera will see closely; it needs a stronger reference than background
dressing.
9.5 Style st
Section titled “9.5 Style st”{ "filmopen": 1, "type": "st", "tag": "war-grade", "epoch": "default", "author": "maria", "v": 1, "name": "War — gritty, desaturated", "description": "Episode 2 onward. Cold, grey, high contrast, grain.", "genre": "drama", "references": ["1970s political thrillers", "hand-processed 16mm"], "look": { "stock": "16mm colour negative", "grain": "medium", "halation": "slight", "contrast": "high", "saturation": "low" }, "palette": ["#2b2f33", "#6b7076", "#b9bcb8", "#d9c9a3"], "prompt": { "positive": "desaturated, cold grey palette, high contrast, 16mm grain, handheld", "negative": "saturated, clean, glossy" }, "cdl": { "slope": [0.95, 0.98, 1.05], "offset": [-0.02, -0.02, 0.0], "power": [1.1, 1.1, 1.05], "saturation": 0.6 }, "lut": "style/war-grade/war-grade.cube", "refs": { "images": ["cs_st_war-grade_default_maria_v1_r8af0_maria_1"] }}cdl records ASC CDL values; lut is a media reference to a .cube file. Both record colour intent
and export with the timeline; whether an editing application applies them depends on its importer, and
an exporter reports what it could not carry (§15.3).
9.6 Misc mi and Document dc
Section titled “9.6 Misc mi and Document dc”{ "filmopen": 1, "type": "mi", "tag": "title-font", "epoch": "default", "author": "john123", "v": 1, "name": "Title font", "kind": "font", "file": "misc/atlantico-bold.otf" }{ "filmopen": 1, "type": "dc", "tag": "treatment", "epoch": "default", "author": "john123", "v": 2, "name": "Treatment", "kind": "treatment", "text": "Kira Voss draws maps for a living and discovers that her maps are redrawing the coast…", "file": "docs/treatment-2026-08.docx" }mi.kind ∈ font · logo · title-card · audio · image · other. dc.kind ∈ treatment · bible
· pitch · beat-sheet · research · context · other. For a document, text is the editable
FilmOpen content and survives a JSON-only checkout; file is an imported source or export. Either may be
present alone.
10. Story structure and script
Section titled “10. Story structure and script”10.1 Story units se ep sq sc
Section titled “10.1 Story units se ep sq sc”| Level | Series | Film / franchise | File |
|---|---|---|---|
| 1 | season | installment | se_ |
| 2 | episode | act / arc | ep_ |
| 3 | sequence (optional) | sequence (optional) | sq_ |
| 4 | scene | scene | sc_ |
Levels 1–3 are optional groupings. Each declares epoch, cast, locations and styles as defaults for its children, and an ordered list of those children. A scene narrows or overrides what it inherits from its unit; nothing is inherited between library files.
{ "filmopen": 1, "type": "ep", "tag": "e2", "author": "john123", "v": 1, "name": "Episode 2 — Low Tide", "synopsis": "Kira finds the first altered chart.", "epoch": "mid-war", "cast": [ { "character": "main-hero", "epoch": "30yo", "outfit": "main-hero.suit" }, { "character": "spouse", "epoch": "28yo" } ], "locations": ["cafe", "archive"], "styles": ["war-grade"], "scenes": ["3", "4", "5", "archive-exit"], "notes": "Cold open, no score until the reveal."}scenes (or sequences, or episodes on a season) fixes the order of children. If absent, a reader
MAY propose natural (numeric-aware) tag order and MUST say so; a reproducible timeline export
needs an explicit list. Cyclic or duplicate containment is reported.
10.2 Scene sc
Section titled “10.2 Scene sc”A scene is one time and one place. Its file holds the blocks — the script — in order.
{ "filmopen": 1, "type": "sc", "tag": "5", "author": "john123", "v": 1, "name": "The archive", "location": "archive", "epoch": "mid-war", "storyDay": 3, "time": "night", "weather": "rain against the skylight", "cast": [{ "character": "main-hero", "epoch": "30yo", "outfit": "main-hero.suit" }], "props": [{ "prop": "chart", "epoch": "default" }], "style": "war-grade", "synopsis": "Kira compares the two charts and realises the coastline moved.", "purpose": "First proof. Turns the mystery from doubt to certainty.", "targetDurationSec": 165, "shots": ["5.1", "5.2"], "cues": ["5.1", "5.2", "5.3"], "blocks": [ { "id": "bl_1", "kind": "action", "text": "Kira spreads both charts across the reading table." }, { "id": "bl_2", "kind": "dialogue", "character": "main-hero", "text": "The bay was here last spring.", "direction": "flat disbelief, does not look up" }, { "id": "bl_3", "kind": "action", "text": "Behind her, the window flashes white. A second later, the glass goes." }, { "id": "bl_4", "kind": "dialogue", "character": "main-hero", "text": "Not now.", "offscreen": true }, { "id": "bl_5", "kind": "transition", "text": "CUT TO:" }, { "id": "bl_6", "kind": "note", "text": "Consider cutting bl_2 if pacing drags." } ]}storyDay is the script supervisor’s continuity day. purpose states what the scene does for the
story, which is the single most useful field for an AI reading the project. shots and cues fix the
order of the scene’s shots and cues; absent, natural tag order applies. locationEpoch overrides the
scene epoch for the location alone.
10.3 Blocks
Section titled “10.3 Blocks”| Field | Meaning |
|---|---|
id |
bl_<n>; stable for the life of the block in this file. Never renumbered. |
kind |
dialogue · action · narration · transition · title · lyric · note |
text |
the line, the action, the title text |
character |
short reference; dialogue, narration and lyric |
direction |
performance note — the screenplay parenthetical |
offscreen voiceover |
booleans — Fountain’s (O.S.) and (V.O.) |
dual |
true when spoken simultaneously with the previous dialogue block |
lang |
BCP 47 override for this block |
startMs endMs |
observed timing, typically from import |
Rules: new blocks take the next unused number; order is array order; moving a block to another scene
copies it there with a new id; note blocks never render. Because ids are stable, two authors’ versions
of a scene align by id with no diff algorithm (§13.3). Two forks that independently invent the same
id are not the same line; a reader shows the text, and the Git base when available, rather than
assuming.
10.4 Fountain correspondence
Section titled “10.4 Fountain correspondence”| Fountain | FilmOpen |
|---|---|
Scene Heading INT. CAFE – NIGHT |
scene location (+ kind), time |
| Action | block action |
| Character + Dialogue | block dialogue, character via aliases |
| Parenthetical | direction |
(O.S.) (V.O.) |
offscreen voiceover |
Dual dialogue ^ |
dual |
| Transition | block transition |
| Centered text | block title |
Lyrics ~ |
block lyric |
Note [[ ]] |
block note |
Section # |
story units |
Synopsis = |
synopsis |
The screenplay content round-trips. Title-page fields, emphasis, forced elements, scene numbers, page
breaks and boneyards are not represented; an importer or exporter reports them, and a dc may keep the
original text. Shot and sound information, which Fountain cannot express, lives in shots and cues.
11. Shots and cues
Section titled “11. Shots and cues”11.1 Shot sh
Section titled “11.1 Shot sh”A visual generation spec covering one or more blocks, with its placement on the timeline.
{ "filmopen": 1, "type": "sh", "tag": "5.2", "author": "john123", "v": 1, "name": "Kira reacts; the window goes", "scene": "sc_5_john123_v1", "blocks": ["bl_3", "bl_4"], "characters": ["main-hero"], "size": "mcu", "angle": "low", "movement": "static", "lens": { "focalMm": 50, "aperture": 2.0, "dof": "shallow" }, "lighting": { "key": { "direction": "side", "quality": "hard" }, "style": "low-key", "colorTempK": 3200, "practicals": ["desk lamp"], "notes": "window flash as a single hard white hit from behind" }, "composition": { "headroom": "tight", "eyeline": "down-left", "screenDirection": "facing right" }, "durationSec": 5, "continuity": ["chart still unfolded on the table", "scar visible, left forearm"], "vfx": "glass shatter, practical-looking, no debris toward lens", "deliverables": { "firstFrame": { "model": "nanobanana", "prompt": "…", "refs": ["cs_ch_main-hero_30yo_john123_v2_r8af0_maria_1"] }, "clip": { "model": "seedance25", "prompt": "…", "from": "firstFrame", "inputs": ["vo_cu_5.3_john123_v1_r8af0_maria_1"] } }, "place": { "track": "pic", "after": "sh_5.1", "offsetMs": 0, "inMs": 0, "outMs": 5000 }, "picks": { "firstFrame": "ff_sh_5.2_john123_v1_r8af0_maria_1", "clip": "cl_sh_5.2_john123_v1_r8af0_maria_1" }}size, angle, movement, lens, lighting and composition use the vocabulary in Appendix A.4; all
are optional. scene is a full reference to the scene version the block ids belong to (§6.4). In a
deliverable, from names a preceding deliverable of the same shot and inputs names other media it
depends on — a chosen dialogue take for lip sync, for instance; the batch records what was actually
used. A still image placed as a shot takes its hold duration from durationSec.
11.2 Cue cu
Section titled “11.2 Cue cu”An audio generation spec. A cue attaches to a scene, or to a sequence or episode when it spans scenes.
{ "filmopen": 1, "type": "cu", "tag": "5.1", "author": "john123", "v": 1, "name": "Kira — the bay line", "kind": "dialogue", "scene": "sc_5_john123_v1", "blocks": ["bl_2"], "character": "main-hero", "spoken": "The bay was here… last spring.", "delivery": { "effort": "quiet", "emotion": "flat disbelief", "processing": "none" }, "model": "elevenlabs", "place": { "track": "dx", "with": "sh_5.1", "offsetMs": 400, "gainDb": -3 }, "picks": { "voice": "vo_cu_5.1_john123_v1_r8af0_maria_1" }}{ "filmopen": 1, "type": "cu", "tag": "e2.1", "author": "maria", "v": 1, "name": "Low Tide — main theme", "kind": "music", "unit": "ep_e2_john123_v1", "music": { "tempoBpm": 72, "key": "D minor", "instrumentation": ["cello", "prepared piano", "tape hiss"], "mood": "unease held under restraint", "structure": "sparse intro, swell at the reveal, cut on the flash" }, "sync": [{ "with": "sh_5.2", "offsetMs": 0, "event": "cut on the flash" }], "anchors": [{ "scene": "sc_5_john123_v1", "blocks": ["bl_3"] }], "model": "suno", "place": { "track": "mx", "with": "scene:3", "offsetMs": 0, "fadeInMs": 2000, "fadeOutMs": 4000, "gainDb": -12 }, "picks": { "music": "mu_cu_e2.1_maria_v1_r91c0_maria_2" }}kind∈dialogue·narration·music·sfx·ambience.- Text comes from the referenced blocks, concatenated in order.
spoken, if present, replaces it — for pauses, pronunciation, numbers spelled out, a translated line. Readers surface “spoken differs from script” as an intentional state, and warn when the block has changed since. ssml(W3C SSML) is an alternative tospokenfor models that accept it; use one or the other.- A cue attached to a unit that needs specific blocks from specific scenes uses
anchors, since block ids are local to a scene.
11.3 Placement
Section titled “11.3 Placement”place states where a shot or cue sits on the timeline. Every field is optional; a scene with no
placement at all is a straight sequential cut on the first av track, in the scene’s shots order.
| Field | Meaning | Default |
|---|---|---|
track |
track id from the project (§8.4) |
first av track for shots; dx for dialogue, vo narration, sfx, amb, mx music |
after |
anchor: start at this item’s end plus offsetMs. A shot tag, or prev |
prev for shots |
with |
anchor: start at this item’s start plus offsetMs. A shot tag, scene, or scene:<tag> |
for cues, the first shot covering the cue’s first block |
offsetMs |
signed milliseconds from the anchor | 0 |
inMs outMs |
trim within the source take, from its first frame; outMs exclusive |
whole take |
audio |
false to place picture only from an av clip |
true |
gainDb pan |
mix | 0, 0 |
fadeInMs fadeOutMs |
audio fades | 0 |
transitionIn |
{ "type": "cut" | "dissolve" | "fade", "ms": n } |
cut |
Rules:
afterandwithare the only anchors, and a placement uses one of them.previs the previous shot in the scene’s order, not the previous file on disk. Anchor cycles, missing anchors and negative starts are reported.- Two items on one track cannot overlap. A negative
offsetMsafter a picture cut on the same track is a collision and is reported. Overlaps go on another track: a second picture track for an overlay, or — the common case — the dialogue track for a J-cut, where the next line begins before the picture cuts:"with": "sh_5.2", "offsetMs": -1500on the cue. - A
dissolveorfadeneeds source handles: media beyond the nominal trims on both sides. The exporter checks the picked takes and reports when handles are short; it never shortens the cut. - Changing a duration ripples downstream through the
afterchain, as a rough assembly should. - Timings are numbers in milliseconds. An exporter converts to the project frame rate and reports any rounding it applies. Equal boundaries must round identically; ties round toward the later frame. Source trims must also respect the source media rate and available range.
An observation at 12:04.625 in an imported film belongs in the batch’s source timing (at).
A placement anchored to scene uses an offset from that scene’s start, not the source film’s start.
The first shot defaults to the scene start when prev has no predecessor. Scenes begin sequentially
in the selected story order; a scene’s length is the latest end of its placed shots and scene cues.
Unit-level cues do not lengthen individual scenes. Cross-scene anchor cycles are reported.
12. Takes and render batches
Section titled “12. Takes and render batches”12.1 Takes are discovered, never recorded in the entity
Section titled “12.1 Takes are discovered, never recorded in the entity”A take is a media file whose name embeds its source stem (§5.4), or an imported file named in a batch.
No entity file lists its takes. A reader finds them by scanning the media root (§4.4) — and the
project folder itself, so that a project without a manifest keeps working — and by reading batches; the batch
says how they were made; the only thing an entity’s author writes about takes is picks. This is what
lets one person render another’s shot without touching their file, and lets a character page show every
sheet anyone has rendered for it.
12.2 Render batch rd
Section titled “12.2 Render batch rd”{ "filmopen": 1, "type": "rd", "id": "8af0", "author": "maria", "kind": "render", "tier": "final", "created": "2026-09-06T15:30:00Z", "status": "done", "items": [ { "n": 1, "source": "sh_5.2_john123_v1", "deliverable": "clip", "model": "seedance25", "platform": "fal", "prompt": "…the fully resolved prompt as sent…", "params": { "seed": 41221, "steps": 30, "durationSec": 5, "fps": 24 }, "inputs": ["ff_sh_5.2_john123_v1_r8af0_maria_1", "vo_cu_5.3_john123_v1_r8af0_maria_1"], "output": "s1/e2/sc5/cl_sh_5.2_john123_v1_r8af0_maria_1.mp4", "sha256": "9d02…", "durationMs": 5000, "elapsedMs": 61400, "costUsd": 0.42, "thumbnail": "s1/e2/sc5/cl_sh_5.2_john123_v1_r8af0_maria_1.thumb.jpg", "human": { "selectedFrom": 4, "promptEditedBy": "maria" } } ]}| Field | Meaning |
|---|---|
kind |
render · import · plugin · manual |
tier |
preview · final — cheap fast previews versus locked finals |
output |
media reference — usually a project-relative path |
take |
take number in a generated filename when it is not 1 |
sha256 |
recorded on ingest. Names carry meaning; hashes carry identity; together they survive renames, moves and duplicates |
durationMs / elapsedMs |
length of the output media / time the job took |
costUsd |
absent when unknown, never zero |
human |
the human contribution: candidates reviewed, who edited the prompt, manual edits. The authorship evidence (§16.5) |
status jobId attempts error |
job notes for a pending, failed or partial batch; a batch may be updated in place |
thumbnail poster proxy waveform |
display derivatives; never model inputs by themselves |
mimeType bytes width height fps frameCount sampleRate channels |
measured media properties; measured on ingest if absent, never invented |
12.3 Import batches — describing a film that exists
Section titled “12.3 Import batches — describing a film that exists”kind: "import" records material taken from an existing work. Its takes are named like any other; the
renderer is the importing author, so the take always finds its batch.
{ "filmopen": 1, "type": "rd", "id": "0001", "author": "john123", "kind": "import", "source": { "file": "the-cartographer-2019.mp4", "sha256": "e1a4…", "fps": 24, "durationMs": 5412000 }, "created": "2026-09-06T09:00:00Z", "status": "done", "items": [ { "n": 1, "source": "sh_5.2_john123_v1", "deliverable": "firstFrame", "at": { "ms": 724625 }, "output": "s1/e2/sc5/ff_sh_5.2_john123_v1_r0001_john123_1.png", "sha256": "77b0…" }, { "n": 2, "source": "cu_5.1_john123_v1", "deliverable": "voice", "at": { "startMs": 724625, "endMs": 727200 }, "output": "s1/e2/sc5/vo_cu_5.1_john123_v1_r0001_john123_1.wav", "sha256": "31cd…" }, { "n": 3, "source": "ch_main-hero_30yo_john123_v1", "deliverable": "baseImage", "output": "references/kira/front.png", "width": 2048, "height": 2048 } ]}Reverse-engineering a film produces ordinary FilmOpen files: blocks from a transcript with timing, shots
from detected cuts with place, characters with aliases from speaker labels and appearance from
observed frames, takes extracted at timecodes. Each such entity carries "source": { "batch": … }. An
import item for a file that keeps its own name, as in item 3, simply names it.
12.4 Plugin batches
Section titled “12.4 Plugin batches”kind: "plugin" records a plugin run: the plugin stem, the settings used, and the files produced under
the run’s derived handle (§14.3).
12.5 Offline rendering
Section titled “12.5 Offline rendering”A batch may be emitted instead of submitted: render/rd_<id>_<author>/ holds one workflow file per
item — for ComfyUI, a workflow JSON, labelled as UI graph or API payload — each already named for the
output it should produce. The workflows run anywhere; the outputs are dropped into the project; a reader
matches them by name and records hashes.
12.6 Ingest
Section titled “12.6 Ingest”On every scan a reader SHOULD: parse every filename; attach takes to sources; record sha256 and
measured properties for new outputs in their batch; flag outputs whose hash no longer matches their
record; and report unknown files without moving them. On a network timeout a reader checks an existing
provider job before submitting another paid request, and keeps completed items when one fails. A reader
MUST NOT assume it is the only writer.
13. Versions, official, compare and commentary
Section titled “13. Versions, official, compare and commentary”13.1 Versions
Section titled “13.1 Versions”A version is a whole file. All are readable; the highest is the author’s working copy. Files are edited
in place and nothing is frozen; a filmmaker may edit sc_5_john123_v1.json for months. Fork on your
own version creates v(n+1) as a copy; fork on someone else’s creates your v1 (or next) with
forkedFrom set. Prior states of a file are Git’s business.
13.2 Official
Section titled “13.2 Official”{ "filmopen": 1, "type": "ch", "tag": "main-hero", "epoch": "30yo", "official": "ch_main-hero_30yo_maria_v1", "setBy": "john123", "setAt": "2026-09-06T14:20:00Z", "note": "Maria's. Using hers." }Written by a director. Applies to every versioned type. Everything downstream reads through official
unless a viewer is looking at their own version (§6.1). Editing a version that official names changes
what the whole project sees; readers SHOULD say so and offer to fork instead, and then allow it.
A project with no chosen version for an entity simply has no pointer file: to withdraw a choice, a
director deletes the pointer; an application that offers official as a toggle removes the file when
the toggle is cleared and writes it, with setBy and setAt, when it is set.
13.3 Compare and copy-left
Section titled “13.3 Compare and copy-left”The core collaborative act, and the only merge operation. Versions of one entity are shown as columns:
- the viewer’s own working version, if any;
- the version the viewer has marked
preferin their commentary, if it differs from official; - official;
- any others the viewer adds — including other epochs of the same entity, plugin output, and a sync client’s conflicted copy.
Each column offers copy-left for the whole entity and beside each attribute. Copying a nested object
copies the subtree. A viewer with no version of their own who copies anything gets a v1 created —
copy-left is fork when needed. Copying is not confirmed; the re-rendered result is the check.
Scenes compare by block id.
| Case | Shown as | Copy-left does |
|---|---|---|
| same id, same text | collapsed: 6 unchanged | — |
| same id, different text | side by side, changed words marked | replace mine |
| id only in theirs | a gap in my column at their position | insert it |
| id only in mine | greyed: not in theirs | delete mine |
“Not in theirs” does not prove they deleted it; when a Git base is available a reader can tell an addition from a deletion.
13.4 Commentary cm
Section titled “13.4 Commentary cm”One file per author per entity, covering all its epochs, versions and takes.
{ "filmopen": 1, "type": "cm", "target": "ch_main-hero", "author": "maria", "prefer": "ch_main-hero_30yo_susan_v1", "entries": [ { "on": "ch_main-hero_30yo_john123_v2", "at": "2026-09-06T10:02:00Z", "rating": 1, "text": "I really like the tattoo." }, { "on": "cs_ch_main-hero_30yo_john123_v2_r8af0_maria_1", "at": "2026-09-06T11:15:00Z", "rating": 1 }, { "on": "ch_main-hero_30yo_susan_v1", "at": "2026-09-06T12:40:00Z", "rating": -1, "text": "Too young for the mid-war scenes.", "block": "bl_2" } ]}on is a version stem or a media reference. rating is 1, -1, or absent. An entry may name a
block, a field or a gitCommit for context. prefer is the author’s pick — the version they
would choose; it orders compare columns and an application shows it (a check) beside official (a
star). Changing a pick rewrites only the author’s own commentary file; a viewer without one gets an
empty one with prefer set. Readers consolidate every
cm_ file for an entity into one feed. Review can equally happen in pull requests or conversation;
commentary is not required.
14. Extensibility
Section titled “14. Extensibility”14.1 Language
Section titled “14.1 Language”Hooks and plugins are JavaScript, ECMAScript 2020, single file, no import/require. Functions
may be async. Code receives one argument, ctx, and returns a value; it never mutates project state.
Hooks and plugins are data until an application chooses to run them; plain readers never execute code.
14.2 Sandbox
Section titled “14.2 Sandbox”Code runs with JSON, Math, String, Number, Array, Object, RegExp, Map, Set, Promise
and nothing else: no filesystem, no network, no clock, no randomness, no timers. That list is the API
surface, not the security boundary: an application MUST isolate untrusted code — runtime, memory and
output limits, no ambient filesystem or shell, no network except the services in §14.4 — and must protect
its credentials, which never enter project JSON or plugin output. The application decides which code
the user trusts to run and re-evaluates that trust when the code changes. An official pointer alone
does not grant execution permission. Trust decisions belong to the application, not to the film files.
14.3 Hooks
Section titled “14.3 Hooks”Short functions inside mo, pl, st and pj files, keyed by name.
| Hook | Runs | Receives | Returns |
|---|---|---|---|
validate |
before save or render | { entity, project, params? }; resolved generation parameters when rendering |
true or an error string |
buildPrompt |
assembling a prompt | { shot | cue | entity, cast, location, style, project } |
string, or { positive, negative, refs, params } |
buildRequest |
submitting to a platform | { model, platform, prompt, inputs, params } |
{ url, body, headers? } |
parseResponse |
platform replies | raw response | { output, durationMs?, elapsedMs?, cost? } |
estimateCost |
before a batch | { model, platform, params } |
number, USD, or null for unknown |
postProcess |
after ingest | { item, take } |
modified item |
Prompt precedence: an explicit prompt on the deliverable; else the model’s buildPrompt; else a simple
documented default. Builders include selected descriptions and references, never every note in a file.
Parameters a provider does not support are reported, not silently dropped.
{ "filmopen": 1, "type": "mo", "tag": "seedance25", "author": "paul", "v": 3, "name": "Seedance 2.5", "vendor": "ByteDance", "kind": "video", "capabilities": ["text2video", "image2video"], "inputs": { "prompt": "string", "image": "file?", "durationSec": "int 3..15", "seed": "int?" }, "defaults": { "durationSec": 5, "fps": 24 }, "platforms": ["fal", "runninghub"], "hooks": { "buildPrompt": "(ctx) => [ctx.shot.prompt, ctx.style && ctx.style.prompt.positive, ctx.cast.map(c => c.prompt.positive).join(', ')].filter(Boolean).join('. ')", "validate": "(ctx) => !ctx.params || ctx.params.durationSec == null || ctx.params.durationSec <= 15 || 'Seedance 2.5 clips are 15 s max'" }}{ "filmopen": 1, "type": "pl", "tag": "fal", "author": "paul", "v": 1, "name": "fal.ai", "kind": "remote", "baseUrl": "https://fal.run", "auth": { "kind": "apiKey", "keychain": "filmopen/fal" }, "models": { "seedance25": "fal-ai/bytedance/seedance/v2.5" }, "hooks": { "buildRequest": "(ctx) => ({ url: ctx.platform.baseUrl + '/' + ctx.platform.models[ctx.model.tag], body: { prompt: ctx.prompt, image_url: ctx.inputs.image, duration: ctx.params.durationSec, seed: ctx.params.seed } })", "parseResponse": "(res) => ({ output: res.video.url })", "estimateCost": "(ctx) => 0.07 * ctx.params.durationSec" }}mo.kind ∈ image · video · audio · music · tts · analysis. Analysis capabilities include
shot-detect, transcribe, diarize, face-cluster, describe-frame, describe-video. Response parsers set durationMs only from the output media duration. Inference or request runtime
belongs in elapsedMs, converted from the provider’s documented units; otherwise omit it.
Secrets never
appear in a project; auth.keychain names a key the application holds.
14.4 Plugins
Section titled “14.4 Plugins”A plugin is a manifest and a code file named after it, in plugin/<tag>/.
{ "filmopen": 1, "type": "pg", "tag": "locale", "author": "paul", "v": 2, "name": "Localiser", "api": 1, "description": "Translates dialogue and relocates settings to a target culture.", "entry": "pg_locale_paul_v2.js", "applies": ["sc", "cu", "lo"], "hooks": ["transform"], "capabilities": { "ai": true }, "settings": { "target": { "type": "string", "default": "th-TH" }, "relocate": { "type": "boolean", "default": true } }}| Hook | Purpose | Receives | Returns |
|---|---|---|---|
transform |
rewrite entities — polish, translate, restyle, relocate | { entities, project, settings, ai? } |
the modified entities |
analyze |
comment without changing — continuity, pacing, consistency | same | commentary entries |
import |
turn a foreign file into FilmOpen entities | { file, project, settings, ai? } |
entities and an optional batch |
export |
turn entities into a foreign format | { entities, project, settings } |
{ filename, content } |
Rules:
apinames the host interface version; a host reports versions it does not support.- A plugin has read access to the whole project and operates on the entities the user selected.
- A plugin never writes files. It returns entities; the application writes them as new versions
under the running user’s derived handle —
john123.locale-th— all starting atv1, and records akind: "plugin"batch. A second run isv2. If the source files changed while the run was in progress, the application shows that rather than overwriting. - Plugin output is never merged into the owner’s own versions. Accepting it is pointing official at it, entity by entity or as a whole run; taking parts is copy-left; hand-fixing it is forking it.
capabilities.aigrantsawait ctx.ai.complete(prompt, options)→{ text, usage?, cost? }and, where the host supports vision,await ctx.ai.describe(media, prompt, options), routed through the user’s configured platform and key. This is the only path from the sandbox to a network. The application owns paid-call consent, cancellation and retries within the user’s configured limits.
A localisation plugin is the canonical example: fork the repository for a new territory, run the
plugin, point every _official.json at the run. The original is untouched in the same tree. An
import plugin with ai: true is the reverse-engineering tool of §12.3.
14.5 The shared library
Section titled “14.5 The shared library”Models, platforms, plugins and optionally styles live in a public repository the format maintainer
controls, using exactly the conventions above: versions, authors, _official.json, commentary. Share
on a forked entry is a pull request; the maintainer merges and, once tested, moves _official.json. No
central service is needed to use a locally installed entry.
The library is installed beside projects, not inside them: one copy per machine (or per user), in a
folder the application manages and can update on its own schedule — a git pull, a download — without
touching any project and without a new build of the application. A project therefore need not contain
mo_, pl_ or pg_ files at all; a reader resolves references to models, platforms and plugins
against the project first and then against the library. A project MAY hold its own — a fork of a
library entry made inside the project as one would fork a character, or a private model — and those
take part in resolution exactly like any other entity of the project. The same full stem present in both
the project and the library is reported as a duplicate; the project’s file is used. Where the library
folder lives is an application preference (§4.2: application caches and indexes live wherever the
application chooses); a project’s manifest may later name the library it was seeded from (§4.4,
library, reserved).
15. Timeline export and round-trip
Section titled “15. Timeline export and round-trip”15.1 Track mapping
Section titled “15.1 Track mapping”OpenTimelineIO and every editing application have separate video and audio tracks; there is no
audio-visual track. A FilmOpen av track exports as a video track and an audio track that share a name.
The mapping is deterministic:
Video tracks: each
avandvideotrack in declared order → V1, V2, … Audio tracks: the sound of eachavtrack in declared order → A1, A2, …; then eachaudiotrack in declared order, continuing the numbering after thoseavaudio tracks Every exported track carries its FilmOpen name.
Nobody in a project ever writes a track number. A cue on dx lands on a track labelled Dialogue
whether that is A3 or A4 in a given project.
15.2 Timing, checks and report
Section titled “15.2 Timing, checks and report”One flat timeline per episode or film. Tracks span the whole timeline; scenes appear in unit order (§10.1) with a marker at each scene start carrying the scene stem, and a marker on each clip carrying its shot or cue stem. No nested compositions — importers handle them badly.
Timings are computed from place by walking after chains, in milliseconds, then converted once to the
project rate using the exact rate ratio for fractional rates given as num/den.
Millisecond inputs may require rounding; conversion does not promise sample-exact interchange. Source in/out are start-inclusive,
end-exclusive. Source timecode and timeline position are distinct.
Before writing, the exporter checks and reports: unresolved or ambiguous references; missing or unreadable media; trims beyond the take’s measured duration; anchor cycles; same-track collisions; transitions without sufficient handles; a cue’s embedded audio duplicated on two tracks; any timing rounding applied. An incomplete project is still editable and still exports as a labelled preview if asked; a final conform stops on the first impossibility and names the field.
Every export ships a manifest — source stem, media path, hash, target path, source and timeline ranges — and the report above.
15.3 What travels and what does not
Section titled “15.3 What travels and what does not”OTIO represents tracks and names, clips, source ranges, gaps, markers, transitions and linear speed. Support in each editing application or adapter must be tested. Metadata can preserve other intent, but does not guarantee that the editor applies grades, effects, audio automation or titles. Consequently:
- Export is a conform of raw footage: picked takes placed as specified, nothing more. The editor finishes in the editing application. CDL and LUT values ship as sidecars.
- Additional export formats are optional. Final Cut Pro 7 XML (
xmeml,.xml) and Final Cut Pro X XML (.fcpxml) are different formats. Premiere supports the former; direct FCPXML import requires conversion. Choose a tested target profile rather than promising generic round-trip fidelity. CMX3600 EDL is a limited fallback, with unsupported structure reported. Adobe interchange documentation - An editor’s export back to FilmOpen is lossy by nature. The format does not attempt to hold what OTIO cannot carry.
15.4 Never overwrite the editor’s timeline
Section titled “15.4 Never overwrite the editor’s timeline”Two things change after the editor has started: takes get re-rendered, and the editor changes timing. They are handled by different mechanisms, and neither one emits a new timeline over the editor’s.
Re-rendered takes → relink. Export media into conform/ under stable slot names that do not
change when a pick changes — sh_5.2_clip.mp4, cu_5.1_voice.wav. Picking a new take and re-exporting
overwrites the slot file as a deliberate act. The editor’s timeline references the same path; the
editor can refresh or relink the media while retaining timeline edits. Preservation of grades, effects
and transitions depends on the editor and compatible replacement media; verify it in the named target
version rather than guaranteeing it. A new take of a
different duration no longer fits the editor’s in/out — exactly as when a live-action take is swapped —
and the report MUST say so.
Editor’s timing → import. When the editor exports OTIO, a reader MAY read it and propose changes
to place — track by name, anchor as with: scene, offset, in/out. Clip identity comes from the media
filename or slot name and from the markers. Split clips, repeated occurrences and structure the format
cannot express are reported, not compressed into one wrong placement. FilmOpen’s representation stays in
step with the editor’s decisions without ever emitting over them.
New material → additive. New scenes and shots export as a separate timeline in the same project, or as a bin of slot media. The editor drags them in.
Under this model the editor can begin finishing as soon as an assembly exists. What still has to wait is structural change — reordering shots after cutting has begun — which no format can make free.
16. Interchange with existing standards
Section titled “16. Interchange with existing standards”16.1 Summary
Section titled “16.1 Summary”| Domain | Standard | Status |
|---|---|---|
| Screenplay | Fountain | adopted, import and export of screenplay content (§10.4) |
| Screenplay | FDX | import via Fountain, with a loss report |
| Subtitles and timing | SRT, WebVTT | adopted; import produces timed blocks, export from dialogue cues |
| Production entities | MovieLabs OMC v2.8 / OMC-JSON | concepts aligned; export mapping (Appendix C) |
| Colour | ASC CDL, .cube |
adopted in styles; exported as sidecars |
| Edit | OpenTimelineIO; optional EDL CMX3600, FCP7 XML, FCPXML | export as conform; OTIO import proposes timing |
| Speech | SSML | optional on cues |
| Provenance | C2PA, XMP | embedded on export (§16.5) |
| Workflows | ComfyUI workflow JSON | native local workflow and offline batches |
| AI character definition | Character Card V2 | precedent; creatorNotes and PNG-embedded JSON borrowed |
| Location, prop, shot, cue, render batch | — | none exists; defined here |
16.2 MovieLabs OMC
Section titled “16.2 MovieLabs OMC”The Ontology for Media Creation, published by MovieLabs and governed with the major studios, defines
Character, Location, Prop, Costume, Scene, Shot, Sequence, Asset and Depiction as first-class
entities. FilmOpen’s entity list is nearly OMC’s; picks is OMC’s Depiction — the link from a narrative
object to the asset that depicts it. FilmOpen keeps its own readable field names and maps on export
(Appendix C). FilmOpen is not an OMC implementation. The OMC-JSON schema repository and the ontology
documentation carry their own licences; confirm them before reusing artefacts.
16.3 Character Card V2
Section titled “16.3 Character Card V2”The AI-conversation community’s character format embeds its JSON inside the PNG that pictures the
character. FilmOpen readers MAY embed the entity JSON in a concept-sheet PNG’s tEXt chunk under
the key filmopen, so a shared image carries its own definition. The JSON file remains authoritative;
embedding changes the image’s bytes and hash.
16.4 ComfyUI
Section titled “16.4 ComfyUI”ComfyUI embeds the workflow that produced an image in the image’s metadata. FilmOpen readers SHOULD do the same for takes produced through ComfyUI, and SHOULD preserve any embedded workflow found on ingest.
16.5 Provenance
Section titled “16.5 Provenance”Each batch item is the provenance of its take. On export a reader SHOULD write it into the output’s
XMP and, where tooling allows, emit a C2PA manifest: trainedAlgorithmicMedia for rendered takes, and
for imported takes whatever the batch’s source states — imported media may itself be generated or
composite and is never labelled camera capture by default. The human block records the human
contribution to each output; it is evidence, not a legal determination. A reader MAY produce an
authorship report walking batches, picks and commentary.
17. Editing by hand or by machine
Section titled “17. Editing by hand or by machine”The format is meant to be edited without any FilmOpen application. For a person or an agent:
- Never rename an entity file. Create a new version.
- Edit only files whose author is you. To change someone else’s, fork it: copy, rename to your
handle and
v1, setforkedFrom. A delegated edit to another’s file is still valid data; the maintainer decides whether to accept it. - Prefer not to edit a version named by
_official.json. Fork instead. If you must, you are changing what everyone sees. - Keep the header in step with the filename.
- Never renumber block ids. Add with the next unused number; reorder by moving array elements.
- Short references in story files; full references in
forkedFrom,prefer,on; media references inpicks,refs,preview,file. - Do not write takes into entities. Drop conforming media beside the JSON, or name it in a batch;
a reader will find it. If you cannot name it, use
_inbox/. - No secrets in the project.
- Preserve fields you do not understand.
- What the format cannot say goes in
notes, or inxfor structured application data.
A machine generating a project from a film should produce: pj_; one ch_ per identified speaker with
aliases; lo_ per setting; sc_ files with timed blocks; sh_ per detected cut with place; cu_
per dialogue line; an import batch; extracted takes — and nothing else.
18. Conformance
Section titled “18. Conformance”18.1 Files
Section titled “18.1 Files”A conforming file is UTF-8 JSON with no duplicate keys, named by the grammar for its category, with the required header for that category. Writers SHOULD pretty-print with two-space indentation for readable diffs; whitespace is not semantic.
18.2 Readers
Section titled “18.2 Readers”A conforming reader:
- MUST parse every filename by the grammars in §5.4 and dispatch on type;
- MUST read
filmopen-project.jsonwhen present (§4.4) and use the media root it names; MUST NOT refuse a folder that lacks it; - MUST resolve references by §6;
- MUST discover takes by scanning and by batches, and MUST NOT require entities to list them;
- MUST preserve unknown fields and the
xobject when rewriting a file it authors; - MUST NOT assume it is the only writer, and MUST NOT move, rename or delete files it does not understand;
- SHOULD warn, and continue, on: a header that disagrees with its filename; a file whose author is
not the current user being modified; an
_official.jsonwritten by a non-director; a version named by_official.jsonbeing edited; a segment longer than 10 characters; a reference that resolves ambiguously; an explicit epoch that does not exist; a project file that declares no epochs.
Authorship warnings are not validity tests. A file edited by someone other than its named author is still a conforming file; whether it is accepted is the maintainer’s decision.
18.3 Writers
Section titled “18.3 Writers”A conforming writer:
- MUST write lowercase filenames matching §5;
- MUST write
filmopen-project.jsonwhen creating a project folder (§4.4), and SHOULD write the creator’s first project version with the creator as director and at least one epoch (§8.2, §8.3); - MUST write the required header for the file’s category;
- SHOULD write only under the current user’s owner handle or a workspace of it;
- MUST NOT delete another author’s files.
18.4 Schemas and tests
Section titled “18.4 Schemas and tests”JSON Schemas for every file type are intended to be published at https://filmopen.ai/schema/1/<type>.json, CC0, and
usable offline. Until released and tested, the URLs are publication targets. Schemas mark the header
and category-specific required fields (including one project story-root list) as required, and enumerate the
vocabularies in Appendix A without restricting free-form objects to them. Cross-file resolution and
timeline arithmetic are reader and exporter work beyond schema validation.
A first implementation should demonstrate at least: a blank project written, rendered and exported with no account and no Git; the same project opened in a text editor and a third-party reader; a delegated edit shown clearly to a maintainer; base and two epochs of one character used in different scenes with independent references; another contributor’s shot rendered and discovered without changing their file; an imported file with a non-conforming name referenced through a batch; a plugin run compared and partly accepted; an interrupted provider job recovered without a second paid request; and an integer-rate and a fractional-rate export opened in a named editing application.
19. Not in this version
Section titled “19. Not in this version”- Overlays or inheritance. Every file is complete.
- Reserved key prefixes, canonical serialisation, hash-addressed JSON, UUIDs. Any editor works.
- Per-field attribution, immutable revisions, history files. Credit lives in
forkedFrom,by, batches and commentary; history lives in Git. - Frame- or sample-unit timing fields. Milliseconds only; exporters convert and report rounding.
- Cast instances. A scene selects one appearance per character; a story needing two at once uses two tags.
- A full edit model — L-cut audio splits beyond cue placement, parameterised transitions, effects. That is the editing application’s job; the format hands it a conform with timing.
- Alternate cuts as first-class objects. An alternate assembly is a set of shot versions with
different
place. An explicit assembly entity may be added in a later version. - Identity or authentication. Handles are names. Trust is the repository gatekeeper’s.
Appendix A — Attribute vocabulary
Section titled “Appendix A — Attribute vocabulary”Everything in this appendix is optional. It exists so that writers — human, scripted or AI — share a
vocabulary, so that comparisons line up attribute by attribute, and so that a reverse-engineering tool
has a checklist of what to look for. Free-form objects (appearance, personality, lighting, …) may
carry any additional keys.
Enumerated values are lowercase strings. Where a field accepts free text, the enumeration is a suggested vocabulary, not a constraint. “media ref” means a media reference as defined in §6.3.
A.1 Character ch
Section titled “A.1 Character ch”| Key | Type | Values / notes |
|---|---|---|
kind |
enum | principal supporting extra group narrator creature animal |
aliases |
string[] | script cue names, nicknames, transcript labels |
summary |
string | one or two sentences |
arc |
string | how the character changes across the story |
birthYear |
integer | year of birth, the same in every epoch file; with the epoch’s year a reader proposes appearance.age (§9.1) |
appearance.age |
number or string | 30, "late thirties"; proposed from birthYear and the epoch’s year, overridable |
appearance.gender |
string | free |
appearance.ethnicity |
string | free; optional; for continuity only |
appearance.species |
string | human default |
appearance.heightCm appearance.weightKg |
number | |
appearance.build |
string | slight lean athletic average stocky heavy … |
appearance.skin |
string | tone, texture, notable features |
appearance.hair.color .length .style .texture |
string | length: bald buzz short chin shoulder long; texture: straight wavy curly coily |
appearance.facialHair |
string | |
appearance.eyes.color .shape .notes |
string | |
appearance.face |
string | shape, notable features |
appearance.marks |
string[] | scars, tattoos, birthmarks, with location |
appearance.glasses appearance.jewellery |
string | worn habitually |
appearance.posture appearance.gait |
string | how they stand and move |
appearance.hands appearance.teeth |
string | often visible in close-ups |
appearance.notes |
string | |
personality.summary |
string | |
personality.traits |
string[] | |
personality.wants .needs .fears |
string | |
personality.speech |
string | rhythm, vocabulary, verbal habits |
personality.mannerisms |
string[] | physical habits |
voice.description |
string | |
voice.pitch |
enum | very-low low mid high very-high |
voice.pace |
enum | slow measured normal quick rapid |
voice.timbre |
string | breathy rasp nasal resonant thin … |
voice.accent voice.lang |
string | free; BCP 47 |
voice.refs |
media ref[] | reference voice samples for this character and epoch |
voice.providerBindings |
object | platform tag → provider voice id; samples and text remain the portable truth |
relationships[] |
object | { character, relation } |
defaultOutfit |
tag | outfit used when a scene does not say; resolved at the character’s epoch |
prompt.positive prompt.negative |
string | |
creatorNotes |
string | for people; excluded from prompts unless explicitly included |
picks.sheet picks.turnaround picks.expressions |
media ref or media ref[] | chosen concept sheets |
refs |
media ref[] or grouped object | §9.0 |
preview |
media ref | shown in library views |
A.2 Outfit of
Section titled “A.2 Outfit of”| Key | Type | Values / notes |
|---|---|---|
garments[] |
object | { item, color, material, fit, pattern, condition, notes } |
accessories |
string[] | |
footwear |
string | |
palette |
string[] | hex or names |
era |
string | |
condition |
enum | new worn distressed damaged bloodied wet muddy |
prompt creatorNotes picks.sheet refs preview |
as for character; no voice |
A.3 Location lo and Prop pr
Section titled “A.3 Location lo and Prop pr”Location
| Key | Type | Values / notes |
|---|---|---|
kind |
enum | interior exterior both |
aliases |
string[] | slugline names |
geography |
object | { city, region, country, coordinates } |
era |
string | period of the architecture and dressing |
architecture |
string | style, materials, scale |
description |
string | |
dressing |
string[] | props and set dressing habitually present |
areas |
tag[] | sub-locations <parent>.<area> |
lighting.default |
string | |
lighting.practicals |
string[] | visible light sources |
lighting.windows |
string | direction, size, coverings |
sound.roomTone sound.ambience |
string | |
weather |
string | default, exteriors |
timeOfDay |
enum | default; see A.5 |
access |
string | entrances, exits, sightlines |
palette |
string[] | |
prompt creatorNotes picks.sheet refs preview |
groups often used: floorPlans, panoramas, lighting |
Prop
| Key | Type | Values / notes |
|---|---|---|
kind |
enum | vehicle weapon document device furniture food tool clothing-item creature other |
hero |
boolean | seen close; needs a strong reference |
description scale material condition |
string | |
interaction |
string | how characters handle it |
sound |
string | what it sounds like |
prompt creatorNotes picks.sheet refs preview |
A.4 Shot sh
Section titled “A.4 Shot sh”| Key | Type | Values |
|---|---|---|
size |
enum | ecu extreme close-up · cu close-up · mcu medium close-up · ms medium · mls medium long / cowboy · ls long / wide · els extreme long · ots over-the-shoulder · pov · two-shot · group · insert · establishing · master |
angle |
enum | eye low high dutch overhead birds-eye worms-eye profile three-quarter frontal reverse |
movement |
enum | static pan tilt push-in pull-out truck pedestal crane boom handheld steadicam tracking arc orbit zoom-in zoom-out rack-focus whip-pan drone |
movementNotes |
string | speed, start and end framing |
lens.focalMm |
number | |
lens.aperture |
number | f-stop |
lens.dof |
enum | shallow moderate deep |
lens.anamorphic |
boolean | |
lens.focus |
string | what is sharp; rack targets |
speed |
enum | normal slow fast timelapse freeze |
speedFactor |
number | 0.5 = half speed |
lighting.key.direction |
enum | front side three-quarter back rim top under |
lighting.key.quality |
enum | hard soft |
lighting.style |
enum | high-key low-key natural practical silhouette neon firelight mixed |
lighting.colorTempK |
number | |
lighting.contrast |
enum | flat normal high extreme |
lighting.practicals |
string[] | |
lighting.notes |
string | |
composition.headroom |
enum | tight normal loose none |
composition.leadRoom |
string | |
composition.eyeline |
string | |
composition.screenDirection |
string | facing left moving right … |
composition.symmetry |
enum | centred thirds asymmetric |
composition.depth |
object | { foreground, midground, background } |
composition.blocking |
string | where characters are and move |
characters |
tag[] | visible in frame; appearance and outfit come from the scene cast |
props |
tag[] | visible in frame |
action |
string | what happens within the shot, in order |
continuity |
string[] | states that must match adjacent shots |
vfx |
string | |
aspect |
string | override of project aspect |
durationSec |
number | target; the hold for a still |
deliverables |
object | keys storyboard firstFrame lastFrame keyframes clip; each { model, platform?, prompt, negative?, refs?, from?, inputs?, params? } |
place |
object | §11.3 |
picks |
object | one media ref, or several frames, per deliverable |
coverage |
string | notes on what else was shot for this beat |
A.5 Scene sc and story units
Section titled “A.5 Scene sc and story units”| Key | Type | Values |
|---|---|---|
location |
tag | locationEpoch overrides the scene epoch for the location |
epoch |
epoch | |
storyDay |
number | continuity day |
time |
enum | dawn morning midday afternoon golden-hour dusk blue-hour night late-night |
weather |
string | clear overcast rain storm fog snow wind heat-haze … free |
cast[] |
object | { character, epoch?, outfit?, notes? } — one selection per character |
props |
array | tags, or { prop, epoch } for an explicit state |
style |
tag | |
synopsis |
string | |
purpose |
string | what the scene does for the story |
mood |
string | |
pacing |
enum | slow measured brisk frantic |
targetDurationSec |
number | |
sound |
object | { ambience, notes } |
continuity |
string[] | |
vfx |
string | |
shots cues |
tag[] | order of the scene’s shots and cues |
blocks |
array | §10.3 |
Units add scenes / sequences / episodes for order, and cascade epoch, cast, locations,
styles.
A.6 Cue cu
Section titled “A.6 Cue cu”| Key | Type | Values |
|---|---|---|
kind |
enum | dialogue narration music sfx ambience |
scene or unit |
full ref | what the blocks belong to |
blocks |
id[] | span, within scene |
anchors[] |
object | { scene, blocks } when a unit-level cue cites specific scenes’ blocks |
character |
tag | dialogue and narration |
spoken |
string | replaces block text |
ssml |
string | alternative to spoken |
lang |
string | BCP 47 |
delivery.effort |
enum | whisper quiet normal raised shout |
delivery.emotion |
string | |
delivery.processing |
enum | none phone radio pa distant underwater |
delivery.adr |
boolean | replaces on-camera sound |
music.tempoBpm music.key |
||
music.instrumentation |
string[] | |
music.mood music.genre music.structure |
string | |
music.reference |
string | a description, never a copyrighted recording as a target |
music.lyrics |
string | |
music.stems |
object | named stem → media ref, when a delivered piece is split |
sfx.description |
string | |
sync[] |
object | { with, offsetMs, event } — hit points |
model platform |
tag | |
place |
object | §11.3 incl. gainDb pan fadeInMs fadeOutMs |
picks |
object | voice music sfx ambience |
A.7 Style st
Section titled “A.7 Style st”| Key | Type | Values |
|---|---|---|
genre |
string | |
references |
string[] | descriptive — eras, movements, techniques |
look.stock |
string | film stock or digital emulation |
look.grain |
enum | none fine medium heavy |
look.halation |
enum | none slight strong |
look.contrast |
enum | flat normal high extreme |
look.saturation |
enum | mono low normal high |
look.sharpness |
enum | soft normal crisp |
look.vignette |
enum | none slight strong |
palette |
string[] | hex |
colorTempBias |
enum | cool neutral warm |
aspect letterbox |
string / boolean | |
lensCharacter |
string | flare, breathing, distortion |
cdl |
object | { slope[3], offset[3], power[3], saturation } |
lut |
media ref | .cube |
prompt refs preview |
groups often used: images, lighting, sound |
A.8 Block kinds and per-kind fields
Section titled “A.8 Block kinds and per-kind fields”| Kind | Fields |
|---|---|
dialogue |
character text direction offscreen voiceover dual lang |
action |
text characters? |
narration |
character text lang |
transition |
text — CUT TO: DISSOLVE TO: FADE OUT. … |
title |
text font? (misc tag) position? durationMs? |
lyric |
character text |
note |
text |
All kinds: id; optional startMs, endMs.
A.9 Project pj
Section titled “A.9 Project pj”author v forkedFrom? label? name kind (short feature miniseries series) genre[] year
logline synopsis lang rating format{aspect,fps,resolution,color,…} runtimeMin
credits[{role,name,handle}] epochs{<token>: {label?, order?, year?}} (at least one; the first is the
default) contributors tracks license hooks, and exactly one story root list: seasons,
episodes, sequences or scenes.
Recommended genre tokens: action adventure animation biography comedy crime documentary
drama family fantasy history horror musical mystery noir romance science-fiction
thriller war western. A project may name others.
A.10 Render batch item
Section titled “A.10 Render batch item”n source deliverable take model platform prompt negative params inputs[] output
sha256 costUsd durationMs elapsedMs at{ms|startMs,endMs} human{selectedFrom,promptEditedBy,manualEdits[]}
status jobId attempts error thumbnail poster proxy waveform mimeType bytes width
height fps frameCount sampleRate channels workflow.
Appendix B — Worked example
Section titled “Appendix B — Worked example”One scene of The Cartographer as a story and conform example. The story and selected media are listed below; provider/model definitions for regeneration are intentionally omitted. Model/platform labels in the historical batch are illustrative. The supplied media has the durations recorded in the batches. Shortened hashes are illustrative; real files use complete hashes. B.10 follows the placements.
B.1 Files
Section titled “B.1 Files”the-cartographer/ filmopen-project.json pj_cartographer_john123_v1.json character/main-hero/ ch_main-hero_30yo_john123_v1.json ch_main-hero_30yo_maria_v1.json ch_main-hero_30yo_official.json cm_ch_main-hero_maria.json cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1.png references/kira/ voice-calm.wav location/archive/ lo_archive_mid-war_john123_v1.json cs_lo_archive_mid-war_john123_v1_r7c21_john123_1.png prop/chart/ pr_chart_default_john123_v1.json style/war-grade/ st_war-grade_default_maria_v1.json st_war-grade_default_official.json s1/ se_s1_john123_v1.json e2/ ep_e2_john123_v1.json sc5/ sc_5_john123_v1.json sh_5.1_john123_v1.json sh_5.2_john123_v1.json cu_5.1_john123_v1.json cu_5.2_john123_v1.json cu_5.3_john123_v1.json ff_sh_5.1_john123_v1_r8af0_maria_1.png cl_sh_5.1_john123_v1_r8af0_maria_1.mp4 ff_sh_5.2_john123_v1_r8af0_maria_1.png cl_sh_5.2_john123_v1_r8af0_maria_1.mp4 vo_cu_5.1_john123_v1_r8af0_maria_1.wav am_cu_5.2_john123_v1_r8af0_maria_1.wav vo_cu_5.3_john123_v1_r8af0_maria_1.wav render/ rd_7c21_john123.json rd_8af0_maria.jsonHere the media sits beside the JSON, so the manifest names no data locator and the project folder is
its own media root:
{ "filmopen": 1, "tag": "cartographer" }Had the renders been kept in a synced folder next to the project, the manifest would say
"data": { "type": "local", "path": "../the-cartographer-data" } and every .png, .mp4 and .wav
above would live there instead, under the same names (§4.4).
B.2 Project
Section titled “B.2 Project”{ "filmopen": 1, "type": "pj", "tag": "cartographer", "author": "john123", "v": 1, "name": "The Cartographer", "kind": "series", "genre": ["drama", "mystery"], "year": 2026, "logline": "A mapmaker discovers her charts are rewriting the coastline.", "lang": "pt-BR", "format": { "aspect": "2.39:1", "fps": 24, "resolution": "1920x804", "color": "rec709" }, "epochs": { "default": { "label": "Present day", "order": 1, "year": 2026 }, "mid-war": { "label": "During the war", "order": 2, "year": 1943 } }, "contributors": { "john123": { "name": "João Silva", "role": "director" }, "maria": { "name": "Maria Costa" } }, "tracks": [ { "id": "pic", "kind": "av", "name": "Picture" }, { "id": "dx", "kind": "audio", "name": "Dialogue" }, { "id": "amb", "kind": "audio", "name": "Ambience" }, { "id": "mx", "kind": "audio", "name": "Music" } ], "seasons": ["s1"], "license": "CC-BY-SA-4.0", "created": "2026-09-05T18:00:00Z", "updated": "2026-09-06T16:00:00Z"}B.3 Character — two versions and the official pointer
Section titled “B.3 Character — two versions and the official pointer”{ "filmopen": 1, "type": "ch", "tag": "main-hero", "epoch": "30yo", "author": "john123", "v": 1, "name": "Kira Voss", "kind": "principal", "aliases": ["KIRA"], "summary": "A cartographer who discovers her maps are rewriting the coastline.", "appearance": { "age": 30, "gender": "woman", "build": "lean", "skin": "olive", "hair": { "color": "black", "length": "shoulder", "style": "loose" }, "eyes": { "color": "dark brown" }, "marks": ["burn scar, left forearm"] }, "personality": { "summary": "Guarded, precise.", "speech": "Short sentences." }, "voice": { "description": "low, unhurried, slight rasp", "pitch": "low", "pace": "slow", "lang": "pt-BR", "refs": ["references/kira/voice-calm.wav"] }, "prompt": { "positive": "30yo woman, olive skin, black shoulder-length hair, lean build, burn scar left forearm", "negative": "cartoon, plastic skin" }, "created": "2026-09-05T18:04:11Z", "updated": "2026-09-05T19:22:40Z"}{ "filmopen": 1, "type": "ch", "tag": "main-hero", "epoch": "30yo", "author": "maria", "v": 1, "name": "Kira Voss", "kind": "principal", "aliases": ["KIRA"], "forkedFrom": "ch_main-hero_30yo_john123_v1", "summary": "A cartographer who discovers her maps are rewriting the coastline.", "appearance": { "age": 30, "gender": "woman", "build": "lean", "skin": "olive", "hair": { "color": "copper red", "length": "short", "style": "cropped, undercut" }, "eyes": { "color": "dark brown" }, "marks": ["burn scar, left forearm", "small compass-rose tattoo, right wrist"] }, "personality": { "summary": "Guarded, precise.", "speech": "Short sentences." }, "voice": { "description": "low, unhurried, slight rasp", "pitch": "low", "pace": "slow", "lang": "pt-BR", "refs": ["references/kira/voice-calm.wav"] }, "prompt": { "positive": "30yo woman, olive skin, cropped copper-red hair with undercut, lean build, burn scar left forearm, small compass tattoo right wrist", "negative": "cartoon, plastic skin" }, "picks": { "sheet": "cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1" }, "refs": { "sheets": ["cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1"] }, "preview": "cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1", "created": "2026-09-06T09:12:00Z", "updated": "2026-09-06T10:31:02Z"}{ "filmopen": 1, "type": "ch", "tag": "main-hero", "epoch": "30yo", "official": "ch_main-hero_30yo_maria_v1", "setBy": "john123", "setAt": "2026-09-06T14:20:00Z", "note": "The red hair reads better against the archive." }B.4 Location, prop, style
Section titled “B.4 Location, prop, style”{ "filmopen": 1, "type": "lo", "tag": "archive", "epoch": "mid-war", "author": "john123", "v": 1, "name": "The municipal archive", "aliases": ["ARCHIVE"], "kind": "interior", "geography": { "city": "Lisbon", "country": "PT" }, "era": "1930s building, wartime neglect", "description": "Long reading room, iron shelving to the ceiling, one skylight, dust in the air.", "dressing": ["oak reading table", "green-shade lamps", "map drawers", "sandbags at the windows"], "lighting": { "default": "single skylight, cold; lamps warm and low", "practicals": ["green-shade desk lamps"] }, "sound": { "roomTone": "large, dead, high ceiling", "ambience": "rain on skylight, distant sirens" }, "prompt": { "positive": "1930s municipal archive reading room, iron shelving, skylight, green desk lamps, sandbagged windows, wartime, dust" }, "picks": { "sheet": "cs_lo_archive_mid-war_john123_v1_r7c21_john123_1" }, "refs": { "sheets": ["cs_lo_archive_mid-war_john123_v1_r7c21_john123_1"] }, "created": "2026-09-05T18:30:00Z", "updated": "2026-09-05T18:30:00Z"}{ "filmopen": 1, "type": "pr", "tag": "chart", "epoch": "default", "author": "john123", "v": 1, "name": "The 1994 harbour chart", "kind": "document", "hero": true, "description": "Hand-drawn nautical chart, yellowed linen-backed paper, sepia ink, folded twice.", "prompt": { "positive": "hand-drawn nautical chart, yellowed linen paper, sepia ink, fold creases" }, "created": "2026-09-05T18:40:00Z", "updated": "2026-09-05T18:40:00Z"}{ "filmopen": 1, "type": "st", "tag": "war-grade", "epoch": "default", "author": "maria", "v": 1, "name": "War — gritty, desaturated", "look": { "stock": "16mm colour negative", "grain": "medium", "contrast": "high", "saturation": "low" }, "palette": ["#2b2f33", "#6b7076", "#b9bcb8", "#d9c9a3"], "prompt": { "positive": "desaturated, cold grey palette, high contrast, 16mm grain, handheld", "negative": "saturated, glossy" }, "cdl": { "slope": [0.95, 0.98, 1.05], "offset": [-0.02, -0.02, 0.0], "power": [1.1, 1.1, 1.05], "saturation": 0.6 }, "created": "2026-09-06T08:00:00Z", "updated": "2026-09-06T08:00:00Z"}{ "filmopen": 1, "type": "st", "tag": "war-grade", "epoch": "default", "official": "st_war-grade_default_maria_v1", "setBy": "john123" }B.5 Story units
Section titled “B.5 Story units”{ "filmopen": 1, "type": "se", "tag": "s1", "author": "john123", "v": 1, "name": "Season 1", "episodes": ["e2"], "created": "2026-09-05T18:00:00Z", "updated": "2026-09-05T18:00:00Z" }{ "filmopen": 1, "type": "ep", "tag": "e2", "author": "john123", "v": 1, "name": "Episode 2 — Low Tide", "synopsis": "Kira finds the first altered chart.", "epoch": "mid-war", "cast": [{ "character": "main-hero", "epoch": "30yo" }], "locations": ["archive"], "styles": ["war-grade"], "scenes": ["5"], "created": "2026-09-05T18:00:00Z", "updated": "2026-09-06T12:00:00Z"}B.6 Scene
Section titled “B.6 Scene”{ "filmopen": 1, "type": "sc", "tag": "5", "author": "john123", "v": 1, "name": "The archive", "location": "archive", "epoch": "mid-war", "storyDay": 3, "time": "night", "weather": "rain", "cast": [{ "character": "main-hero", "epoch": "30yo" }], "props": ["chart"], "style": "war-grade", "synopsis": "Kira compares the two charts and realises the coastline moved.", "purpose": "First proof. Turns the mystery from doubt to certainty.", "targetDurationSec": 40, "shots": ["5.1", "5.2"], "cues": ["5.1", "5.2", "5.3"], "blocks": [ { "id": "bl_1", "kind": "action", "text": "Kira spreads both charts across the reading table." }, { "id": "bl_2", "kind": "dialogue", "character": "main-hero", "text": "The bay was here last spring.", "direction": "flat disbelief, does not look up" }, { "id": "bl_3", "kind": "action", "text": "Behind her, the window flashes white. A second later, the glass goes." }, { "id": "bl_4", "kind": "dialogue", "character": "main-hero", "text": "Not now.", "offscreen": true } ], "created": "2026-09-06T11:58:02Z", "updated": "2026-09-06T12:02:11Z"}B.7 Shots — eight seconds, then a straight cut to five seconds
Section titled “B.7 Shots — eight seconds, then a straight cut to five seconds”{ "filmopen": 1, "type": "sh", "tag": "5.1", "author": "john123", "v": 1, "name": "Kira at the table", "scene": "sc_5_john123_v1", "blocks": ["bl_1", "bl_2"], "characters": ["main-hero"], "props": ["chart"], "size": "mcu", "angle": "eye", "movement": "push-in", "movementNotes": "slow, ends tight on her hands", "lens": { "focalMm": 50, "dof": "shallow" }, "lighting": { "key": { "direction": "side", "quality": "soft" }, "style": "low-key", "colorTempK": 3200, "practicals": ["green desk lamp"] }, "durationSec": 8, "deliverables": { "firstFrame": { "model": "nanobanana", "prompt": "Kira leaning over two nautical charts on an oak table, green desk lamp, archive shelving behind, 16mm grain", "refs": ["cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1", "cs_lo_archive_mid-war_john123_v1_r7c21_john123_1"] }, "clip": { "model": "seedance25", "prompt": "slow push in as she traces the coastline with a finger and speaks without looking up", "from": "firstFrame" } }, "place": { "track": "pic", "with": "scene", "offsetMs": 0 }, "picks": { "firstFrame": "ff_sh_5.1_john123_v1_r8af0_maria_1", "clip": "cl_sh_5.1_john123_v1_r8af0_maria_1" }, "created": "2026-09-06T12:10:00Z", "updated": "2026-09-06T16:00:00Z"}{ "filmopen": 1, "type": "sh", "tag": "5.2", "author": "john123", "v": 1, "name": "The window goes", "scene": "sc_5_john123_v1", "blocks": ["bl_3", "bl_4"], "characters": ["main-hero"], "size": "ms", "angle": "low", "movement": "static", "lens": { "focalMm": 35, "dof": "moderate" }, "lighting": { "key": { "direction": "back", "quality": "hard" }, "style": "low-key", "notes": "single white flash from behind, then darkness with lamp only" }, "continuity": ["charts still on the table", "scar visible, left forearm"], "vfx": "glass shatter, no debris toward lens", "durationSec": 5, "deliverables": { "firstFrame": { "model": "nanobanana", "prompt": "low angle, Kira in medium shot at the archive table, the window behind her blown white", "refs": ["cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1"] }, "clip": { "model": "seedance25", "prompt": "the window flashes white, glass falls, she does not turn", "from": "firstFrame" } }, "place": { "track": "pic", "after": "sh_5.1", "offsetMs": 0, "transitionIn": { "type": "cut" } }, "picks": { "firstFrame": "ff_sh_5.2_john123_v1_r8af0_maria_1", "clip": "cl_sh_5.2_john123_v1_r8af0_maria_1" }, "created": "2026-09-06T12:12:00Z", "updated": "2026-09-06T16:00:00Z"}B.8 Cues — dialogue riding with picture, a J-cut leading the second shot, ambience under the scene
Section titled “B.8 Cues — dialogue riding with picture, a J-cut leading the second shot, ambience under the scene”{ "filmopen": 1, "type": "cu", "tag": "5.1", "author": "john123", "v": 1, "name": "Kira — the bay line", "kind": "dialogue", "scene": "sc_5_john123_v1", "blocks": ["bl_2"], "character": "main-hero", "delivery": { "effort": "quiet", "emotion": "flat disbelief" }, "model": "elevenlabs", "place": { "track": "dx", "with": "sh_5.1", "offsetMs": 2750, "gainDb": -3 }, "picks": { "voice": "vo_cu_5.1_john123_v1_r8af0_maria_1" }, "created": "2026-09-06T12:20:00Z", "updated": "2026-09-06T16:00:00Z"}{ "filmopen": 1, "type": "cu", "tag": "5.3", "author": "john123", "v": 1, "name": "Kira — not now (J-cut)", "kind": "dialogue", "scene": "sc_5_john123_v1", "blocks": ["bl_4"], "character": "main-hero", "delivery": { "effort": "quiet", "emotion": "clipped" }, "model": "elevenlabs", "place": { "track": "dx", "with": "sh_5.2", "offsetMs": -1500, "gainDb": -3 }, "picks": { "voice": "vo_cu_5.3_john123_v1_r8af0_maria_1" }, "notes": "Her line starts 1.5 s before the picture cuts to 5.2 — we hear her before we see the window go.", "created": "2026-09-06T12:22:00Z", "updated": "2026-09-06T16:00:00Z"}{ "filmopen": 1, "type": "cu", "tag": "5.2", "author": "john123", "v": 1, "name": "Archive — rain and sirens", "kind": "ambience", "scene": "sc_5_john123_v1", "blocks": ["bl_1", "bl_2", "bl_3", "bl_4"], "sfx": { "description": "rain on a skylight, large dead room, one distant siren rising and falling" }, "model": "elevenlabs-sfx", "place": { "track": "amb", "with": "scene", "offsetMs": 0, "inMs": 0, "outMs": 13000, "fadeInMs": 1000, "fadeOutMs": 1500, "gainDb": -18 }, "picks": { "ambience": "am_cu_5.2_john123_v1_r8af0_maria_1" }, "created": "2026-09-06T12:25:00Z", "updated": "2026-09-06T16:00:00Z"}B.9 Render batch and commentary
Section titled “B.9 Render batch and commentary”{ "filmopen": 1, "type": "rd", "id": "7c21", "author": "john123", "kind": "manual", "status": "done", "items": [ { "n": 1, "source": "lo_archive_mid-war_john123_v1", "deliverable": "sheet", "output": "location/archive/cs_lo_archive_mid-war_john123_v1_r7c21_john123_1.png" } ] }{ "filmopen": 1, "type": "rd", "id": "8af0", "author": "maria", "kind": "render", "tier": "final", "created": "2026-09-06T15:30:00Z", "status": "done", "items": [ { "n": 1, "source": "ch_main-hero_30yo_maria_v1", "deliverable": "sheet", "model": "midjourney", "platform": "midjourney", "prompt": "character sheet, 30yo woman, olive skin, cropped copper-red hair with undercut, lean build, burn scar left forearm, compass tattoo right wrist, front three-quarter profile, neutral grey", "output": "character/main-hero/cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1.png", "sha256": "a4f1…", "costUsd": 0.08, "width": 2048, "height": 2048, "human": { "selectedFrom": 6 } }, { "n": 2, "source": "sh_5.1_john123_v1", "deliverable": "firstFrame", "model": "nanobanana", "platform": "fal", "inputs": ["character/main-hero/cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1.png", "location/archive/cs_lo_archive_mid-war_john123_v1_r7c21_john123_1.png"], "output": "s1/e2/sc5/ff_sh_5.1_john123_v1_r8af0_maria_1.png", "sha256": "0c9e…", "costUsd": 0.04, "human": { "selectedFrom": 4 } }, { "n": 3, "source": "sh_5.1_john123_v1", "deliverable": "clip", "model": "seedance25", "platform": "fal", "params": { "seed": 41221, "durationSec": 8, "fps": 24 }, "inputs": ["s1/e2/sc5/ff_sh_5.1_john123_v1_r8af0_maria_1.png"], "output": "s1/e2/sc5/cl_sh_5.1_john123_v1_r8af0_maria_1.mp4", "sha256": "9d02…", "durationMs": 8000, "elapsedMs": 64200, "costUsd": 0.56, "human": { "selectedFrom": 3 } }, { "n": 4, "source": "sh_5.2_john123_v1", "deliverable": "firstFrame", "model": "nanobanana", "platform": "fal", "output": "s1/e2/sc5/ff_sh_5.2_john123_v1_r8af0_maria_1.png", "sha256": "5b77…", "costUsd": 0.04 }, { "n": 5, "source": "sh_5.2_john123_v1", "deliverable": "clip", "model": "seedance25", "platform": "fal", "params": { "seed": 41222, "durationSec": 5, "fps": 24 }, "inputs": ["s1/e2/sc5/ff_sh_5.2_john123_v1_r8af0_maria_1.png"], "output": "s1/e2/sc5/cl_sh_5.2_john123_v1_r8af0_maria_1.mp4", "sha256": "e310…", "durationMs": 5000, "elapsedMs": 41800, "costUsd": 0.35 }, { "n": 6, "source": "cu_5.1_john123_v1", "deliverable": "voice", "model": "elevenlabs", "platform": "elevenlabs", "output": "s1/e2/sc5/vo_cu_5.1_john123_v1_r8af0_maria_1.wav", "sha256": "31cd…", "durationMs": 2500, "sampleRate": 48000, "channels": 1, "costUsd": 0.01 }, { "n": 7, "source": "cu_5.3_john123_v1", "deliverable": "voice", "model": "elevenlabs", "platform": "elevenlabs", "output": "s1/e2/sc5/vo_cu_5.3_john123_v1_r8af0_maria_1.wav", "sha256": "c0de…", "durationMs": 1000, "sampleRate": 48000, "channels": 1, "costUsd": 0.01 }, { "n": 8, "source": "cu_5.2_john123_v1", "deliverable": "ambience", "model": "elevenlabs-sfx", "platform": "elevenlabs", "output": "s1/e2/sc5/am_cu_5.2_john123_v1_r8af0_maria_1.wav", "sha256": "88a2…", "durationMs": 14000, "costUsd": 0.02 } ]}{ "filmopen": 1, "type": "cm", "target": "ch_main-hero", "author": "maria", "entries": [ { "on": "ch_main-hero_30yo_john123_v1", "at": "2026-09-06T09:05:00Z", "rating": 1, "text": "Good bones. Hair is too safe for the archive — trying red." }, { "on": "cs_ch_main-hero_30yo_maria_v1_r8af0_maria_1", "at": "2026-09-06T15:40:00Z", "rating": 1 } ]}B.10 What the export produces
Section titled “B.10 What the export produces”One timeline, Episode 2, 24 fps, 13 seconds (312 frames). All boundaries in this example are frame-aligned, so no timing rounding is needed:
| Track | Clip | Start | End |
|---|---|---|---|
| V1 Picture | cl_sh_5.1… |
0:00.000 | 0:08.000 |
| V1 Picture | cl_sh_5.2… |
0:08.000 | 0:13.000 |
| A1 Picture | the two clips’ embedded sound | as above | |
| A2 Dialogue | vo_cu_5.1… |
0:02.750 | 0:05.250 |
| A2 Dialogue | vo_cu_5.3… |
0:06.500 | 0:07.500 — leads the cut by 1.5 s |
| A3 Ambience | am_cu_5.2… |
0:00.000 | 0:13.000, 1 s in, 1.5 s out |
A marker sc_5 at 0:00.000; a marker on each clip carrying its stem; conform/ holding
sh_5.1_clip.mp4, sh_5.2_clip.mp4, cu_5.1_voice.wav, cu_5.3_voice.wav, cu_5.2_ambience.wav; a
manifest; and a report noting that the ambience take is 14 s and is trimmed to 13.
Appendix C — MovieLabs OMC correspondence
Section titled “Appendix C — MovieLabs OMC correspondence”Concept-level. Property names must be confirmed against the OMC-JSON v2.8 schema before an exporter is written.
| FilmOpen | OMC concept | Notes |
|---|---|---|
pj |
Creative Work | title, synopsis; contributors and credits → Participants |
ch |
Character | name; appearance → profile / physical characteristics; aliases → alternate names |
of |
Narrative Wardrobe / Costume | linked to Character |
lo |
Narrative Location | areas → contained Locations |
pr |
Narrative Prop | hero → notable |
st |
— | no OMC equivalent; export as Asset with CDL sidecar |
se ep sq |
Creative Work structure / Sequence | nested by scenes, sequences, episodes |
sc |
Narrative Scene | blocks → scene description and dialogue; storyDay → Context |
sh |
Shot | place → editorial timing; with Slate where an import batch supplies one |
| take | Asset | media file with identifiers; sha256 → identifier |
picks |
Depiction | the narrative-object-to-asset link |
rd |
Task and Asset provenance | human → participant contribution |
author |
Participant | owner segment |
| epoch | Context | “in which circumstances” |
FilmOpen Project Specification 1.3 Draft · filmopen.ai · CC-BY-4.0