67js gives AI agents a 3D scene they can revise
By AgentRiot Editorial
The open-source WebGL2 renderer connects agents to editable scenes through MCP, with PNG feedback, revision checks and local media export.

Ask an agent to move a lamp to the left, soften its light and keep the camera where it is. That request needs more than a new picture: it needs a scene whose objects, materials and camera remain available for another edit. 67js (opens in new tab), the project in the 67.js repository, gives agents that kind of workspace through the Model Context Protocol, or MCP.
The engine renders a scene in a browser. An agent supplies structured data, receives PNG previews and changes the same scene through tool calls. Its output can be a still or an MP4, but the working artifact is an editable recipe rather than a clip produced by a generative video model.
An Xuan introduced the project in a November 8 post (opens in new tab). Version 0.16.0 was published the same day (opens in new tab). The package is available as @codepawlhq/67js under the MIT license (opens in new tab). The distinction worth understanding is how much control an agent retains between the first preview and the final export.
The agent edits objects, not just pixels
At the renderer level, a part has geometry, a transform matrix and a material. The agent-facing scene recipe (opens in new tab) organizes geometries, materials and nodes under stable IDs. Nodes can share a geometry or material, and a label can change without changing the object's identity.
That makes follow-up requests addressable. An agent can change a node's position, alter a material's roughness or adjust the camera without describing the whole image again. Shared materials also have consequences: changing one can affect several objects. The agent needs to inspect the scene's structure, not merely judge the last screenshot.
The MCP tools (opens in new tab) expose creation, inspection, edits, checkpoints and image review. Local GLB assets can supply imported models. The 0.16.0 release also adds recipes that place catalog GLBs alongside procedural meshes and terrain, so a scene need not be built entirely from primitives.
This is a useful arrangement for an explanatory animation or product-layout prototype where the next instruction refers to a particular component. It still leaves the agent responsible for choosing geometry, arranging the scene and noticing when the result looks wrong.
A change can commit even when rendering fails
Consider a hypothetical desk-lamp scene: a floor, a lamp assembled from named parts, a light and a camera. The agent creates the recipe, calls scene_inspect to read the current revision and saves a scene_checkpoint before experimenting.
It then sends a small scene_apply batch with that revision as expectedRevision. The batch could move the lamp's parent node and change its shade material. The revision contract (opens in new tab) rejects stale revisions or invalid commands without publishing partial edits. A checkpoint lets the agent restore an earlier state if the experiment is unhelpful; restoring advances the revision rather than winding the revision counter backward.
There is an important split between editing and drawing. A response can report committed: true and a new revision while also reporting renderSucceeded: false. In that case, the edit exists even though a fresh frame does not. Repeating the same command with the old revision is the wrong recovery. The agent should inspect or export the recipe and work from the actual state.
For procedural scenes, named branches let the agent try alternatives without changing the active scene. It could compare warm and cool lighting, then restore the chosen branch. Branch adoption fails if the source scene has changed since the fork, and adopting a branch drops the other branches. This is bounded experimentation, not an unlimited version-control system.
Looking from another angle is part of the workflow
A single attractive view can hide a misplaced component. scene_review (opens in new tab) returns one labeled PNG grid with up to four camera views or motion samples. It renders an isolated snapshot while preserving the source recipe, revision and preview pose.
For the lamp example, front and side views would help reveal whether the shade is attached convincingly and whether the base sits on the floor. The review tool supplies images; it does not guarantee good composition or diagnose every intersection.
The feedback is deliberately smaller than a final render. Ordinary previews accept dimensions up to 1,024 pixels per axis; review tiles are capped at 480 per axis. Memory limits can shrink the actual dimensions, which the returned metadata reports. An agent should read that metadata rather than assume the requested size was delivered.
Running it means supplying a browser
The published MCP setup (opens in new tab) needs Node.js 20.19 or later and an installed Chrome or Chromium executable. The package includes a prebuilt server and preview, so using it does not require building the project website. It does not download a browser.
A version-pinned installation uses the project's short import alias:
npm install 67js@npm:@codepawlhq/[email protected]
An MCP client can launch the installed 67js-mcp command with --backend gpu, or --backend cpu for software rendering. The connection uses standard input and output; a bundled scene page is served over loopback. Render jobs require a configured private directory through --jobs.
MCP support should not be read as proof that every client and model works equally well. The project's compatibility notes distinguish recorded Claude Code agent runs and SDK checks from clients it had not run. They also identify schema-conversion issues for OpenAI strict function tools and Gemini declarations. A developer integrating a different client still has compatibility work to verify.
Export the picture, or keep an editable asset
Once the scene is ready, scene_render_submit (opens in new tab) captures its recipe and verified asset bytes for a job. The agent polls status and reads output paths and hashes after completion. Jobs temporarily occupy the renderer, pausing preview rendering and edits, although inspection and recipe export remain available.
The published job limits allow at most 1,920 pixels on either side and 1,920 by 1,080 pixels in total, at most 30 frames per second for video, and ceilings of 60 seconds and 900 frames per job. Those are separate limits, not a promise of a full minute at the maximum frame rate. Memory budgeting can also reduce the output size.
MP4 rendering still needs FFmpeg. Hardware-capable video jobs can encode H.264 inside the browser, but the released runtime (opens in new tab) passes the encoded stream to its FFmpeg pipeline. Browser encoding does not make the tool dependency disappear.
For further editing elsewhere, scene_export_glb (opens in new tab) writes a GLB into the configured job store. That export has limits: recipe motion is not converted to animation clips, and lighting, cameras, custom shaders and postprocessing do not travel with the asset. Keeping the canonical recipe preserves more of the 67js authoring context than a GLB alone.
A narrower interface, not a Blender replacement
The MCP surface does not expose arbitrary host JavaScript or remote asset URLs. Imports come from an operator-configured local catalog. There is a shader exception: bounded GLSL fragment snippets are accepted for postprocessing and material hooks. The documented restrictions (opens in new tab) constrain those snippets, while the runtime blocks page requests outside its local origin. These are specific controls, not a blanket security guarantee for the surrounding agent or machine.
The project describes Blender capability and three.js lightness as goals. Its published MCP reference (opens in new tab) explicitly warns that MCP support does not establish Blender feature parity.
The project's six-task agent comparison (opens in new tab) reported six passes for 67js MCP, six for Blender MCP and five for three.js-by-code. It used one model and tasks built around the 67js suite. Fewer tool calls did not mean fewer reported tokens; one competitor's token count was also flagged unreliable. Blender ran under emulation with render timeouts, making its wall-time comparison unfair. These are narrow development results, not a general efficiency or visual-quality verdict.
The practical reason to try 67js is the retained scene: an agent can inspect a component, change it, compare views and restore a checkpoint before exporting. Start with a small assembly whose parts you can identify. If the agent can revise that scene without losing what was already correct, you have a basis for trusting it with a larger one.

