Skip to content
screenjson

Specification

The full ScreenJSON specification: document model, element types, shared scalars, analysis, encryption, and conformance.

Last updated January 2026

ScreenJSON specification page

1. Overview

ScreenJSON is a data serialisation format for screenplays. It describes, at the structural level, everything a working screenplay contains: a cover page, one or more scenes, sluglines, typed scene elements, a characters index, revisions, notes, bookmarks, layout rules, and optional derived data for analysis and retrieval.

A ScreenJSON file is a JSON document with a stable top-level shape. The authoritative machine-readable definition is the JSON Schema at https://screenjson.com/schema.json.

This page is the human-readable counterpart. It walks through every part of the schema in the order you'd actually encounter it when reading or writing a document.

2. Design principles

Five commitments shape the schema.

Structural first, presentational second

A ScreenJSON document describes what a screenplay is, not how it looks. Slug, action, cue, parenthetical, dialogue, shot, and transition are typed nodes — not layout hints. Rendering rules live in an optional layout block that viewers can honour or ignore.

Language as a first-class concern

Every user-facing text field is a map keyed by BCP 47 language tag. A single document can carry the same line of dialogue in English, French, and Japanese side by side. Renderers pick a language at read time.

Stable identity

Every node that can be referenced from elsewhere carries a RFC 4122 UUID. Scenes, characters, authors, elements, notes, bookmarks, revisions — you can point to exactly one of them across the lifetime of a document, even after a rewrite.

Extensible without ambiguity

Every object includes an optional meta map — arbitrary string-typed key/value pairs — so tools can round-trip their own metadata. The core fields stay strictly typed and additionalProperties: false; extension goes in meta, and nowhere else.

Analysis is optional

The analysis block (embeddings, passages, summaries) is additive and discardable. A document without analysis is as valid as a document with it. Analysis sits alongside the canonical document rather than mutating it.

3. The document root

The top-level object has these required properties:

{
  "id":        "<uuid>",
  "version":   "1.0.0",
  "title":     { "en": "The Heist" },
  "lang":      "en",
  "charset":   "utf-8",
  "dir":       "ltr",
  "authors":   [ /* one or more */ ],
  "document":  { /* cover, scenes, layout, bookmarks */ }
}

…and a long list of optional properties for richer documents:

  • generator — tool that produced the file (name, version).
  • locale — BCP 47 locale (e.g. en-US), defaults to en-US.
  • contributors — editors, directors, script doctors with their roles.
  • characters — index of characters referenced by cues and dialogue.
  • colors — reusable named colours for notes, revisions, UI.
  • sources — source works this screenplay is based on.
  • registrations — registration records (e.g. WGA).
  • revisions — global revision history.
  • encrypt — default encryption parameters.
  • license — licensing / copyright descriptor.
  • taggable / genre / themes — slug-keyed tag indexes for filtering.
  • logline — one-sentence summary, language-keyed.
  • analysis — optional derived data for retrieval and AI.

4. Shared types

ScreenJSON reuses a small set of scalar and small-object types everywhere. Understanding them once means the rest of the schema reads itself.

uuid

An RFC 4122 UUID string, formatted 8-4-4-4-12.

slug

A lowercase, kebab-cased identifier matching ^[a-z0-9]+(?:-[a-z0-9]+)*$, between 3 and 50 characters. Used for every enumerable identifier that's not a UUID: tag names, style ids, revision labels, colour ids.

datetime

An ISO 8601 date-time string (date-time format).

lang

A BCP 47 language tag. The schema regex accepts a 2–3 letter primary subtag and any number of 2–8 character sub-subtags: en, en-GB, fr-CA, zh-Hant, sr-Latn-RS.

dir

Text direction: ltr or rtl.

charset

An IANA character set label, defaulting to utf-8.

text and name

The single most important pattern in the schema. Any place where a screenplay might need translation, ScreenJSON uses a map keyed by language tag:

