Skip to content
screenjson

Schema & data

Version-control screenplays as ScreenJSON

Commit ScreenJSON files to Git, diff drafts line-by-line, and keep every revision reviewable.

Last updated January 2026

Why this works

Because ScreenJSON is text, git diff just works. Because every element carries a UUID, changes to one scene don’t cascade into spurious diffs on unrelated scenes. Because text is language-keyed, you can even see translation changes as additions to a language map rather than replacements.

A reasonable repo layout

screenplays/
  my-script/
    manuscript.fdx            # source in your writing tool
    screenplay.json           # canonical ScreenJSON
    revisions/
      2026-01-10-blue.json
      2026-01-15-pink.json
    notes/                    # optional prose markdown

A pre-commit hook

Keep the canonical screenplay.json in sync with the source .fdx:

#!/usr/bin/env bash
# .git/hooks/pre-commit
set -e
for fdx in screenplays/**/manuscript.fdx; do
  dir="$(dirname "$fdx")"
  docker run --rm -v "$PWD/$dir:/data" screenjson/cli \
    convert -i /data/manuscript.fdx -o /data/screenplay.json
  git add "$dir/screenplay.json"
done

Pretty-printing for diffs

Commit the ScreenJSON pretty-printed — it diffs cleanly line-by-line:

screenjson convert -i manuscript.fdx | jq . > screenplay.json

Keeping UUIDs stable

Use a converter that honours existing UUIDs. Both screenjson-cli and screenjson-export will, by default, reuse an existing screenplay.json if one is present next to the source to keep UUIDs stable across regenerations.

Git attributes

Mark ScreenJSON files for text diffing:

# .gitattributes
*.json diff

Automatic commits

screenjson-server can give each script its own Git repository and commit after every burst of edits, pushing to GitHub, GitLab or Bitbucket, so changes made through the API or by AI agents land in history without anyone running git.

Next