Skip to main content

FilmGraph

A structured data format for film analysis.

PyPI License: MIT Python 3.11+

Install · Quick Start · Schema · Importers · Exporters · Docs


Why FilmGraph?

The film industry relies on dozens of incompatible formats — CCSLs in Word documents, Dialogbücher, SRT subtitles, EDLs, XML timelines, proprietary pipeline outputs. Building tools that work across these formats means spending more time parsing than analyzing.

FilmGraph is a single JSON schema that captures shots, scenes, dialogue, cinematography, characters, locations, and narrative events. Zero dependencies beyond Pydantic. One format for your entire pipeline.

{
  "schema_version": "filmgraph/v1",
  "meta": { "title": "Lost Killers", "duration": 5731.2 },
  "scenes": [{
    "id": 1, "title": "Opening", "start_time": 0, "end_time": 142.5,
    "shots": [{
      "id": "sh-001", "order": 1, "start_time": 0, "end_time": 8.3,
      "cinematography": { "shot_size": "WS", "camera_movement": "static" },
      "visual": { "description": "Wide establishing shot of Berlin skyline at dusk" },
      "audio": { "dialogue": [{ "speaker": "narrator", "text": "Berlin, 1998.", "start_time": 2.1, "end_time": 4.5 }] }
    }]
  }]
}

Install

pip install filmgraph

With importers for .docx files (CCSL, Dialogbuch, AD scripts):

pip install filmgraph[docx]

With OpenTimelineIO support (EDL, FCP XML, AAF):

pip install filmgraph[otio]

Quick Start

from pathlib import Path
from filmgraph import FilmGraph, Scene, Shot, ShotSize, CameraMovement

# Load
fg = FilmGraph.from_json(Path("movie.filmgraph.json").read_text())

# Traverse
for scene in fg.scenes:
    print(f"{scene.title} ({scene.shot_count} shots)")
    for shot in scene.shots:
        print(f"  {shot.cinematography.shot_size}  {shot.visual.description}")

# Save
Path("movie.filmgraph.json").write_text(fg.to_json(indent=2))

Schema

FilmGraph
├── meta: FilmMeta            # title, duration, resolution, data sources
├── entities: Entities         # characters, locations (referenced by ID)
├── scenes: [Scene]            # narrative segments
│   ├── shots: [Shot]          # atomic visual units (cut to cut)
│   │   ├── cinematography     # shot_size, camera_movement, camera_angle
│   │   ├── visual             # description, colors, lighting
│   │   ├── audio              # dialogue lines, music cues, SFX
│   │   └── editorial          # transitions, confidence, thumbnail
│   └── dialogue: [DialogueLine]
└── events: [Event]            # plot turning points

Controlled Vocabularies

Every categorical field uses a controlled enum with an OTHER fallback for extensibility.

Enum Values
ShotSize ECU · BCU · CU · MCU · MS · MLS · MWS · WS · EWS · INSERT · AERIAL · OTHER
ShotType single · two-shot · group · over-the-shoulder · point-of-view · reaction · establishing · insert · cutaway · master · other
CameraMovement static · pan · tilt · dolly · truck · tracking · handheld · crane · drone · zoom · whip-pan · push-in · pull-out · arc · rack-focus · steadicam · other
CameraAngle eye-level · high-angle · low-angle · birds-eye · worms-eye · dutch-angle · overhead · ground-level · other
Transition cut · dissolve · fade-in · fade-out · fade-to-black · wipe · match-cut · jump-cut · j-cut · l-cut · smash-cut · other

Importers

Convert industry formats into FilmGraph with a single function call:

from filmgraph.importers.ccsl import ccsl_to_filmgraph
from filmgraph.importers.srt import srt_to_filmgraph

fg = ccsl_to_filmgraph("FTR3_BloodyTennis.docx")
fg = srt_to_filmgraph("movie.srt", title="My Film")
Importer Function Input Extra
CCSL ccsl_to_filmgraph() .docx shot lists pip install filmgraph[docx]
Dialogbuch dialogbuch_to_filmgraph() German dubbing scripts .docx pip install filmgraph[docx]
AD Script ad_to_filmgraph() Audio description scripts .docx pip install filmgraph[docx]
SRT/VTT srt_to_filmgraph() Subtitle files —
Pipeline timeline_to_filmgraph() Pipeline JSON output —
OTIO otio_to_filmgraph() EDL, FCP XML, AAF pip install filmgraph[otio]