{
  "en": "Hello.",
  "fr": "Salut.",
  "ja": "こんにちは。"
}

text allows up to 10,000 characters per language — long dialogue or action runs. name is the short-form variant, capped at 255 characters — titles, display names, cover labels.

meta

An arbitrary string-to-string map with key pattern ^[A-Za-z0-9_.:-]{1,64}$ and 2KB values. Every object has one. It is the only place tools are permitted to stash data not described elsewhere in the schema.

tags and roles

Unique arrays of slug. Scenes, characters, and elements carry tags; contributors carry roles.

5. Authors & contributors

Authors — the original writers of the content — are required at the document level and at every element level. An author is a minimal object: a UUID, a given name, a family name, and optional meta.

{
  "id":     "a2c2a2f0-1c34-4b68-9f4d-ac8f21a0d8a4",
  "given":  "Jordan",
  "family": "Lee"
}

Contributors are anyone who made artistic input other than original authorship — editor, director, script doctor, showrunner. They carry the same fields plus a roles array of slugs: ["editor"], ["script-doctor", "director"].

Why both?

Attribution in screenwriting is contested and legally significant. Separating "authors" from "contributors" makes the canonical credit list unambiguous while still giving you somewhere to record the people who shaped the work.

6. Characters

Characters are declared once, at the document level, and referenced everywhere else by UUID. A character has:

{
  "id":      "<uuid>",
  "slug":    "mara",                       // optional, for tooling
  "name":    "MARA",                       // canonical display name
  "aliases": ["Mara Halpern", "M."],
  "desc":    { "en": "A thief, mid-30s." },
  "traits":  ["lead", "thief", "antihero"],
  "meta":    {}
}

name is the canonical form that renderers show in character cues (traditionally uppercase). aliases captures alternate names and titles used inside the script so they can be reconciled to the same canonical character. traits is an editorial taxonomy — casting types, narrative roles, demographics — strictly non-canonical and useful for search.

Why a character index?

Because the character of MARA should be the same character every time she speaks, regardless of whether the script says MARA, MARA (V.O.), or M., and regardless of what language the dialogue is rendered in. A UUID anchors her.

7. The document container

The document property is the screenplay itself. It has three required halves: a cover page, a list of scenes, and — implicitly — a layout block for renderers.

{
  "document": {
    "cover":   { "title": { "en": "…" }, "authors": ["<uuid>"] },
    "layout":  { "styles": [], "templates": [] },
    "bookmarks": [],
    "scenes": [ /* one or more */ ],
    "meta": {}
  }
}

Cover

The cover page — title, authors, optional sources, and free-form extra text. It exists so that a ScreenJSON document can produce a faithful title page without re-interpreting document-level metadata.

Bookmarks

Stable shortcuts into the document. Each bookmark references a specific scene UUID and element UUID, so even after a re-order or rewrite it still lands on the right line.

8. Scenes

A scene has this shape:

{
  "id":       "<uuid>",
  "authors":  ["<uuid>"],
  "heading":  { /* slugline */ },
  "body":    [ /* elements: action, cue, dialogue, … */ ],
  "cast":    ["<uuid>"],
  "animals": [], "extra": [], "locations": [], "moods": [],
  "props":   [], "sfx": [], "sounds": [], "tags": [],
  "vfx":     [], "wardrobe": [],
  "meta":    {}
}

Every scene has at least one author, one slugline, and a body of zero or more elements (an empty body is allowed for outlining). The cast array is the set of character UUIDs that appear in the scene — a projection that tools and UIs can use without walking the body.

The ten production taxonomies — animals, extra, locations, moods, props, sfx, sounds, tags, vfx, wardrobe — are each a unique array of slugs. Populated by breakdown tools, they make scheduling, budgeting, and discovery queryable.

9. Sluglines

The slugline — the scene heading — is one of the few places in screenwriting where formatting is the structure. ScreenJSON decomposes it:

