Voxel cases
A voxel case produces a 3D asset. There are eight kinds in two families: the cube
kinds voxel-model and voxel-animation, which sculpt discrete opaque cells
with the voxel binaries; and the
meshed kinds mc-model/mc-animation, sn-model/sn-animation, and
dc-model/dc-animation, which extract a surface from a signed-distance field
with the meshing binaries.
Every voxel kind declares a [voxel] table in place of [canvas]. Every
animated kind adds a [model] table declaring the
required animations the model must
author. Everything on the
Manifests overview applies
unchanged.
A static case
Section titled “A static case”asset_kind = "voxel-model"
# The bounding volume the model sculpts into — the 3D analog of [canvas]. Cells# are OPAQUE #rrggbb (no alpha) and the volume starts EMPTY.[voxel]width = 32 # extent along x, in voxels (required, > 0)height = 32 # extent along y — up — in voxels (required, > 0)depth = 32 # extent along z, in voxels (required, > 0)background = "transparent" # PNG preview clear color only: transparent | a hex color
[tool]binary = "voxel" # the binary for the kind (required)preview = "model.png" # where the binary writes the wgpu preview PNG on `render`
[output]actions = "actions.json" # the ordered op recordA meshed static case is identical in shape. Only the binary differs, and the
[voxel] table frames the signed-distance field the surface is extracted from
rather than bounding sculpted cells:
asset_kind = "dc-model" # mc-model / sn-model are identical in shape
[voxel]width = 48height = 48depth = 48background = "transparent"
[tool]binary = "dc" # the meshing binary: mc | sn | dcpreview = "model.png"
[output]actions = "actions.json" # the extracted .glb geometry is emitted automatically by coreAn animated case
Section titled “An animated case”An animated kind authors, previews, and emits each part separately, so
[tool].preview and [output].actions must carry the {part} token. It also
declares the [model] table:
asset_kind = "voxel-animation" # or mc-animation / sn-animation / dc-animation
[voxel]width = 32height = 24depth = 32background = "transparent"
[tool]binary = "voxel-anim" # voxel-anim | mc-anim | sn-anim | dc-animpreview = "parts/{part}.png" # {part} REQUIRED for an animated kind
[output]actions = "parts/{part}.actions.json" # {part} REQUIRED for an animated kind
# The rig contract: the set of animations the model must author. A case declares NO# parts and NO joints — the model invents whatever skeleton the subject needs and is# scored on whether it worked out the right pieces and animated them.[model]
[[model.animation]]name = "walk" # stable, unique name a game plays this animation by (required)loop = true # loop (true, the default) or play once and hold the last poseauto_play = false # false (default) = a named playable a game triggers (walk, recoil); # true = plays continuously on its own (a decorative idle)The voxel table
Section titled “The voxel table”[voxel] fixes the bounding volume: width, height (up), and depth in
voxels, each greater than zero, plus a background used only as the preview
PNG’s clear color. The volume always starts empty, so the background never places
material. Voxel material is opaque #rrggbb.
For a cube case the volume bounds the sculpted cells. For a meshed case it frames
the signed-distance field the surface is extracted from. It is required for, and
only for, a voxel-family case, and replaces [canvas]. A voxel case declaring
[canvas], or a 2D case declaring [voxel], is rejected.
Tool and output paths
Section titled “Tool and output paths”[tool].binary is the binary for the kind: voxel or voxel-anim for the cube
kinds, and mc/sn/dc or mc-anim/sn-anim/dc-anim for the meshed kinds.
The binary a case names fixes the character of the output, a cube volume against
an mc low-poly, sn smooth, or dc sharp-edged surface.
Every voxel case’s [output] names its actions operation log. For a meshed
case core also emits the extracted geometry to a path it provides, mesh.glb for
a static kind and meshes/{part}.glb per part for an animated one, so the
geometry is not manifest-declared. An animated kind’s preview and actions
must carry {part}; a static kind’s must not.
The model table
Section titled “The model table”[model] is required for, and only for, an animated kind. It declares only the
case’s required [[model.animation]] entries. It declares no parts and no
joints: the rig’s parts, joints, pivots, and ranges are model-invented at run
time with the
rig subcommands.
Resolution validates that every [[model.animation]] has a unique name.
Each [[model.animation]] declares an animation by identity alone:
name— the stable, unique name a game plays the animation by.loop— loop, or play once and hold the last pose. Defaults totrue.auto_play— whether the animation plays continuously on its own, such as a radar spin, rather than being a named playable a game triggers. Defaults tofalse.
The case fixes no parts, joints, period, or keyframes. The model invents whatever
rig realizes the animation and authors the motion as F-curves, with per-keyframe
constant/linear/bezier interpolation plus ease-in, ease-out, and
ease-in-out presets, choosing the period itself. The produced animations are
carried in rig.json, exported to glTF for a game to play, and reconciled
against these declarations. A required animation that is missing, or that never
actually animates, is a contract gap.
A rig’s caller joints are the procedural interface a game drives per frame, such as turret yaw or gun pitch, exported as machine-readable metadata. Its animations are the baked clips a game plays. The review UI surfaces caller joints as controls, plays the produced animations, and poses the full rig in the 3D viewer. See Evaluation.
Per-variant volumes
Section titled “Per-variant volumes”For a voxel case the bounding volume is a variant axis. A variant may declare its
own [voxel] table, which replaces the case’s [voxel] for runs of that
variant. A variant with no [voxel] inherits the case’s volume. This is how a
case offers the same subject at several sizes: a base variant with no override,
plus half and double variants with their own volumes.
# variants/double.toml — the same subject in a doubled volume.slug = "double"name = "Double Size"
[voxel]width = 100 # the case's width, doubledheight = 40depth = 152background = "transparent"Resolution validates a variant’s [voxel] exactly as the case’s, and rejects a
[voxel] on a variant of any non-voxel case. The size a variant runs at flows to
everything that reads the volume: the tool config the binary is seeded with, the
volume the produced model is scored against, and the brief.
A voxel brief therefore should not hardcode its dimensions. Write its [[spec]]
as a Handlebars template with a .hbs source, so the seeded dest drops the
.hbs. The spec-template context
exposes the effective volume as {{voxel}}: {{voxel.width}},
{{voxel.height}}, and {{voxel.depth}} for the extents, and {{voxel.maxX}},
{{voxel.maxY}}, and {{voxel.maxZ}} for the highest index on each axis, so an
inclusive coordinate range reads `0`–`{{voxel.maxX}}`. The same context is
available in the case’s prompt.hbs.
Because coordinates are size-dependent, a voxel case’s brief and [[domain]]
text should describe the form itself rather than citing specific coordinates or
extents. A reviewer judges the shape.