The cel CLI · celworld docs

The cel CLI

Look, make, check, shoot, save. Every command, in the order you use them.

bun run cel <command> runs from the repo root. The library commands need the database (DATABASE_URL in apps/web/.env); shot and thumb also need the site running (bun run dev), because they render through it.

Postgres is the store. The library/ folder on disk is how the library travels in git: cel export writes it and cel import reads it back.

Look before you make

bun run cel catalogue            # library models (ref, title, latest v, size in metres, complexity, states) and built-ins
bun run cel catalogue --json
bun run cel list [--tag t]       # every model: slug, title, versions, tags
bun run cel show <slug>          # versions, complexity, triangles, states, which scenes use it
bun run cel cat <slug>[@v]       # print a script, to fork from it

Reuse beats making. Built-ins are approved and ready, and a close library model can be forked (cel save … --fork slug@v). Search the catalogue for your scene's nouns first: bun run cel catalogue | grep -i -E "dock|lighthouse|boat" turned up a dock and a lighthouse for one harbour scene, so only the crab, the tug and the shack were new.

Open a run

bun run cel agent start --label "Tiny Harbor: 3 models + scene" [--scene tiny_harbor] [--model claude-opus-5-5] [--effort high]

It prints a run id. Pass it to every save, so each version records which session made it.

Models: check, look, save

bun run cel check packages/engine/src/dsl/scripts/<set>/<slug>.cel [--complexity N] [--seeds 1,2,3]
dock_crab c3 · seeds 1,2,3
  shapes     18 / 45 (40%)
  tris       3746 / 4500 (83%)
  draw calls 2 / 3 (67%)
  states     scuttle, wave
  0 must-fix · 0 advice

A must-fix names the line and the fix:

  1 must-fix · 0 advice
  25: FIX warn zfight funnel and glassband (line 19) put faces in one plane near (-0.14, -0.22, 0.65) facing +z, 0.0 mm apart: they will z-fight; offset one by at least 4 mm

The exit code is 1 while anything is must-fix. Advice (floating parts, tiny parts) is worth fixing unless it's deliberate.

bun run cel shot model --file <path.cel> --out shots/<slug>.png [--angle front|three-quarter|side|top|<az>,<el>] [--seed N] [--state s] [--t secs]
bun run cel shot model <slug> --out shots/<slug>.png      # a saved model, latest version

Look at every picture. Shoot a few seeds, a side or front angle as well as the default three-quarter, and every named state: the check can't tell you a claw waves downward or a deck stands on end.

bun run cel save <path.cel> --agent <run> --new --prompt "<the brief>" --tags <a,b>
bun run cel save <path.cel> --agent <run> --prompt "v2: what changed"     # the next version of the same slug
bun run cel save <path.cel> --agent <run> --fork <slug>@<v> --new         # a fork, linked to its parent

The slug comes from the asset line. --new refuses if the slug exists, and save refuses must-fix issues unless you pass --force. Without --agent the version is recorded as hand-written.

Scenes: new, check, save

bun run cel scene new tiny_harbor --template beach
bun run cel scene check packages/engine/src/scene/scripts/tiny_harbor.scene
tiny_harbor (beach) · placed 41 · ≈98 draw calls before batching
  0 error(s) · 1 warning(s)
  43: warn crowded placed 3 of 4: the area is too full (make it bigger, lower count= or spacing=)

The check lays the scene out against the real footprints of the latest library versions, so save the models first.

bun run cel scene save packages/engine/src/scene/scripts/tiny_harbor.scene --agent <run> --prompt "<the brief>"

Look at the scene

bun run cel shot scene tiny_harbor --out shots/tiny_harbor.png [--view name] [--t secs] [--hide-above n] [--w 1600 --h 900]
bun run cel shot scene --file <path.scene> --out <png>     # an unsaved scene file

The shot runs the scene's life for --t seconds (3 by default) in fixed 1/60 s steps, so the same scene, view and time give the same image every time. It prints one stats line:

placed 105 · dynamic 15 · batches 24 · protos 29 · tris 136310 · placeholders 0 · drawCalls 67 · fps 58 · buildMs 14 · loadMs 155 · lights 0

The live viewer is /scenes/<slug> on the site.

Thumbnails

bun run cel thumb model <slug> [--v N]                 # 512 × 512 library thumb
bun run cel thumb scene <slug> [--v N] [--view name]   # 1280 × 720
bun run cel thumb --missing                            # every latest version and built-in without one

Close the run

bun run cel agent show <run>
bun run cel agent stamp <run> --context <final context tokens> --steps <tool steps> --ms <wall ms>
bun run cel agent stamp <run> --input N --output N --cache-read N --cache-write N --ms N

Stamp once, when the work is finished. It records the session's tokens and time and splits them over everything the run saved, in proportion to the size of each script. The Costs page keeps the ledger.

Export and import

bun run cel export [--root <dir>]                # database → library/ (one folder per slug: meta, every version, thumbs)
bun run cel import [--if-empty] [--root <dir>]   # library/ → database, idempotent
bun run cel runs [--source studio|scene_build|celgen|agent|import]