.trellis
ZIP-based archive format with a plugin-keyed JSON document and optional binary payloads for embedded image assets.
Contents
1. Container layout
ZIP archive with a .trellis suffix. Most of the document lives in JSON.
Binary files appear only when the document embeds image assets or another plugin emits non-JSON payloads.
project.trellis
├── manifest.json
├── document.json
└── plugins/
└── VECTOR_DOCUMENT@1/
└── image-assets/<assetId>.bin If a file has no embedded image assets, it can be entirely JSON-backed inside the ZIP.
2. manifest.json
manifest.json records the container version and the set of serialized plugin entries expected in
document.json.
{
"version": "1.0.0",
"plugins": [
{ "name": "VECTOR_DOCUMENT@1", "version": "1.0.0" },
{ "name": "VECTOR_LAYER_SYSTEM@1", "version": "1.0.0" },
{ "name": "VECTOR_VIEWPORT_STATE@1", "version": "1.0.0" }
],
"layerCount": 4,
"createdAt": "2026-03-15T00:00:00.000Z",
"modifiedAt": "2026-03-15T00:00:00.000Z"
} version
The current container version written by the shared serializer.
plugins
Array of plugin names and versions. Every listed plugin must appear in document.json with a
matching entry.
layerCount
High-level document metadata. It does not replace the canonical vector layer-system payload.
createdAt and modifiedAt
Shared document timestamps.
3. document.json
document.json is keyed by plugin token ID. The file does not flatten everything into one object
schema; each entry owns its own payload.
{
"VECTOR_LAYER_SYSTEM@1": { ... },
"VECTOR_DOCUMENT@1": { ... },
"VECTOR_VIEWPORT_STATE@1": { ... }
} Entry envelope
{
"pluginName": "VECTOR_DOCUMENT@1",
"version": "1.0.0",
"data": {
"objects": [ ... ],
"rootOrder": [ ... ],
"selection": [ ... ],
"artboards": [ ... ],
"assets": [ ... ]
}
}
Each entry must contain a matching pluginName, a version, and a
data field. Manifest/document mismatches, missing payloads, or bad entry keys fail preflight.
That envelope is part of the format. A reverse-engineering parser should not jump directly to
data; it should first resolve the plugin name and version carried by the envelope itself.
4. Document entry families
A .trellis archive is a set of plugin-owned entries. In practice those entries fall into a few
predictable families.
Core document entries
VECTOR_DOCUMENT@1 and VECTOR_LAYER_SYSTEM@1 carry the scene graph, artboards,
embedded asset metadata, and vector layer definitions.
Editor-state entries
Entries such as VECTOR_VIEWPORT_STATE@1, VECTOR_STYLE_STATE@1,
VECTOR_ACTIVE_TOOL_STATE@1, VECTOR_TEXT_DEFAULTS@1,
VECTOR_GRID_STATE@1, and VECTOR_SNAPPING_STATE@1 store additional
editor state.
Binary-backed entries
VECTOR_DOCUMENT@1 may reference embedded image binaries under
plugins/VECTOR_DOCUMENT@1/image-assets/.... Other plugin entries may also own binaries.
Unknown entries
The envelope format allows additional plugin entries beyond the ones documented here. A parser should not assume the set is permanently closed.
5. VECTOR_DOCUMENT@1
VECTOR_DOCUMENT@1 is the scene-graph core of the file. It stores the object map,
ordering, artboards, selection state, counters, and embedded image asset metadata.
{
"objects": [
{
"id": "obj_1",
"type": "path",
"name": "Path 1",
"transform": { ... },
"style": { ... },
"visible": true,
"locked": false,
"parentId": null,
"layerId": "layer_1",
"authoring": { ... },
"commands": [ ... ]
}
],
"rootOrder": ["obj_1"],
"selection": [],
"lastSelectedId": null,
"artboards": [ ... ],
"activeArtboardId": "artboard_1",
"artboardCounter": 1,
"objectCounter": 24,
"assets": [ ... ]
} objects
Array of serialized vector objects. Current object types are path, group,
clipGroup, text, and image.
rootOrder, selection, lastSelectedId
Document ordering and current selection state.
artboards and activeArtboardId
Document artboards in order plus the currently active artboard.
artboardWidth and artboardHeight
Compatibility dimensions projected from the active artboard.
artboardCounter and objectCounter
Counters stored as document metadata.
assets
Embedded image metadata including MIME type, dimensions, byte length, checksum, original filename, and a binary filename for the matching asset payload.
This is the main entry. Parsing it is enough to reconstruct the document's objects, hierarchy, artboards, and embedded-asset references. The remaining editor-state entries are not required.
6. Artboards, ordering, and counters
In addition to the object array, the file stores document-wide ordering and artboard metadata directly in
VECTOR_DOCUMENT@1.
rootOrder
Back-to-front root object order for the scene graph.
selection and lastSelectedId
Current selected object IDs and the most recently selected object.
artboards
Array of artboard records with id, name, x, y,
width, and height.
activeArtboardId
Active artboard identifier.
artboardWidth and artboardHeight
Compatibility dimensions projected from the active artboard.
artboardCounter and objectCounter
Counters stored as document metadata.
rootOrder is the root-level z-order only. Child ordering for grouped content lives on each
group or clip-group object’s children array. A parser needs both to reconstruct draw order.
7. Object payloads
Every serialized object carries a shared base shape: id, type, name,
transform, style, visible, locked,
parentId, and layerId. Each object type then adds its own payload.
Path objects
Store both canonical path geometry and compiled path commands.
Group objects
Store ordered child IDs and act as structural containers in the scene graph.
Clip groups
Extend group payloads with a required clipperId. The clipper must resolve to a child path
object.
Text objects
Store UTF-16 content, layoutMode, paragraph spans, style runs, optional area-text frame,
story links, text-on-path metadata, and overset state.
Image objects
Store an assetId plus intrinsic dimensions. The actual bytes live in the matching embedded
asset binary.
Hierarchy
Objects can live at root level or under a parent group. The file preserves this graph explicitly rather than flattening it away.
Layer membership
Every object carries a layerId. The file depends on the separate vector layer-system payload
to make those IDs meaningful.
Bounds
Some serialized object kinds also include cached bounds.
Shared primitives
Every object relies on the same transform and style families. Current transform matrices are six-number 2D affine matrices in column-major form:
{
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
} Current vector styles are serialized as fill/stroke objects with explicit paint kinds and rules:
{
"fill": {
"paint": {
"kind": "solid",
"color": { "r": 30, "g": 30, "b": 30, "a": 1 }
},
"fillRule": "nonZero"
},
"stroke": {
"paint": {
"kind": "solid",
"color": { "r": 255, "g": 120, "b": 0, "a": 1 }
},
"width": 2,
"cap": "round",
"join": "round",
"miterLimit": 4,
"transformPolicy": "scaleWithObject"
}
} Path shape
{
"id": "obj_path",
"type": "path",
"name": "Path 1",
"transform": { ... },
"style": { ... },
"visible": true,
"locked": false,
"parentId": null,
"layerId": "layer_1",
"authoring": { ... },
"commands": [ ... ]
}
Path objects preserve both authoring and commands. The authoring
payload is the richer geometric form; commands are a second geometric representation.
commands are arrays of discriminated records. Current command types are
moveTo, lineTo, quadTo, cubicTo,
closeCubic, and close. Paths can therefore be reconstructed even if a consumer
ignores the richer authoring payload.
Group shape
{
"id": "obj_group",
"type": "group",
"name": "Group 1",
"transform": { ... },
"style": { ... },
"visible": true,
"locked": false,
"parentId": null,
"layerId": "layer_1",
"children": ["obj_path", "obj_text"]
}
Group objects are structural containers. Their children array preserves child ordering inside the
group.
Clip group shape
{
"id": "obj_clip_group",
"type": "clipGroup",
"name": "Clip Group 1",
"transform": { ... },
"style": { ... },
"visible": true,
"locked": false,
"parentId": null,
"layerId": "layer_1",
"children": ["obj_shape", "obj_clipper"],
"clipperId": "obj_clipper"
}
Clip groups extend the group shape with a required clipperId. The referenced clipper must resolve
to a path object.
Text shape
{
"id": "obj_text",
"type": "text",
"name": "Text 1",
"transform": { ... },
"style": { ... },
"bounds": { ... },
"visible": true,
"locked": false,
"parentId": null,
"layerId": "layer_1",
"content": "Hello",
"layoutMode": "area",
"paragraphSpans": [ ... ],
"styleRuns": [ ... ],
"frame": { "width": 320, "height": 180 },
"storyId": null,
"previousTextId": null,
"nextTextId": null,
"pathLayout": null,
"overset": false
} Text objects carry the styled text model directly: text content, paragraph spans, style runs, frame information, threading metadata, text-on-path metadata, and overset state.
Image shape
{
"id": "obj_image",
"type": "image",
"name": "Image 1",
"transform": { ... },
"style": { ... },
"bounds": { ... },
"visible": true,
"locked": false,
"parentId": null,
"layerId": "layer_1",
"assetId": "asset_1",
"intrinsicWidth": 1024,
"intrinsicHeight": 1024
}
Image objects carry an assetId and intrinsic dimensions. The binary bytes are resolved
separately through the embedded asset table.
For reverse engineering, the practical discriminator is:
path owns geometry, group owns ordered children, clipGroup adds a
required clipper reference, text owns styled text payload, and image owns an
embedded-asset reference.
8. Text model and threaded flows
Text ranges
Text objects preserve paragraph spans and style runs, so the file stores structured styled text rather than only plain text.
Point vs area text
Point text must not define a frame. Area text must define one.
Threaded text
Story metadata uses storyId, previousTextId, and nextTextId. The
current loader checks reciprocal links and rejects invalid text threading.
Text on path
Optional pathLayout metadata stores path target ID, offset, direction, and related layout
controls. The path target must resolve to a real path object.
Overset state
Text objects persist an overset flag.
Image references
Image objects reference image assets by ID. The object payload does not inline the binary asset bytes into the text or image object record itself.
The file stores text content as a UTF-16 JavaScript string, paragraph spans as paragraph-level range/style records, and style runs as character-range style records. For file compatibility, those ranges and links need to remain internally coherent.
9. VECTOR_LAYER_SYSTEM@1
The vector layer system is serialized separately from the scene graph. Objects carry layerId
references, and this payload defines what those IDs mean.
VECTOR_LAYER_SYSTEM@1 serializes the current vector layer records, the bottom-to-top layer order,
the active layer ID, and the layer counter.
{
"layers": [
{
"id": "layer_1",
"name": "Layer 1",
"visible": true,
"locked": false,
"opacity": 1,
"blendMode": "normal"
}
],
"layerOrder": ["layer_1"],
"activeLayerId": "layer_1",
"layerCounter": 1
}
Each serialized vector layer currently carries id, name, visible,
locked, opacity, and blendMode.
layerOrder is bottom-to-top. activeLayerId must resolve to a layer in that array.
layerCounter is serialized as document metadata.
10. Optional editor-state entries
Files may also include editor-state entries beyond the scene graph and layer system.
VECTOR_VIEWPORT_STATE@1
Stores pan, zoom, and rotation.
VECTOR_STYLE_STATE@1
Stores fill and stroke state.
VECTOR_ACTIVE_TOOL_STATE@1
Stores the current primary tool plus shape subtype, even-scaling, center-draw, polygon, and spiral settings.
VECTOR_TEXT_DEFAULTS@1
Stores default text settings for newly created text objects.
VECTOR_GRID_STATE@1
Stores grid visibility, spacing, subdivisions, major-line cadence, color, and opacity values.
VECTOR_SNAPPING_STATE@1
Stores snapping enablement, individual snapping toggles, and the current tolerance in pixels.
VECTOR_COLORWAY_STATE@1
Stores colorway enablement plus the current list of color anchors.
VECTOR_PATTERN_MODE_STATE@1 and VECTOR_NODE_GRAPH_STATE@1
Store pattern-mode display settings and the serialized node-graph workspace.
Representative small-payload shapes
{
"VECTOR_VIEWPORT_STATE@1": {
"pluginName": "VECTOR_VIEWPORT_STATE@1",
"version": "1.0.0",
"data": { "panX": 0, "panY": 0, "zoom": 1, "rotation": 0 }
},
"VECTOR_STYLE_STATE@1": {
"pluginName": "VECTOR_STYLE_STATE@1",
"version": "1.0.0",
"data": {
"fill": { ... },
"stroke": { ... }
}
}
}
Other payload families are compact JSON payloads:
VECTOR_ACTIVE_TOOL_STATE@1 writes the current tool plus shape/polygon/spiral controls,
VECTOR_GRID_STATE@1 writes visibility plus spacing/subdivision/color settings,
VECTOR_SNAPPING_STATE@1 writes snapping toggles plus tolerance,
VECTOR_COLORWAY_STATE@1 writes enabled plus anchor records, and
VECTOR_PATTERN_MODE_STATE@1 writes visual toggles and colors for pattern-mode overlays.
11. Embedded assets and binary routing
Embedded image bytes are stored as plugin-owned binaries under
plugins/VECTOR_DOCUMENT@1/image-assets/<assetId>.bin.
Binary filename
Current files use image-assets/<assetId>.bin inside the
VECTOR_DOCUMENT@1 plugin directory.
Metadata first
Asset metadata and binary payloads are paired through id and
binaryFilename.
Required pairings
Missing asset metadata, missing asset binaries, or image objects that reference unknown assets are all treated as invalid.
Unused asset cleanup
Asset tables may include entries that are not referenced by any object.
Asset metadata shape
{
"id": "asset_1",
"mimeType": "image/png",
"width": 1024,
"height": 1024,
"byteLength": 88421,
"sha256": "7f...ab",
"filename": "example.png",
"binaryFilename": "image-assets/asset_1.bin"
}
The binary path is plugin-relative. Inside the ZIP, files place that binary at
plugins/VECTOR_DOCUMENT@1/image-assets/<assetId>.bin. Image objects then reference the
metadata row through assetId.
12. Consistency rules
A valid .trellis file is more than syntactically valid JSON. The scene graph, layer data, and
embedded asset references need to agree with one another.
Artboards
Artboards must have valid IDs, names, dimensions, and a resolvable active artboard.
Paths
Path objects must carry either canonical geometry data or commands.
Groups and clip groups
Groups must declare children. Clip groups must also declare a valid clipperId.
Text
Text payloads are checked for content, frame/layout consistency, reciprocal story links, and valid text-on-path targets.
Images and assets
Image objects must reference existing assets, and asset metadata must have valid MIME type, dimensions, and checksum fields.
Hierarchy topology
Objects should appear in ordering arrays exactly where their parent and root relationships say they do.
In practical terms, the important checks are duplicate IDs, missing geometry, missing children,
missing clipperId, invalid text-link references, image objects that point at missing assets, and
order arrays that contradict parent links.
13. Compatibility and versioning
- Files use the
.trellissuffix. - The loader also accepts
.zipcontainers with the same internal layout. - The shared manifest currently writes container version
1.0.0. - Legacy files with empty plugin version strings are still accepted, but load with a warning.
- The loader does not currently branch into separate historical codepaths by document version.
- The format contract is the contents of the ZIP, not just the filename suffix.