{
  "no":      14,
  "context": "INT.",
  "setting": "VAULT — SUB-LEVEL 3",
  "time":    "NIGHT",
  "mods":    ["FLASHBACK", "ESTABLISHING"],
  "desc":    { "en": "Low-ceilinged. Emergency lighting." },
  "meta":    {}
}

context is constrained to the industry set — one of INT, EXT, INT/EXT, EXT/INT, I/E, or POV. The time field is either one of the common enums — DAY, NIGHT, DAWN, DUSK, LATER, MOMENTS LATER, CONTINUOUS, MORNING, AFTERNOON, EVENING, THE NEXT DAY — or any custom uppercase string matching the shoulder-pattern ^[A-Z0-9][A-Z0-9 .’'/-]{1,39}$.

mods is for additional slugline modifiers — INTERCUT, FLASHBACK, ESTABLISHING, SAME, whatever your production calls them.

10. Scene elements

Every element inside a scene body extends a common element base — shared fields shown here once and then assumed throughout:

{
  "id":           "<uuid>",
  "scene":        "<uuid>",                 // back-reference
  "authors":      ["<uuid>"],
  "contributors": ["<uuid>"],
  "access":       ["<role-slug>"],          // RBAC
  "notes":        [ /* note objects */ ],
  "charset":      "utf-8",
  "dir":          "ltr",
  "class":        "<slug>",                 // custom class for styling
  "dom":          "<string>",               // optional dom hint
  "encrypt":      { /* encrypt params */ },
  "locked":       false,
  "omit":         false,                    // scheduled-for-deletion
  "revisions":    [ /* revision markers */ ],
  "styles":       ["<slug>"],
  "meta":         {}
}

On top of that base, each element has its own narrow type:

action

Narrative description. text is a language-keyed map.

{ "type": "action", "text": { "en": "MARA lifts the lid." } }

character (cue)

The cue above a block of dialogue. References a character UUID and optionally carries a display override like MARA (V.O.).

{ "type": "character", "character": "<uuid>", "display": "MARA (CONT'D)" }

parenthetical

The bracketed actor direction between a cue and a line.

{ "type": "parenthetical", "text": { "en": "(whispering)" } }

dialogue

The line itself. References a character UUID. origin captures the dialogue's source — V.O., O.S., O.C., or FILTER. dual flags side-by-side dual-dialogue.

{
  "type": "dialogue",
  "character": "<uuid>",
  "origin": "V.O.",
  "dual": false,
  "text": { "en": "We have ninety seconds." }
}

shot

Camera direction — CLOSE ON, ANGLE ON, PUSH IN. Carries an optional fov (0–360°) and perspective (2D or 3D) for visualisation tools.

transition

Scene transitions — CUT TO:, FADE TO BLACK., SMASH CUT TO:

general

A typed catch-all for any scene-body text that doesn't fit the others — chapter dividers, sub-headings, scripted on-screen text.

11. Revisions & notes

Revisions

A revision describes a discrete editorial pass. It has a UUID, an optional parent UUID (the revision it was forked from), an integer index, one or more authors, a sluggable label (draft, blue, final, production-draft), and a created timestamp.

{
  "id": "<uuid>",
  "parent": "<uuid>",
  "index": 3,
  "authors": ["<uuid>"],
  "label": "blue",
  "created": "2026-01-14T10:12:00Z"
}

Revisions can live at the document level (revisions on the root), or attached to individual elements (element.revisions), making fine-grained revision marking possible without inventing a sidecar format.

Notes

Notes are annotations. Every note has an author, a creation timestamp, language-keyed text, an optional colour, and — most importantly — a highlight array of character index ranges into the rendered text of the element it's attached to:

{
  "id": "<uuid>",
  "created": "2026-01-14T10:20:00Z",
  "contributor": "<uuid>",
  "highlight": [[12, 27]],          // start/end codepoints
  "color": "amber",
  "text": { "en": "Too on-the-nose." }
}

12. Layout, styles & templates

document.layout is an optional block that tells renderers how to present the document. Everything in it is informational — viewers may honour, partially honour, or ignore it.

Ribbons

Header and footer ribbons — optional repeating content at the top and bottom of each page. cover controls whether the ribbon appears on the cover, show toggles visibility, start sets the page from which the ribbon first appears, and omit is a list of pages to skip.

Status

The industry revision status block: color — one of white, blue, pink, yellow, green, goldenrod, buff, salmon, cherry — plus a round and updated timestamp.

Styles & templates

Reusable style fragments (short) and template fragments (longer). Each has a slug id, a default flag, and a body of up to 5,000 or 20,000 characters respectively.

Guides

References to external presentation standards — a URL, a title, an id, and notes. They let a document tell a renderer "follow this convention", without attempting to embed the convention itself.

13. Analysis: embeddings, passages, summaries

The analysis block holds derived data for retrieval and AI workflows. Everything in it is optional and discardable — a document without analysis is still canonical.

Embeddings

Embeddings are grouped by target UUID (keyed by the UUID of the scene, element, or character they describe) and each has:

{
  "id": "<uuid>",
  "model": "text-embedding-3-large",
  "dimensions": 1536,
  "values": [0.0234, -0.0417, ],
  "source": "text",        // name|text|desc|heading|composite
  "lang": "en",
  "tokens": 420,
  "created": "2026-01-14T10:30:00Z"
}

Passages

A passage is a retrieval-sized chunk of text derived from one or more elements. It has a UUID, the scene UUID it belongs to, the element UUIDs it covers, the passage text, the tokens count, and an optional overlap for sliding-window retrieval schemes.

Summaries

A summary has a scope of document or scene, optionally a target UUID, a generated flag, the model that produced it, and a creation timestamp. Human-written and machine-generated summaries share the same shape.

Settings

analysis.settings records how the analysis was produced: model name, chunk size, overlap, tokeniser. Reproducibility is a first-class concern.

14. Encryption

ScreenJSON supports confidentiality without sacrificing structural introspection: only text runs are encrypted. UUIDs, timestamps, scene counts, character lists, revision labels, and meta stay in plain text, so indexers and schedulers can still do their jobs.

{
  "encrypt": {
    "cipher":   "aes-256-ctr",
    "hash":     "sha256",
    "encoding": "hex"
  }
}

The default cipher is AES-256-CTR with SHA-256 key derivation from a shared secret of at least 10 characters. Binary output is encoded as hex, base16, base32, base64, or ascii85. Additional tool-specific parameters live in encrypt.meta.

Encryption can be declared at the document root — applying to every element that doesn't override it — or on individual elements, so you can encrypt sensitive dialogue while leaving action visible.

15. Registration & license

A document can carry one or more registrations — a registration authority name (e.g. WGA-West), a registration id, and timestamps — and a single license descriptor with an id and an optional reference URI.

16. Versioning

The top-level version field is the schema version the document was authored against. It is a strict semantic version — ^\d+\.\d+\.\d+$ — not a free-form label. Tools SHOULD warn when reading a document whose version they do not support, and MUST NOT silently drop unknown-but-well-formed fields.

17. Conformance

A ScreenJSON document conforms to version N of this specification if, and only if, it validates successfully against the JSON Schema published under https://screenjson.com/draft/<version>/schema for version N.

The following guarantees hold for every conforming document:

  • Exactly one id, version, title, lang, charset, dir, authors, and document at the root.
  • Every referenced UUID — author, character, scene, element, note, revision — exists exactly once in its canonical list.
  • Every text map is keyed by a syntactically valid BCP 47 tag.
  • No object contains properties beyond those permitted by the schema; extension data lives only in meta.

The reference validator is screenjson validate --strict in screenjson-cli. Any validator implementing the current JSON Schema draft will produce equivalent results.

Changelog

Breaking changes between drafts will always bump the major version. Additive, backwards-compatible changes will bump the minor version.