67js is a 3D engine for AI agents and for pages. It has a real-time rasterizer, a path tracer, addons for terrain, vegetation, characters, liquid, vehicles and media export, and an MCP server. A scene is plain data: each part has a geometry, a matrix and a material.
An agent builds and changes a scene through the MCP server, looks at PNG previews and renders stills or MP4 video.
The rasterizer runs on WebGL2.
The path tracer runs on the CPU, on WebGL2 and, with the optional packages/render-native, on Vulkan.
A WebGPU backend is opt-in from the library, and the MCP server does not expose it.
The goal is to be as capable as Blender and as light as three.js. docs/goal.md defines each part. See the showcase, the documentation, the guide for agents and the changelog. The FAQ answers common questions.
| Name | What it is | Runs on |
|---|---|---|
Glaze (Renderer67) |
The real-time rasterizer | WebGL2 |
| Cook | The path tracer, one still per job | CPU (default), WebGL2, Vulkan ray queries through the optional packages/render-native, and WebGPU (opt-in, library only) |
| Real-time path tracer | A hybrid tracer with a radiance cache and a temporal denoiser. It is experimental, and the MCP server does not expose it | WebGPU, with a WebGL2 fallback |
| Light bake | Baked lightmaps | CPU, WebGL2 and WebGPU |
The WebGPU backend of Cook traces a BVH in WGSL compute, because browsers have no hardware ray tracing. MCP render jobs take the Cook backends cpu, gpu and native only.
The roadmap in issue 890 groups the renderers into four tiers.
The tier names are working names.
The quality setting that picks a tier is planned (issue 904), and so is refine-at-rest (issue 903).
Realtime-high does not exist yet (issue 901 and issue 902).
Six scenes at 960x540, medians over 3 interleaved runs on an idle card. FLIP is the error against a Cycles 4096-sample reference, and lower is better. Every value is the range of the per-scene medians across the six scenes. The full per-scene tables are in the bench/tiers folder. They land with pull request 931, after pull request 921 and before this one.
| Tier | For | Runs on | Trade-off | 67js measured | Blender measured | FLIP vs Cycles |
|---|---|---|---|---|---|---|
| draft | A quick look while editing | Glaze, 0.5 render scale, 1 sample, light shading, 8 bit target | Aliased edges, no environment lookup, a quarter of the pixels enlarged | 0.54 to 1.04 ms a frame with the pixel read; 0.26 to 0.33 ms queued back to back | EEVEE 5.3, 1 sample: 56 to 59 ms a render call | Glaze 0.045 to 0.188, EEVEE 0.041 to 0.562 |
| realtime | Interactive use | Glaze, default settings | Indirect light is approximate | 0.77 to 0.98 ms a frame with the pixel read; 0.35 to 0.50 ms queued back to back | EEVEE 5.3, 64 samples: 288 to 363 ms a render call | Glaze 0.030 to 0.197, EEVEE 0.042 to 0.562 |
| realtime-high | Better interactive frames | Planned: Glaze on WebGPU with a GI cache and upscaling (issue 901, issue 902) | More VRAM | not measurable yet | none | none |
| final | Finished stills | Cook native, 256 samples (Vulkan ray queries, optional packages/render-native) |
More samples than Cycles for the same noise | 1.73 to 4.24 ms a sample; 0.71 to 1.32 s for 256 samples with setup | Cycles 5.3 OptiX: 6.81 to 26.41 ms a sample; 3.43 to 8.46 s for 256 samples with setup | Cook native 0.019 to 0.080, Cycles 0.010 to 0.039 |
| final | Finished stills | Cook webgpu, 256 samples (WGSL compute, software BVH, library only) | Slower per sample than native, same image | 5.88 to 17.33 ms a sample; 1.94 to 4.86 s for 256 samples with setup | same Cycles | Same as native: FLIP between the two images 0.0000 to 0.0003 |
Glaze runs the realtime tier in under about 1 ms a frame at 960x540 on these scenes (0.77 to 0.98 ms), measured with a pixel read. The EEVEE times are one full background render call, including scene sync, with EEVEE ray tracing off and no global illumination. They are not a frame rate comparison. The draft tier is not faster than realtime here. At 960x540 a Glaze frame costs about as much as the browser pixel read, so the queued figures are the ones that differ.
Cook native draws a sample 3.8 to 6.2 times faster than Cycles 5.3 OptiX, but needs more samples for the same noise. On the three noise-limited scenes (lit-interior, spot-area and light-linking) it needs 6.6 to 19.0 times Cycles' samples for the same error. That makes it 1.05 to 4.02 times Cycles' time for the sampling alone, BD0 and 0.87 to 2.52 times with setup included.
On metal, glass and outdoor-hdri the error falls slower than 1/N between 256 and 1024 samples, which points to bias. Cook does not reach Cycles' error there, so no equal-error ratio is given. Cook webgpu draws a sample 3.3 to 4.1 times slower than native.
Cook gpu (WebGL2) and Cook cpu are not in this run. Cook cpu needs no card, so VRAM does not apply. docs/cycles-parity.md has the Cook against Cycles method on one scene.
The experimental real-time path tracer is not the realtime-high tier. These figures come from lit-interior only, measured before the idle gate with the card 17 to 20 percent busy. On the WebGPU backend it draws a frame in 5.6 ms. FLIP drops under 0.20 after 16 frames (0.15 s) and under 0.10 after 64 frames (0.41 s). It ends at 0.056 after 256 frames.
The WebGL2 fallback takes 6.7 ms per frame and 6.1 s for the first frame, which includes shader compile. It runs at 2 bounces against an 8-bounce reference.
Machine: RTX 3060 12 GB (driver 621.14), Intel i7-14700KF, Chrome 157 headless on D3D11, Node 24, Blender 5.3, measured 2026-11-11. The card was idle: each run waited for at most 15 percent utilisation, and 0 of 162 runs were contended.
Each picture below is a 67js render. The linked ones open live in the browser.
| Airport ramp | AI data center | Container port |
![]() |
![]() |
![]() |
| Bistro cafe corner | Bistro plaza |
![]() |
![]() |
Let your agent do it. Paste this prompt into Claude Code, Codex, Cursor, Gemini CLI or OpenCode. The agent installs the package, reads the guide and connects the MCP server.
Install 67js from npm as `67js@npm:@codepawlhq/67js` and connect its MCP server with `npx 67js-mcp`. Read
https://67js.codepawl.com/llms.txt first and follow it.
Claude Code plugin. One command adds the MCP server and both skills. The server starts from the published npm
package with npx, so nothing is built locally.
/plugin marketplace add codepawl/67.js
/plugin install 67js@67js
By hand
npm install 67js@npm:@codepawlhq/67jsThe registry name is @codepawlhq/67js. The command installs it under the alias 67js, so imports stay short.
The package is ESM. The tools need Node.js 20.19 or later. Glaze and the WebGL2 path tracer need a WebGL2 browser. The WebGPU backends need a browser with WebGPU.
A new minor version ships about once a week. The day is not fixed and can move by one to three days, so a release can wait for an important fix or go out early when its work is done. A serious bug gets a patch release at once. Before 1.0, a minor version can change the API. CHANGELOG.md lists each change and what to update.
npx keeps the copy it downloaded first, so the MCP server does not update by itself. To get the latest version, run
npm install 67js@npm:@codepawlhq/67js@latest in a project, or start the server once with
npx -y -p @codepawlhq/67js@latest 67js-mcp.
import { Renderer67, box, sphere } from '67js';
// Column-major 4x4 matrix: scale, then move.
const placed = ([x, y, z], [width, height, depth] = [1, 1, 1]) =>
new Float32Array([width, 0, 0, 0, 0, height, 0, 0, 0, 0, depth, 0, x, y, z, 1]);
const parts = [
{
name: 'Floor',
geometry: box(),
matrix: placed([0, 0, 0], [8, 0.1, 8]),
material: { color: [0.4, 0.42, 0.45], metallic: 0, roughness: 0.9, emission: 0 },
},
{
name: 'Ball',
geometry: sphere(48, 24),
matrix: placed([0, 1, 0]),
material: { color: [0.8, 0.3, 0.2], metallic: 0, roughness: 0.35, emission: 0 },
},
];
const canvas = document.querySelector('canvas');
const renderer = new Renderer67(canvas, parts, { samples: 4, memoryBudgetMiB: 256 });
renderer.render({ eye: [4, 3, 6], target: [0, 1, 0] });Call renderer.updateParts(parts) to move or recolour parts without a new upload.
Call renderer.resize() after the canvas changes size, and renderer.dispose() before you replace the renderer.
The guide covers cameras, lights, effects and every material field.
To save a PNG from a script, use the render-from-a-script recipe.
The package includes an MCP server that connects an agent to a persistent browser renderer. The server needs a local Chrome installation.
npx 67js-mcp --backend gpu --memory 192--backend gpu renders with hardware WebGL2 through Chrome. Use --backend cpu on a machine without a GPU.
With bun, bunx 67js-mcp takes the same flags; CI runs the packaged server under bun on every pull request.
An agent authors a JSON recipe, sets lights and fog, imports GLB assets and adds motion.
It gets PNG previews back, compares up to four views in a review grid and runs render jobs for stills and MP4 video.
The server accepts no arbitrary code and no remote asset URLs. The MCP reference lists its tools.
Two skills teach an agent to drive the MCP tools: build-67js-scene for scenes and materials, and render-67js-media for image and video export. For a plain-text guide, give the agent llms.txt.
viz3d uses 67js. It is a skill that turns places, systems and events into 3D apps and films, and it renders its films and stills in 67js.
To add it in Claude Code, run /plugin marketplace add codepawl/viz3d, then /plugin install visualize-in-3d@codepawl.
Each addon is a separate import, so a page loads only what it uses.
| Area | Import | Guide |
|---|---|---|
| Lighting | 67js/addons/hdri |
Image-based lighting from .hdr files |
| Terrain | 67js/addons/terrain, 67js/addons/texture-set |
Chunked terrain with scanned ground layers |
| Vegetation | 67js/addons/vegetation, 67js/addons/grass, 67js/addons/clutter |
Trees, grass and ground clutter with wind and level of detail |
| Characters | 67js/addons/gltf, 67js/addons/retarget, 67js/addons/skeleton-pose |
glTF import, clip retargeting and pose layers with IK |
| Liquid | 67js/addons/spume |
Baked liquid playback with refraction and spray |
| Vehicles | 67js/addons/vehicle |
Wheeled vehicles on a path |
| Physics | 67js/addons/physics |
Rapier contacts and joints recorded into a timeline |
| Live games | 67js/addons/runtime |
Game loop with fixed or variable steps and pluggable systems |
| Live games | 67js/addons/input |
Input: keyboard, mouse, gamepad, touch, device motion, replay and custom sources mapped to named actions and axes |
| Live games | 67js/addons/streaming |
Streaming: loader plugins, distance and request loading, a byte budget with LRU eviction and LOD with hysteresis |
| Live games | 67js/addons/netcode |
Netcode: server or host authority, pluggable transports, delta snapshots, client prediction with reconciliation and remote interpolation |
| Live games | 67js/addons/physics-runtime |
Live physics: a physics world stepped in the game loop, contact and sensor events, ray, shape and overlap queries |
| Live games | 67js/addons/physics-jolt |
Jolt engine: a second engine for live physics, with the same events and queries; needs the optional jolt-physics package |
| Live games | 67js/addons/audio |
Spatial audio: sounds on nodes, played from contacts, markers and input, with buses and a limiter |
| Live games | 67js/addons/animation-graph |
Animation graph: states, 1D and 2D blend spaces, parameter transitions with crossfades and masked layers for any rig |
| Live games | 67js/addons/player |
Player: character, vehicle and flight controllers, follow, first-person, top-down, orbit, chase and side-scroller camera rigs with wall pull-in, custom kinds, swappable at runtime |
| Live games | 67js/addons/game-rules |
Game rules: a JSON rule document of variables, triggers and actions, played as a runtime system |
| Live games | 67js/addons/game |
Game: a scene recipe with a game section played in a page, and the scene_export_web MCP tool that writes it as a static web build |
| Modeling | 67js/addons/mesh, 67js/addons/modeling, 67js/addons/sculpt |
Mesh editing, modeling and sculpt brushes |
| Offline light | 67js/addons/path-tracer, 67js/addons/light-bake |
Path-traced stills and baked lightmaps |
| Post passes | 67js/addons/user-pass |
Your own full-screen GLSL passes: dither, pixel downscale, quantise |
| Agents | 67js/addons/agent-scene, 67js/addons/agent-asset |
Scene sessions with revisions and checkpoints |
The documentation page lists every guide.
The render command exports a scene to PNG or MP4 through headless Chrome, on the GPU or on the CPU.
npm run render -- --kind image --scene nature --backend gpu --preset high --output artifacts/nature.pngVideo export streams one frame at a time, so a film never sits in memory. The render skill lists every preset and flag.
- Install Node.js 22.12 or later.
- Run
npm ci. - Run
npm run dev. Vite prints the local URL.
Each number below comes from this repository's benchmarks.
- Bundle size. On
lit-box, 67js is 58,788 bytes gzip and three.js is 133,797 (2.28 times smaller). This is thenpm run sizeresult on 2026-11-11. The goal of 50,000 bytes is not met yet. bench/size/README.md has every scene. - Path tracing on the GPU. One run on 2026-11-03, on a shared machine, traced the 1920 by 1080 demo room (181,708 triangles, 64 samples, 8 bounces). The 8-thread CPU tracer took 585.9 s. The WebGL2 GPU tracer took 58.15 s, and that figure includes 10.3 s of shader compile. Whether the CPU figure is end to end is not recorded, so read the two as separate figures, not a speedup. docs/webgpu-decision.md has the method.
- Cook against Cycles. See Quality tiers and docs/cycles-parity.md.
docs/verification.md has older results and their limits. They compare matching scenes on the same hardware. They do not show a general speed advantage over three.js or visual parity with Blender.
Read CONTRIBUTING.md before you open a pull request. It covers setup, checks, code style and the release flow.
Coding agents start with AGENTS.md, and npm run preflight runs the pull request checks locally.
Questions, ideas and what you made go in Discussions. Bug reports: SUPPORT.md.
67js is free and MIT licensed. Sponsors pay for GPU time, test hardware and the hours that go into it. Company sponsors get their logo here from $100 a month.
- gl-matrix supplies the matrix math.
- The glTF addon has its own parser. The Draco, meshopt and KTX2 decoders are three.js loaders that you pass in.
- The textures and the HDRI on the site are CC0 scans from Poly Haven and ambientCG. See the texture credits.
- The Bistro renders use Amazon Lumberyard Bistro (CC BY 4.0, from the NVIDIA ORCA library) under a CC0 Poly Haven sky.
- The showcase models and their sources are listed in each world's
scene.jsonunderpublic/showcase/. - The banner wordmark uses Sora (SIL Open Font License).
MIT © CodePawl





