Edit, upgrade & ship a project (CLI walkthrough)
After scaffolding, three vgai verbs carry a project through its life: apply-diff
edits scenes with validation before every write (the sanctioned way for scripts
and agents to touch a .vscn.json), upgrade audits and re-syncs the project
against the engine checkout, and deploy ships it to Cloudflare Pages. This
walkthrough runs all three on a fresh project — the transcript below is real
captured output, including one deliberately broken patch.
# transcript pending capture — run: node site/media/capture-cli.mjs site/media/capture-cli.mjs -
Scaffold a fresh project.
Terminal window npx @vgai/cli@latest create lifecycle-demoCopies the editor template and installs dependencies (see Scaffold a project for details). The default scene at
public/scenes/default.vscn.json— lights, a ground, a box, a camera — is what we’ll edit. -
Write a patch, and validate it with
--report.A
SceneDiffpatch is a JSON file: anopsarray (add/update/remove/move) plus two required booleans. This one adds a crate next to the box — save it asadd-crate.patch.jsonin the project root:{"ops": [{"type": "add","entity": {"id": "crate-1","name": "Crate","mesh": { "type": "box", "args": [1, 1, 1] },"material": { "type": "standard", "color": "#ff5533" },"transform": { "position": [2, 0.5, 0] },"shadow": { "enabled": true }},"parentId": null,"index": 4}],"environmentChanged": false,"metaChanged": false}Terminal window npm run vgai -- apply-diff public/scenes/default.vscn.json add-crate.patch.json --report--reportvalidates the scene, the patch, the result, and every asset reference the patch introduces — and never writes. The report names the ops and the entity ids touched. -
Apply it for real.
Terminal window npm run vgai -- apply-diff public/scenes/default.vscn.json add-crate.patch.jsonSame validation, then the scene is written back. The crate now exists in the scene with the id we gave it (
crate-1). -
Update by id.
Ops address entities by id — which is why the patch above set one explicitly (
addauto-generates an id if you omit it, but then later patches can’t find the entity). Anupdateop is a full field replace, not a merge: fields you leave out are deleted.recolor.patch.jsonre-states the whole crate with a new color:{"ops": [{"type": "update","id": "crate-1","entity": {"id": "crate-1","name": "Crate","mesh": { "type": "box", "args": [1, 1, 1] },"material": { "type": "standard", "color": "#22cc88" },"transform": { "position": [2, 0.5, 0] },"shadow": { "enabled": true }}}],"environmentChanged": false,"metaChanged": false}Terminal window npm run vgai -- apply-diff public/scenes/default.vscn.json recolor.patch.json -
Watch a broken patch get rejected.
bad-ref.patch.jsonadds an entity whosematerialRefpoints at a.mat.jsonthat doesn’t exist. The whole diff is rejected with the issue named, exit code 1, and nothing is written:Terminal window npm run vgai -- apply-diff public/scenes/default.vscn.json bad-ref.patch.json# ✗ the patch introduces 1 broken asset reference(s) — nothing was writtenThis is the point of the verb: a script (or an AI agent) can’t half-apply a bad edit. Every introduced asset reference must exist under the project’s asset root and parse through its own schema.
-
Audit the project with
npm run vgai -- upgrade --report.Terminal window npm run vgai -- upgrade --reportupgradecompares every template file against the scaffold baseline (.vgai/scaffold-baseline.json) three-way: ourapply-diffedits surface as a[user-edited]diff onpublic/scenes/default.vscn.json— reported, never clobbered. The engine pin is compared (here0.2.0 -> 0.2.0 [match]) and the scene/manifest validation walls run. Drop--reportto actually re-sync and re-pin. -
Dry-run the deploy.
Terminal window npm run vgai -- deploy --reportDiscovery, the pre-flight walls, the production build, and staging all run — then it stops. Zero remote calls. The report names the Cloudflare Pages project (
vgai-<slug>) and the URL shape it would ship to. Drop--reportto push withwrangler.
Recap
New functionality
- Added and recolored an entity via validated JSON patches
- Saw a broken asset reference rejected atomically
- Audited template drift and the engine pin with upgrade --report
- Staged a full deploy with zero remote calls
New concepts & skills
- apply-diff validates scene + patch + result + introduced asset refs before writing
- SceneDiff ops address entities by id; update is a full replace, not a merge
- upgrade is a three-way compare against the scaffold baseline — user edits are surfaced, never clobbered
- deploy --report runs everything up to the wrangler push
Next lesson → Build & publish
See also
Section titled “See also”- Project lifecycle (manual) — the reference page for the same three verbs.
- Scaffold a project · Validate & schema tooling