Writing a .cel model
Shapes, colours, joints and motion, coarse to fine, held to a budget the compiler enforces.
A .cel script is a seeded family: every seed grows a different, equally good variant. It compiles to the same primitives, toon materials and ink as the hand-coded generators, streams line by line, enforces a complexity budget, rejects z-fighting at compile time, and carries motion states and cel effects.
The authoritative reference is generated from the compiler's own tables, so it can't drift: see the language reference for every kind, key, default, preset and palette name. This page is how to use them well.
Anatomy
asset <name> "Title" complexity=N [float] first line; name is snake_case and becomes the library slug let NAME = expr a gene: drawn once per seed <kind> <name> [xN] [flags] key=value … a part, or N copies fx [state:] <type> on=<part> key=… particles, after the parts and before the anims anim [state:] <part> <preset> [key=…] motion on a jointed part anim [state:] <part> <channel> <wave> key=…
One statement per line, // comments. Write coarse to fine: the asset line, then lets (proportions, then colours, then style picks), the biggest masses, secondary masses, features, small details, effects, anims.
Coordinates and values
Coordinates. Metres, Y up, the model faces +Z, and +X is the model's own left. The lowest point sits within 3 cm of y = 0 unless the asset line says float. Typical sizes: a critter 0.3 to 0.8 m, a person 1.6 m (chibi 0.8), a vehicle about 3 m long, a house 5 m, a boss 3 to 6 m.
Where a kind sits on its origin. lathe, cyl, cone and box stand on it and grow up +Y; ball, puff, torus and wheel are centred; limb hangs down from it (the joint is at the top); rod runs from it to to=; tube goes through pts=; slab is an x, y outline with thickness along z; face sits on its parent's surface.
Values. Numbers .3, vectors (x, y, z), lists [a b c], stations [t:value …], colours (a palette name, #rrggbb or a colour let). a..b is a seeded uniform draw; red:3|teal|cobalt is a seeded weighted pick. Arithmetic works on numbers, vectors and colours (H*.4, coat*.85 for darker, coat~ for a hue jitter). In a part line you also have i, n, t = i/(n-1), parent.i, parent.<key> and <part>.<key>. Logic: if=chance(.4), if=style=="horned", sel(k, a, b, c).
Placement. on=<part> rides the parent: its frame, its bone and its copies. at=(x, y, z) is in the parent's frame, or an anchor plus an offset: at=top+(0, .05, 0), at=end, at=front-(0, .1, 0). surf=(azimuth, elevation) sticks a part on the parent's surface (0 is the front, 90 its left, 180 the back; elevation 90 is straight up) with +Y out of the surface. decal lies flat on it, upright keeps the parent's axes, and lift= moves along the normal (negative sinks it in). rot=(x, y, z) is degrees, or use yaw=, tilt= and roll=.
Copies. x3 or x2..4. ring spreads copies round the parent's Y; row=(dx, dy, dz) lines them up centred on at=; chain=(dx, dy, dz) makes each copy ride the last (tails, garlands, necks). mirror adds a twin across the parent's X = 0: write the original at x > 0.
Kinds at a glance
| Kind | For | Key keys |
|---|---|---|
lathe | pots, bodies, columns, domes | h r prof=[t:r …] linear sq depth bands stripes panels open cap |
cyl | drums, posts, wheels on end | h r r2 round, plus the lathe family |
cone | roofs, ears, spikes, hats | h r r2, plus the lathe family (panels=4 for a pyramid roof) |
ball | heads, bodies, eyes | r=(rx, ry, rz) under half bands segs rings |
puff | foliage | r under noise |
box | rounded boxes, panels | size=(w, h, d) round bev bands stripes panels axis |
tube | handles, pipes, spirals | pts=[…] r smooth sides |
rod | poles, legs, rails | to r sides bands |
limb | arms, legs, necks | len r=(top, bottom) bands depth |
torus | rims, hoops, arcs | R r arc segs sides |
slab | signs, wings, leaves, flags | pts=[x,y …] t round edge |
wheel | wheels on an X axle | r w tyre hub hubR |
face | eyes, mouth, blush | eyes mouth lid size spacing eyeY mouthY mouthW iris skin blush brows detail |
spot | seats, saddles, stand spots, decks (no geometry) | use=seat|saddle|stand|deck size=(w, d) |
Every part also takes on at surf lift decal upright rot yaw tilt roll scale color ink joint mirror x ring ring0 row chain if detail. ink= is full (the default), thin, none or glow (unlit, for real lights).
Complexity budgets
complexity=N on the asset line caps shapes (parts after copies and mirror twins), triangles and draw calls (each ink class in use, plus one for a face, plus one per fx line). Going over any cap is a compile error.
| c | Shapes | Triangles | Draw calls | Typical |
|---|---|---|---|---|
| 1 | 16 | 1,500 | 2 | a pebble, a sign |
| 2 | 30 | 3,200 | 2 | a mailbox, a fence, a tombstone |
| 3 | 45 | 4,500 | 3 | small props, toys, a canoe |
| 4 | 70 | 6,000 | 4 | critters, machines, a dock |
| 5 | 100 | 8,000 | 4 | houses, desks, a skeleton guard |
| 6 | 140 | 10,000 | 5 | big furniture, an elk |
| 7 | 200 | 15,000 | 5 | a log cabin, a waterfall, a teacup ride |
| 8 | 300 | 22,000 | 6 | a big top, a research lab |
| 9 | 420 | 32,000 | 7 | a ferris wheel, a dragon skull |
| 10 | 640 | 48,000 | 8 | a kaiju |
Aim for 60 to 90% of the shape and triangle caps. Rough triangle costs per shape at default settings: ball 170 to 480, puff 280, lathe or cyl 260 to 530, cone 100 to 190, limb 260, tube 300 to 400, torus 380, wheel 420, box 110 even unrounded, rod 70, slab 50. With segs and rings set, a ball or lathe costs about 2 × segs × rings. A round-eyed face costs about 2,500 triangles at detail=1 and 900 at detail=.6.
Folding small parts into ink=full is the cheap way back under the draw-call budget.
States and anims
jointmakes a part a bone at its origin. Only jointed parts animate: putjointon the root body and on every part that moves.anim <part> <preset>with no state always plays (idle life).anim walk: leg gait …plays only while a game or a scene puts the model inwalk.- Presets:
gait,sway,bob,bounce,wag,flap,nod,spin,breathe. Channelsrx ry rz(degrees),px py pz(metres) ands(scale swell); wavessin spin bounce keys. keys=[0:0 .3:40 .7:40 1:0]is a keyframed cycle;onceplays one cycle and holds the end (doors, a bow, a lid).twin=.5alternates mirror twins;stagger=.5offsets each copy (a trot on diagonals);stagger=.1along a chain runs a wave down a tail. A negativehzruns the motion backward.- Scene movers play the first state they have from
walk run hop move waddle trot scurry crawl fly swim. Name your gait from that list. - A placement with any joint or effect is dynamic and can't batch. Drop joints and effects from scenery that doesn't need them: one showcase dungeon went from 476 to 314 draw calls that way.
Faces
face look on=head eyes=round mouth=smile … draws the house face: unlit, never inked, with the same rules on every skin and fur colour. Defaults are bright and alert; lid stays 0 unless the brief names a mood (.3 calm, .5 sleepy, .7 grumpy, .9 and up shut). Mouths: smile, grin, fang, open, cat, flat. Eyes: round, dot, happy, sleepy. Use blush only on skin, fur or pale heads; on green or blue it reads as a wound. Use detail=.6 unless the face is the star.
Spots: seats, saddles, stand spots and decks
A spot is a part with no geometry: a place a scene can use. It takes every placement key and rides its parent's bone, so a seat on a spinning cup spins its rider. Spots don't count toward the shape budget.
spot sit on=seat at=(0, .09, .04) use=seat a seat: a person sits on it facing its +Z spot rider on=horse at=(0, .2, -.04) use=saddle a saddle: sits astride, facing +Z spot deckhand on=deck at=(0, .1, 0) use=stand a stand spot: someone stands here and rides along spot walk at=(0, .66, 2.5) size=(1.5, 5.5) use=deck a deck: a walkable rectangle, centred on the spot spot ramp at=(0, .6, -2.2) tilt=-14 size=(1.3, 1.5) use=deck tilt a deck for a ramp or steps
Put the spot on the surface: a seat at the cushion's top, a deck at the walking surface. A model with a deck may span paths and water (a bridge, a dock), and walkers step onto any deck within half a metre of where they stand.
Mistakes everyone makes once
Names. Lets and parts share one namespace with palette names, kinds and functions. light, shade, clamp and floor are taken. Call a colour let coatC or furC, and rename on the first error.
Copies and parents.
row=copies are centred onat=, not started from it.- Children of a copied part are copied with it:
mug x3 on=pegwithpeg x3makes nine mugs. Drop the innerxand useparent.ifor per-parent variety. xNwith noroworringstacks the copies in one place and z-fights.mirroralone is the pair.rowandringon one line multiply out; use two lines.- Children of a rotated parent live in its rotated frame. Make the root an unrotated part and give every child world-like coordinates.
Rotation and shape.
rot=is a three.js Euler in YXZ order. A slab laid flat withrx=-90turns in the ground plane withry.- Materials are front-side only, so
open=toplathes show through from inside. Fake the inside with a contrasting part poking through a closed top. - Keys are per kind: the check names the kind and the key it doesn't know.
Anims.
anim … s keys=[…]values are offsets: scale = 1 + v.cel shot model --state sposes at t = 0.6 s unless you pass--t. Shoot a slow cycle at a few times.- Which sign raises a limb depends on how it was rotated. Shoot the state and flip the sign or the channel.
Z-fighting and ink.
- Thin flat parts stacked on a surface z-fight unless each has its own height: offset by a few millimetres.
- Keep inner parts at least 10 cm under an outer surface, or their ink pokes through.
- Markings follow the surface:
under=,bands=, or a ball onsurf=sunk in with negativelift. Never a flat disc pasted on.
More to learn from
The worked examples the generator learns from are in the language reference, each with an Open in Playground button: a vehicle with glass and glowing lamps, a tree with every gene, and a fountain with cel effects. Every model in the library shows its script too.