A minimal, structured data format for film analysis
Project description
FilmGraph
A structured data format for film analysis.
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file filmgraph-0.1.2.tar.gz.
File metadata
- Download URL: filmgraph-0.1.2.tar.gz
- Upload date:
- Size: 85.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6fd1cc3402562ddef478559ab565a290903bc6fcefee1b860290450e1c41282b
|
|
| MD5 |
184f1c66e74912232e3550f81a174de7
|
|
| BLAKE2b-256 |
eb50532c7621349ac01f4a65b9303b96ee7d54bb998e25369ab7b8fa5ce96fca
|
Provenance
The following attestation bundles were made for filmgraph-0.1.2.tar.gz:
Publisher:
publish.yml on Chapter41/filmgraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
filmgraph-0.1.2.tar.gz -
Subject digest:
6fd1cc3402562ddef478559ab565a290903bc6fcefee1b860290450e1c41282b - Sigstore transparency entry: 1396642424
- Sigstore integration time:
-
Permalink:
Chapter41/filmgraph@65f27abbbea1905503a97c903691069886de3a82 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/Chapter41
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@65f27abbbea1905503a97c903691069886de3a82 -
Trigger Event:
release
-
Statement type:
File details
Details for the file filmgraph-0.1.2-py3-none-any.whl.
File metadata
- Download URL: filmgraph-0.1.2-py3-none-any.whl
- Upload date:
- Size: 49.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74991bc4820467e39a9a534312e2e5c636e5bbb1da5e7519a1a6420083a33c67
|
|
| MD5 |
a93c58d4f30e03619179c348a2cc9db1
|
|
| BLAKE2b-256 |
c99562cd2a044d9713efd9990e8e95630063cf12da412360b4e96140dff3636f
|
Provenance
The following attestation bundles were made for filmgraph-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on Chapter41/filmgraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
filmgraph-0.1.2-py3-none-any.whl -
Subject digest:
74991bc4820467e39a9a534312e2e5c636e5bbb1da5e7519a1a6420083a33c67 - Sigstore transparency entry: 1396642458
- Sigstore integration time:
-
Permalink:
Chapter41/filmgraph@65f27abbbea1905503a97c903691069886de3a82 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/Chapter41
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@65f27abbbea1905503a97c903691069886de3a82 -
Trigger Event:
release
-
Statement type: