Setup
What the command line needs: Node, Chrome for renders, the local renderer for films and Cycles, where credentials live, and what each exit code means.
The command line is a preview for Puni's own team. It builds from Puni's private repository and is not published to npm, so you can run it only with access to that repository.
The command line runs anywhere Node runs. Rendering adds a browser; films and Cycles add the local renderer.
#Requirements
| For | Needs |
|---|---|
| Scene commands | Node 22 or newer |
render png, glb, usdz | An installed Chrome with WebGL2, or --browser /path/to/chromium. With neither, a terminal run offers to download Chromium (Render commands) |
render film | The local renderer at http://127.0.0.1:4317 with FFmpeg |
| Cycles stills | The local renderer with Blender |
The renderer is pnpm -C apps/renderer start. On Apple silicon pnpm -C apps/renderer setup:blender installs a pinned Blender.
#Check the runtime
puni runtime --base-url https://puni.design --jsonThis compares the app's builds with the command line's bundled core and renderer. A mismatch exits 1 with PUNI_RUNTIME. It sends no credentials.
#Credentials
| Item | Where |
|---|---|
| Device tokens | ~/.config/puni/credentials.json, per origin, readable only by you |
| Another file | PUNI_AUTH_FILE=path or --auth-file path |
| A token for one shell | PUNI_AUTH_TOKEN; never written to disk |
--base-url names the origin on every remote command. HTTPS only, except loopback.
#Exit codes
| Code | Exit | Meaning |
|---|---|---|
PUNI_USAGE | 64 | A flag or argument is wrong |
PUNI_VALIDATION | 2 | The scene, file or settings failed validation |
RENDER_SCENE_EMPTY | 2 | The scene has nothing visible to draw |
PUNI_RENDERER | 1 | The renderer itself failed; the scene was not the cause it named |
PUNI_HOST_BUSY | 75 | The machine was too busy to start a browser; retry when load falls |
PUNI_RENDERER_BUSY | 75 | The renderer's browser failed to launch or went away mid-render; retry |
PUNI_RENDERER_UNAVAILABLE | 69 | There is no browser to launch on this machine |
PUNI_IO | 66 or 73 | A file could not be read (66) or written (73) |
PUNI_AUTH | 78, 1 or 2 | 78: no token to send, or a malformed one. 1: the studio refused the token, or sign-in was declined or expired. 2: the token lacks the render scope |
PUNI_CONFLICT | 75 | The revision moved; read the latest and retry |
PUNI_TIMEOUT | 75 | A deadline passed: the command's --timeout, or a connection that timed out; retry |
PUNI_NETWORK | 75 or 1 | The studio could not be reached or the connection broke. Exit 75 from render view --id and from failures the CLI names itself; 1 from the older remote, runtime and transfer paths |
PUNI_CONFIG | 78 | A remote command has no origin |
PUNI_LIMIT | 2 | A byte or count limit was hit |
PUNI_CANCELLED | 130 | You interrupted the command |
Every error also carries type and message in the JSON envelope.
#Input from a pipe
- reads one JSON input from standard input: a scene, a command file, an environment patch or simulation settings. Editing a piped scene needs --output. Input is capped at 280 MiB and must finish arriving within 30 seconds.
Read the Quickstart if you have not made a scene yet.
#Self-hosted render worker
This direct-worker route is for operators who already control a render worker and its service credential. The worker secret is not a user token from Settings. Keep it private. Connected end users should call the MCP render tool with render access.
export PUNI_RENDER_WORKER_URL=https://render.example.com
export PUNI_RENDER_WORKER_SECRET=YOUR_WORKER_SECRET
puni render view --file scene.json --output view.png --remote --width 640 --jsonThe command checks the returned PNG and document hash before writing. See Rendering for local rendering without a worker.
Was this useful?