Skip to content

Edit, upgrade & ship a project (CLI walkthrough)

cli tutorial Beginner ⏱ 10 min vgai 0.1.0

Prerequisites: Node.js installed

What you'll learn

  • Edit a scene from a script with vgai apply-diff — validated before every write
  • Read the SceneDiff patch format (add/update/remove/move ops)
  • See a broken patch get rejected with nothing written
  • Audit a project against its scaffold baseline with vgai upgrade --report
  • Dry-run a Cloudflare Pages deploy with vgai deploy --report

What you'll build: A scaffolded project taken through a validated scene edit, an upgrade audit, and a staged (dry-run) deploy — all real captured output.

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
Terminal — Edit, upgrade & ship a project (CLI walkthrough) · captured by site/media/capture-cli.mjs
  1. Scaffold a fresh project.

    Terminal window
    npx @vgai/cli@latest create lifecycle-demo

    Copies 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.

  2. Write a patch, and validate it with --report.

    A SceneDiff patch is a JSON file: an ops array (add / update / remove / move) plus two required booleans. This one adds a crate next to the box — save it as add-crate.patch.json in 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

    --report validates 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.

  3. Apply it for real.

    Terminal window
    npm run vgai -- apply-diff public/scenes/default.vscn.json add-crate.patch.json

    Same validation, then the scene is written back. The crate now exists in the scene with the id we gave it (crate-1).

  4. Update by id.

    Ops address entities by id — which is why the patch above set one explicitly (add auto-generates an id if you omit it, but then later patches can’t find the entity). An update op is a full field replace, not a merge: fields you leave out are deleted. recolor.patch.json re-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
  5. Watch a broken patch get rejected.

    bad-ref.patch.json adds an entity whose materialRef points at a .mat.json that 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 written

    This 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.

  6. Audit the project with npm run vgai -- upgrade --report.

    Terminal window
    npm run vgai -- upgrade --report

    upgrade compares every template file against the scaffold baseline (.vgai/scaffold-baseline.json) three-way: our apply-diff edits surface as a [user-edited] diff on public/scenes/default.vscn.json — reported, never clobbered. The engine pin is compared (here 0.2.0 -> 0.2.0 [match]) and the scene/manifest validation walls run. Drop --report to actually re-sync and re-pin.

  7. Dry-run the deploy.

    Terminal window
    npm run vgai -- deploy --report

    Discovery, 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 --report to push with wrangler.

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