What it does
A ModelSpec is a JSON object of parts, materials and clips. Each part names a shape, a parent, a pivot position and
rotation in that parent's frame, the size of the box it fills in world units, and a material. An offset moves the mesh
from its pivot, so a leg swings from the hip, and mirror builds a twin across x, children and all.
game.models.define(name, spec) names it, and game.spawn({ model: name }) builds it on the spawned object, which
becomes its root: move it, tag it, destroy it, and root.play('walk') plays a clip.
The built model is ordinary objects, one per part, each riding its parent. You can attach a sword to parts['hand-r'],
read a wheel's world position, recolour one mesh, and under collision-3d the model collides as the box its parts fill
at rest. Clips are tracks of keys per part: moves and turns as changes from the rest pose, and scales as multipliers, so
editing the rest pose never breaks an animation. pose(clip, time) holds one moment, for a scrubber or a thumbnail.
Smooth forms take models past blocks. A part can be a lathe, an extrusion, a tube, a sweep along a path (a banana, a
candy cane, a pretzel), a hollow vessel with its drink filled to a level, a leaf, a scatter of copies over its parent
(seeds, kernels, a bunch of grapes), a coat over its parent (icing, glaze, chocolate) with drips, or a numbered die.
Parts can be sliced by up to three planes, and child parts marked as tools carve holes out of their parent, each cut
face in its own material. Materials carry patterns painted by the renderer, so a rind is striped and a donut sprinkled
without a part per stripe, and opacity gives see-through glass, drinks and ice.
Features
- Models as JSON — parts, materials and clips, tidied into a valid spec by
game.models.clean, which never throws. - A part hierarchy — pivots, offsets, mirrored twins, and handles for every part's pivot and mesh.
- Animation clips — per-part move, turn and scale tracks with easing, looping or one-shot, at any speed.
- Smooth forms — lathe, extrude, tube, sweep, vessel, leaf, scatter, coat and die, with deformers for bend, taper, twist, lobes, noise and squash.
- Slices and cuts — up to three cutting planes, and tool parts carved out of their parent.
- Fourteen patterns —
stripes,bands,swirl,rings,segments,checker,grid,dots,speckle,sprinkles,spotsandgrain, pluspipsandnumbersfor dice faces. - See-through materials — opacity from 0.05 to 1 for glass, drinks and ice.
- Surface checks —
modelContactsfinds floating parts and parts poking through a vessel's side. - Ordinary objects — models collide, cull, pick and attach like anything else, and batch across copies.
Good for
- Low-poly and toy-like 3D games with characters, vehicles and props built from primitives.
- Endless runners and crossing games with simple chunky characters and obstacles.
- Food, cooking and café games — fruit that slices, cakes with icing, glasses with drinks, cheese with holes.
- Board and dice games, with real numbered dice and pieces.
- Blockouts that can ship, where the placeholder art is good enough to keep.
- Generated content, where code or a tool writes model specs instead of an artist exporting files.
Make it yours
Everything is in the spec: the parts and their shapes, sizes, poses and materials; the forms and their settings; the patterns, opacity, roughness, metalness and glow of each material; and the clips. A spec is plain data, so one from an editor or a tool drops straight in. One spec serves many copies, scaled as a whole.
Two different uses: a walking robot built from rounded boxes and capsules, with mirrored arms and legs, a walk loop
and a jump one-shot, a laser attached to its hand; and a smoothie stand where a lathed glass holds a see-through
drink, a sliced kiwi sits on the rim and a striped straw is swept along a bent path.
A quick look
Build a model, play a clip and attach a sword to its hand:
import { hero } from './models/hero.js'; // a ModelSpec
const h = game.models.build(hero, { x: 0, y: 0, z: 0 });
h.play('walk');
game.attach.to(sword, h.parts['hand-r']!, { y: -0.3 });
game.models.define('hero', hero);
game.spawn({ id: 'hero-2', model: 'hero', x: 4, y: 0, z: 0 });
Works with
core-3d— includes this pack asgame.models.geometry-3d— the primitives and smooth forms every part is built from.render-3d— draws the materials, patterns and see-through parts.attach-3dandcollision-3d— attach things to parts, and collide models as boxes.model-files-3d— loads.glband.objfiles made by an artist, side by side with these.art-3d— lighter scene dressing with no hierarchy.
Good to know
- Parts are rigid: there is no skinning, and a joint is where two parts overlap. For a skinned character, load a file
with
model-files-3d. - One clip plays at a time per model, with no blending, and a one-shot clip holds its last pose with no event.
- Specs are clamped: 160 parts, 32 materials, 24 clips, 96 tracks a clip, 64 keys a track and 200 world units a side. Past that it is a scene; build it from several models.
- A model collides as its rest-pose box; clips move the parts, not the box.
- See-through parts sort as whole pieces and cast no shadow.






