Browse docs
On this page

DEVELOPMENT BUILD · API VOXELITE.V1

The .voxl format

One project. One readable JSON file.

.voxl stores a complete portable project as UTF-8 JSON. This reference follows voxelite-format and the validated core model in this development build. Media type: application/vnd.voxelite.project+json. Current writer version: {"major": 1, "minor": 0}.

Top-level structure

FieldContract
formatRequired literal "voxelite".
versionRequired major and minor unsigned 16-bit integers. Major must be 1. A newer minor is preserved.
required_featuresRequired array of strings. Only an empty array is currently supported.
documentRequired id, name, bounds.
paletteRequired slots and order.
layersRequired array, bottom to top; 1–64 entries.
commentsOptional thread array, omitted when empty.
versionsOptional named snapshot array, omitted when empty.
lineageOptional source document and version UUIDs for an independent branch.
viewOptional portable view metadata, excluded from the project semantic hash.

Coordinates and layers

Coordinates are integer [x, y, z] triples in a right-handed, Y-up space. A cell at [x,y,z] occupies a unit cube. bounds.min is inclusive and bounds.max exclusive. Each extent must be 1–256; cell coordinates must lie in [-32768, 32768). The exclusive maximum may equal 32768.

Each layer has id, name, visible, locked, and voxels. A voxel row is [x, y, z, slot]. Omit air entirely: slot zero is invalid on disk. All rows must lie in the document bounds and reference existing palette slots. Duplicate coordinates within a layer reject; the same coordinate in different layers is valid. The highest visible occupied layer wins the composite. Hidden geometry is retained; lock state does not change rendering.

Palette identity

A slot has index (1–256), rgba (four bytes, alpha exactly 255), and an optional name. There must be 1–256 slots, with unique indices. order is a full permutation of those indices and controls display order independently of identity. No translucent voxels are supported.

Canonical bytes and hashes

The project semantic hash differs from a named version's content_hash, which hashes the canonical core snapshot serialization. Use the Rust API to compute these hashes; do not substitute a generic pretty-printed JSON hash.

Comments and named versions

A comment contains id, anchor, optional layer, resolved, and ordered messages. Anchors are {"kind":"voxel","at":[x,y,z]} or {"kind":"region","min":[x,y,z],"max":[x,y,z]}. Each message has id, origin (human or agent), plain-text text, and optional public tool ID. Hidden/orphaned state is derived, not stored; an anchor survives deleted geometry.

A named version contains id, name, optional parent, origin, content_hash, and a nonrecursive snapshot. Snapshots contain name, bounds, palette, layers, and optional comments. Hashes must match. Parents must exist in the same library, and cycles reject. Session IDs, revision counters, undo/redo entries and retry receipts are not serialized by the writer.

Parser and resource limits

ResourceLimit
Encoded file128 MiB
Live layer-voxels / allocated chunks1,048,576 / 8,192; overlapping layers count separately
Decoded voxels across live and version content4,194,304
Metadata excluding voxel arrays8 MiB total; 4 MiB top-level comments, 4 MiB other metadata
JSON nesting / optional metadata nesting32 / 16
Comment threads / messages1,024 / 10,000 per snapshot; each message 1–8,192 UTF-8 bytes; 4 MiB comment budget
Named versions64; aggregate canonical snapshot bytes ≤64 MiB

Duplicate object keys reject at every level. Parsing validates all layers and snapshots, including hidden content. Unknown major versions and nonempty required-feature lists fail without installing the document. Limits may reject a file before any model becomes available.

Forward compatibility

Bounded unknown optional fields are preserved as inert data and merged by stable IDs or palette indices, not array position. Optional extension values accept strings, booleans, null, signed 64-bit integers, arrays and objects within depth limits. They are never interpreted as executable code or remote resources. Known fields always come from current validated content.

A complete example

Download a valid one-voxel project. The site crate tests this fixture against the actual format reader and verifies canonical byte equality.

{
  "document": {
    "bounds": {"max": [16, 16, 16], "min": [0, 0, 0]},
    "id": "00000000-0000-4000-8000-000000000001",
    "name": "One voxel"
  },
  "format": "voxelite",
  "layers": [{
    "id": "00000000-0000-4000-8000-000000000002",
    "locked": false, "name": "Base", "visible": true,
    "voxels": [[0, 0, 0, 1]]
  }],
  "palette": {
    "order": [1],
    "slots": [{"index": 1, "name": "clay", "rgba": [180, 140, 100, 255]}]
  },
  "required_features": [],
  "version": {"major": 1, "minor": 0}
}

This displayed example is compacted for readability. The downloadable file uses canonical whitespace. Open it in the editor or with voxelite_document_open to validate it; the app preserves the existing document if an open fails.