Skip to content
screenjson

Screenplays are data.

ScreenJSON is an open schema and toolchain for treating the screenplay as a first-class, structured document. Convert from Final Draft, Fountain, FadeIn, and PDF. Store in any NoSQL database. Query it, transform it, render it, feed it to an LLM, ship it to a viewer.

ScreenJSON

ACT I — THE PROBLEM

The screenplay is the last major creative format still locked inside proprietary formats.

A novel is UTF-8. A song is MIDI or stems. A video is MP4 plus sidecar tracks. A screenplay? An .fdx file, a proprietary XML variant, or — more often than anyone wants to admit — a flat PDF that has to be re-parsed every time anything touches it.

That works fine for writing a screenplay. It breaks the moment you want to do anything else: batch-process 5,000 library titles for streaming catalogue search, build an AI tool that understands dialogue per character, version two drafts side by side, or translate a whole film for an international production.

ScreenJSON fixes this by treating the screenplay as what it already is — a structured, hierarchical, typed document — and giving it a proper schema, a proper toolchain, and a proper viewer. Open at the schema layer, licensable at the industrial layer.

INTERCUT

The same scene, two formats.

A single scene from The Heist, on the left as Final Draft's FDX XML, on the right as ScreenJSON. Same information, one of them structured.

Final Draft · FDX XML · proprietary
<Paragraph Type="Scene Heading">
  <Text>INT. VAULT - NIGHT</Text>
</Paragraph>
<Paragraph Type="Action">
  <Text>A single bulb flickers.</Text>
</Paragraph>
<Paragraph Type="Character">
  <Text>MARA</Text>
</Paragraph>
<Paragraph Type="Dialogue">
  <Text>We have ninety seconds.</Text>
</Paragraph>
ScreenJSON JSON · open
{
  "id": "7a1c0b4e-…",
  "heading": {
    "context": "INT.",
    "setting": "VAULT",
    "time":    "NIGHT"
  },
  "body": [
    { "type": "action",
      "text": { "en": "A single bulb flickers." } },
    { "type": "character", "character": "8d2f-mara" },
    { "type": "dialogue",  "character": "8d2f-mara",
      "text": { "en": "We have ninety seconds." } }
  ]
}

Stable UUIDs

Every scene, element, character — addressable forever.

Language maps

Every text field keyed by BCP 47 — en, fr, ja.

Typed elements

Action, cue, dialogue, parenthetical, shot, transition — not layout.

Queryable

jq a catalogue, index it, embed it, retrieve it.

THE SCHEMA

Every part of a screenplay, exactly where you'd expect it.

ScreenJSON models every element a working screenplay actually contains: structured sluglines with context and time-of-day, typed scene bodies with action, dialogue, cues, parentheticals, shots and transitions, a characters index, a revisions log, notes anchored to character ranges, bookmarks, embeddings, passages and summaries for retrieval — and a layout block so renderers can reproduce studio-standard formatting.

Every textual field is keyed by BCP 47 language tag, so localisation is a first-class concern, not an afterthought. Every structural node carries a UUID, so you can point to the exact line of dialogue in an otherwise-identical revision.

{
  "id": "9fea5fc5-f8f9-4c59-85d2-9ec5dcd452c1",
  "version": "1.0.0",
  "title": { "en": "The Heist" },
  "lang": "en",
  "authors": [{ "id": "…", "given": "Jordan", "family": "Lee" }],
  "characters": [
    { "id": "…", "name": "MARA", "traits": ["lead", "thief"] }
  ],
  "document": {
    "cover": { "title": { "en": "The Heist" }, "authors": ["…"] },
    "scenes": [{
      "id": "…",
      "authors": ["…"],
      "heading": { "context": "INT.", "setting": "VAULT", "time": "NIGHT" },
      "body": [
        { "type": "action", "text": { "en": "A single bulb flickers." } },
        { "type": "character", "character": "…" },
        { "type": "dialogue",  "character": "…",
          "text": { "en": "We have ninety seconds." } }
      ]
    }]
  }
}

FADE IN:

Paste a URL. Upload an FDX. See what your screenplay looks like as structured data.

APPENDIX

Start where you are.