What's inside a .sboardx
Rename it to .zip or run unzip and you get this:
project.json format version, name, frame + resolution, fps
sequence.json panel order, scenes, camera keyframes
panels/<id>/panel.json code, shot, duration, note, dialogue
panels/<id>/layers.json layer stack (bottom to top), image layers, blur
panels/<id>/art/<layer>.svg the art: one SVG per layer
audio/clips.json + audio/* clips, tracks, embedded audio files
images/* embedded images for image layers
Every entry is stored uncompressed, so a reader is a few dozen lines in any language and nothing is hidden behind a proprietary codec.
Open it anywhere
- In a browser. The web reader plays a storyboard back with layers, camera moves and audio. It's a single HTML file; nothing is uploaded.
- In a vector editor. Each layer's SVG opens in Illustrator, Inkscape, Figma or Affinity as ordinary filled paths.
- In Toon Boom Storyboard Pro. The import/export scripts bring boards into Storyboard Pro as true vector layers, with timing, dialogue, audio tracks and scene cameras, and take edited boards back to Upshot. See the Toon Boom plugin guide.
- From a script. Python's
zipfileandjsonare all you need; see below.
The SVG art
Each layer is one SVG in world units: the frame is 540 units tall, centred
on the origin, and the viewBox is the frame, so a panel of any resolution
uses the same coordinates. Strokes are closed, filled outlines (M C Z
paths), never centrelines, so they render identically everywhere. Layer
opacity, blend mode and blur are baked into the group's CSS, so a browser
shows the layer correctly on its own. A handful of sboardx: attributes let
Upshot re-import its own files bit-exactly; every other reader ignores them.
The JSON manifest
| Entry | Holds |
|---|---|
project.json |
Format version, name, episode, frame size, render resolution, fps |
sequence.json |
Panel order; scenes with their camera keyframes (t, zoom, centre, rotation) |
panel.json |
Code, shot type, duration in seconds, notes, dialogue |
layers.json |
Per layer: name, opacity, blend, visibility, lock, blur, optional image placement |
audio/clips.json |
Clips with start, duration, trim, gain, file; tracks with mute state |
The full schema, every key and default, is in SPEC.md.
Scripting example
List every panel with its dialogue:
import json, sys, zipfile
z = zipfile.ZipFile(sys.argv[1])
seq = json.loads(z.read("sequence.json"))
for scene in seq["scenes"]:
print(scene["name"])
for pid in scene["panels"]:
p = json.loads(z.read(f"panels/{pid}/panel.json"))
print(f" {p['code']:<8} {p['dur']:>5.2f}s {p.get('dialogue', '')}")
More in the repo's examples: extract all layer SVGs, validate an archive.
Versioning and extending the format
The current version is 1.0. Readers ignore keys they don't know, so new
optional keys don't change the version; app-specific data lives under
vendor keys (x-upshot) and never leaks into the public schema. Proposals
are pull requests against the spec on GitHub.
No lock-in, by design
The format, the reader and the Toon Boom scripts are Apache-2.0 at github.com/Upshot-Storyboard/sboardx. An exported storyboard is readable, editable and convertible with free tools today, and will stay that way whether or not Upshot is installed.