Each importer also works as a CLI:

python -m filmgraph.importers.ccsl input.docx -o output.filmgraph.json
python -m filmgraph.importers.srt movie.srt -o subs.filmgraph.json

Exporters

Go the other direction — render a FilmGraph as the industry format of your choice:

from filmgraph.exporters.srt import filmgraph_to_srt
from filmgraph.exporters.ccsl import filmgraph_to_ccsl

Path("movie.srt").write_text(filmgraph_to_srt(fg))
filmgraph_to_ccsl(fg, "movie_ccsl.docx")
Exporter Function Output Extra
SRT/VTT filmgraph_to_srt() / filmgraph_to_vtt() Subtitles —
CCSL filmgraph_to_ccsl() .docx shot list pip install filmgraph[docx]
Dialogbuch filmgraph_to_dialogbuch() German dubbing script .docx pip install filmgraph[docx]
AD Script filmgraph_to_ad() Audio description .docx pip install filmgraph[docx]
Pipeline filmgraph_to_timeline() Pipeline JSON —
Ground Truth filmgraph_to_ground_truth() Bloody Tennis-style JSON fixture —
OTIO filmgraph_to_otio() EDL, FCP XML, AAF, .otio pip install filmgraph[otio]
CSV filmgraph_to_csv() Flat shot-list CSV —
Markdown filmgraph_to_markdown() Human-readable report —

Every exporter also works as a CLI:

python -m filmgraph.exporters.srt movie.filmgraph.json -o movie.srt
python -m filmgraph.exporters.ccsl movie.filmgraph.json -o movie_ccsl.docx
python -m filmgraph.exporters.otio_export movie.filmgraph.json -o edit.edl
python -m filmgraph.exporters.markdown movie.filmgraph.json -o report.md

Build a FilmGraph Programmatically

from filmgraph import *

fg = FilmGraph(
    meta=FilmMeta(title="My Film", duration=5400.0),
    entities=Entities(characters=[
        Character(id="alice", name="Alice"),
        Character(id="bob", name="Bob"),
    ]),
    scenes=[
        Scene(
            id=1,
            title="Opening",
            summary="Alice meets Bob",
            start_time=0,
            end_time=120,
            shots=[
                Shot(
                    id="sh-001",
                    order=1,
                    start_time=0,
                    end_time=8.5,
                    cinematography=Cinematography(
                        shot_size=ShotSize.WS,
                        camera_movement=CameraMovement.STATIC,
                    ),
                    visual=Visual(description="Wide shot of a café"),
                    audio=Audio(dialogue=[
                        DialogueLine(
                            speaker="alice",
                            text="Is this seat taken?",
                            start_time=3.0,
                            end_time=5.2,
                        ),
                    ]),
                ),
            ],
        ),
    ],
)

print(fg.to_json(indent=2))

JSON Schema

Generate the full JSON Schema for validation or code generation:

import json
from filmgraph import FilmGraph

schema = FilmGraph.model_json_schema()
print(json.dumps(schema, indent=2))

Contributing

Contributions welcome. Please open an issue first to discuss what you'd like to change.

License

MIT · Made by Chapter41

Metadata

Release files for filmgraph 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for filmgraph 0.1.2
File Size Uploaded
filmgraph-0.1.2.tar.gz 85.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for filmgraph 0.1.2
File Interpreter ABI Platform
filmgraph-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 135.5 kB

Release files / filmgraph-0.1.2.tar.gz

Download URL filmgraph-0.1.2.tar.gz
Size 85.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6fd1cc3402562ddef478559ab565a290903bc6fcefee1b860290450e1c41282b
BLAKE2b-256 checksum
How to use checksums
eb50532c7621349ac01f4a65b9303b96ee7d54bb998e25369ab7b8fa5ce96fca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

Release files / filmgraph-0.1.2-py3-none-any.whl

Download URL filmgraph-0.1.2-py3-none-any.whl
Size 49.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
74991bc4820467e39a9a534312e2e5c636e5bbb1da5e7519a1a6420083a33c67
BLAKE2b-256 checksum
How to use checksums
c99562cd2a044d9713efd9990e8e95630063cf12da412360b4e96140dff3636f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page