cpu3d
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cpu3dBuild a lighthouse on a rocky island and render a view from the sea."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cpu3d
Agentic-first 3D modeling. Your AI agent builds the geometry, a tiny CPU rasterizer renders it.
Connect Claude (or any agent) over MCP, ask for a scene, and watch it being built live in the editor.
The agent can see its own work: every render_view call returns a PNG rendered on the CPU, no GPU or browser required.
Live demo · Quick start · Connect an agent · Tools · How it works
A scene built by Claude Code over MCP. The activity feed on the right shows every tool call as it happens.
Why
Most 3D tools are built for hands on a mouse. cpu3d is built for agents first:
One API for everyone. The editor has no private code paths. Every click calls the same tools an agent calls, so anything a human can do, an agent can do.
Agents get eyes.
render_viewrenders the scene headlessly on the CPU and returns an image. The agent builds, looks, and fixes, in a loop.Geometry as JSON recipes. Shapes are described declaratively (
lathe,sweep,extrude,tube,terrain, ...). No code is evaluated, so recipes from any agent are safe, diffable and easy to edit by hand.Zero dependencies. Pure JavaScript, about 3,000 lines including the editor. The renderer is a real software rasterizer, not a WebGL wrapper.
Related MCP server: material-workbench
Gallery
Seagrass meadow: 35,000 blades swaying in one current (the wind behaviour bends every vertex, harder towards the tip), tall kelp, rocks, two schools of fish circling, drifting plankton and volumetric light shafts through the water that the fish cut with their shadows, seen from a slowly gliding drone. Designed for a fluid frame rate: full density only where the drone flies, light shafts marched once per 2x2 pixels. 55 objects, 204k triangles from 53 KB of JSON, thanks to scatter.
Café racer garage: a motorcycle at real scale on a paddock stand, its rear wheel spinning. Wire-spoke wheels with tread, a finned parallel twin, chrome headers into megaphones, shocks with chrome springs, a chain, a glossy tank and a leather hump seat; brick walls, sealed concrete, a workbench, a roller door and a swinging work lamp. 131 objects, 99 KB of JSON, every surface procedural.
Photographer's desk: a vintage rangefinder at real scale on oiled walnut. Pebbled leather, satin chrome, knurled dials, the walnut grain, the cloth of the notebook and the marble of the coaster are all procedural patterns with relief, evaluated per pixel in object space on any shape. 49 objects, 34 KB of JSON, no image files.
Neon district: 462 objects, everything procedural. Towers carry painted window textures (thousands of lit windows from three PNGs made by the build script), neon signs with abstract glyphs flicker and smear their light across the wet asphalt, rain is one raw mesh of 1,800 streaks falling in two stacked layers so the loop is seamless, flying cars cruise in four lanes, an elevated train crosses, lanterns swing and a hologram turns in the purple haze.
Fairground at dusk: 339 objects, 98,046 triangles, everything moving. The Ferris wheel gondolas orbit and counter-rotate so they hang upright, horses gallop on the carousel, chairs fly out on the wave swinger, the roller coaster train follows its track on spline keyframes timed by energy conservation (slow over the lift hill, fast in the dips), fireworks burst with keyframed scale and glow, balloons drift away with flow. Built in about 240 lines of examples/build.mjs.
Plush dancer (right): a fluffy character whose fur is surface noise, dancing to a 120 bpm beat. cpu3d has no object hierarchy, so the build script poses a small skeleton (root bounce, sway and twist; shoulders and hips) and bakes it into keyframes for each of the 59 parts; a slow orbit turns the whole dancer.
The skeleton watch scene: 170 parts, every one a JSON recipe (spoked gears are extrudes with holes, the hairspring is a tube along a spiral), rendered on one CPU core. Full view: docs/watch.png.
Turbofan cutaway: about 1,350 NACA-profiled blades in radial arrays and casings revolved through 240°. 47 KB of recipes, 4.15 MB once exported as triangles.
Fifteen scenes ship with cpu3d, all of them animated. Open them from the Gallery in the editor, or start with cpu3d serve --example castle.
All of them are built in examples/build.mjs through the same tool API an agent uses, including probe_height to put things on terrain.
Recipes are compact: the lighthouse island is 7.5 KB of JSON but 1.48 MB once exported as triangles. The editor shows these numbers live for the scene and the selected object.
Quick start
Requires Node.js 18 or newer.
npx -y github:alparn/cpu3d serveOpen http://localhost:8173 (it starts with the shape showcase; --example castle or --empty change that), then connect your agent (next section) and ask something like:
Build a small harbor: a wooden pier on posts, two boats, and a lighthouse on a rock. Check it with render_view from two angles and fix anything that floats or intersects.
Or clone it:
git clone https://github.com/alparn/cpu3d.git
cd cpu3d
npm start # editor + MCP on http://localhost:8173
npm run dev # same, autosaves to ./scene.jsonConnect an agent
The editor's Connect agent button shows these snippets with the right URL filled in.
Claude Code
claude mcp add --transport http cpu3d http://localhost:8173/mcpClaude Desktop (claude_desktop_config.json, Settings → Developer → Edit Config)
{
"mcpServers": {
"cpu3d": { "command": "npx", "args": ["-y", "github:alparn/cpu3d", "mcp"] }
}
}The stdio server starts the editor on port 8173 so you can watch. If an editor server is already running there, it forwards to it, so the agent edits the scene you have open.
Cursor, VS Code, Windsurf and other MCP clients
{ "mcpServers": { "cpu3d": { "url": "http://localhost:8173/mcp" } } }Any agent framework (plain HTTP)
curl http://localhost:8173/api/tools?format=openai # tool schemas, OpenAI function format
curl -X POST http://localhost:8173/api/tools/add_objects \
-H 'Content-Type: application/json' -H 'X-Cpu3d-Client: my-agent' \
-d '{"objects":[{"name":"Ball","shape":{"type":"sphere","radius":0.5},"position":[0,0.5,0]}]}'Tools
Tool | What it does |
| The recipe language: primitives, generative shapes, 2D shapes, paths, tips |
| All objects with id, recipe, transform, material, triangle count and world bounds |
| Add one or many objects in a single call |
| Change name, transform, material (merged) or replace the recipe |
| Delete objects |
| Replace the whole scene with a scene document |
| Set the scene camera, or |
| Background gradient, fog, light, ground grid, an |
| Make objects move: behaviours ( |
| Add, merge or delete one keyframe of an object or of the camera path |
| One image with several frames of the animation, so the agent sees the motion at a glance |
| Render an animated GIF with motion blur (saved to |
| Raycast down at |
| Render a PNG and return it to the agent, with optional camera, focus, shading, wireframe, highlight and animation |
| Wavefront OBJ out and in |
| Shared history for humans and agents |
The MCP server also sends a short guide in its instructions, so agents know the workflow (read reference → build → render → fix) without any prompt engineering on your side.
Shape recipes
An object is plain JSON. Rotations are in degrees, colors are hex, Y is up and the ground is y = 0.
{
"name": "Vase",
"shape": { "type": "lathe", "profile": [[0, 0], [0.4, 0], [0.5, 0.3], [0.3, 1.0], [0.35, 1.4]], "segments": 48 },
"position": [0, 0, 0],
"rotation": [0, 0, 0],
"scale": 1,
"material": { "color": "#4d99d9", "specular": 0.5, "doubleSided": true }
}Recipe | Idea |
| Primitives |
| Box with smooth rounded edges and corners (devices, furniture, buttons) |
| Revolve a 2D profile around Y (vases, towers, bottles, columns); partial revolutions for cutaways |
| Repeat any shape around an axis (blade rings, spokes, columns), one object for hundreds of copies |
| Push any 2D polygon (concave too, with |
| Move a cross-section along a 3D path, with twist and taper (rails, frames, twisted columns, horns) |
| Sweep of a circle (pipes, cables, springs, handles, knots) |
| Noise heightfield with water level and height-based colors |
| Raw triangles |
| A tapered, bent ribbon: grass, seagrass, kelp, leaves, feathers |
| Thousands of copies of any shape over an area with random scale, yaw, tilt and clumping, in one object (meadows, forests, rocks, particles) |
| Displace the surface along its normals by fractal noise: fur and plush, rocks, bark, clay |
2D shapes (circle, polygon, rect, roundedRect with optional squircle corners, star or point lists) and paths (line, circle, helix, torusKnot or point lists) plug into extrude, sweep and tube. The full reference is what get_shape_reference returns, see src/recipes.js.
Materials and light
"material": { "color": "#b9b6b0", "metalness": 1, "roughness": 0.25 } // polished titanium
"material": { "color": "#ffffff", "texture": "examples/textures/screen.png", "emissive": 1 } // a lit displayProperty | Meaning |
| base color and the sun highlight |
| metals reflect in their own color and have no diffuse light |
| 0 = mirror, 1 = matte (default 0.7); sharp or blurry reflections |
| self-illumination; |
| PNG in the project or a |
| Procedural surface with relief, no image: |
| faceted shading, open surfaces |
set_environment controls what glossy surfaces reflect (reflections: "sky" | "studio" | "none"), the main light (intensity, softness for soft shadows) and up to four extra lights for fill and rim lighting.
Animation
Objects move with declarative behaviours, keyframes, or both, so an agent can animate a whole machine in a few calls. Everything is evaluated per frame. Geometry is never rebuilt, only the object matrix and the glow change.
Behaviour | Parameters | Good for |
|
| rotors, wheels, clock hands |
|
| pendulums, balance wheels, doors |
| world | floating boats, hovering drones |
|
| turntables, planets, satellites |
|
| breathing lights, warning beacons |
| world | wind streaks, particles, exhaust, conveyor belts |
{ "id": "obj_7", "animation": { "spin": { "axis": [0, 0, 1], "speed": -6, "step": 1, "pivot": [0, 0.4, 0] } } }Without pivot, spin and swing turn around the object's own origin and local axis; with pivot, around a world axis through that point, so several parts can turn as one. The timeline loops after duration seconds (default 12).
Keyframes replace the base transform over time; behaviours are applied on top. Each channel (position, rotation, scale, emissive) is interpolated between the keys that define it, with ease set to smooth (eases in and out at each key), linear, spline (a smooth curve through all keys, good for flight paths) or step:
{ "id": "obj_3", "animation": { "ease": "spline", "keys": [
{ "t": 0, "position": [0, 2, 0] }, { "t": 3, "position": [4, 3, 1], "rotation": [0, 90, 0] }, { "t": 6, "position": [0, 2, 0] } ] } }A camera path works the same way for yaw, pitch, distance and target: set_animation({ camera: { keys: [{ "t": 0, "yaw": 0 }, { "t": 12, "yaw": 360 }], ease: "linear" } }) is a turntable. set_keyframe adds one key at a time, for objects or for "camera".
Agents check the motion with render_animation (one contact sheet with several frames) or render_view({ time: 2.5 }). The CLI renders stills and GIFs:
cpu3d render examples/watch.json still.png --time 2.5
cpu3d gif examples/city.json city.gif --width 480 --height 300 --fps 15 --seconds 6GIFs are rendered in high quality with motion blur (each frame averages several samples spread over the shutter time), one stable palette for the whole clip and delta frames, so a mostly static shot stays small. Every gallery scene is animated: the watch ticks under a slow camera move, the turbofan spins, the station rotates, a blimp flies a keyframed spline loop around the city while the beacons blink, and the lighthouse lantern pulses while a boat rocks on the sea.
The editor
Live sync over Server-Sent Events: agent changes appear instantly, with an activity feed that attributes each step to its agent (
claude-code,cursor,you, ...)Follow agent: the viewport jumps to whatever the agent is looking at with
render_viewClick to select (CPU ray picking), then drag the selected object with the mouse to move it on the ground; hold Alt to move it up/down, Shift to snap to a 0.25 m grid. Each drag is one
update_objectcall, so it is undoable and visible to agentsOutliner, inspector (transform, material, editable JSON recipe), undo/redo
New scene (File menu,
Shift+N, or the top of the gallery): an empty stage with ground grid, or a ready photo studio with podium and softboxesTimeline: animated scenes play automatically; play/pause and scrub at the bottom of the viewport, with diamonds for the keys of the selected object (or of the camera path)
Keyframing:
◆orKrecords the selected object's pose at the current time (with nothing selected: the view as a camera path key). Once an object has keys, moving it or editing its transform sets a key at the current time.🎥toggles following the camera path; orbiting the view leaves itThe inspector has animation presets (spin, swing, bob, pulse) and a JSON field for behaviours and keys
Effects button (
E): shows or hides everything marked as an effect ("effect": trueon an object: airflow, rain, fireworks); a view setting, the scene stays unchanged.render_view({ effects: false })does the same for agentsExport animated GIF (File menu): rendered in the browser with motion blur, with size, frame rate, clip and camera options
Gallery of example scenes; add menu with presets; OBJ and scene JSON import/export
Size readouts: what the scene weighs as
scene.jsonand as.obj, geometry RAM, and the same for the selected object; load and download times and sizes are reported tooHigh quality rendering with shadows and ambient occlusion that refines itself when the view is still, or Fast mode
Orbit / pan / zoom, smooth, flat and normal shading, wireframe, resolution: Auto (full Retina resolution when still), 0.5×, 1×, Retina
Local mode: without a server (for example on GitHub Pages) the same tools run in the browser
Mouse: drag rotate · shift/right-drag pan · wheel zoom · click select · drag selected object to move (Alt up/down, Shift snap)
Keyboard: Space play/pause · K keyframe · E effects on/off · Shift+N new scene · F focus · W wireframe · Del delete · Ctrl/Cmd+Z undo · Shift+Ctrl/Cmd+Z redo · Ctrl/Cmd+D duplicate · Esc cancel move / deselect
Rendering on the CPU
Both images were rendered by the CLI, for example cpu3d render examples/lighthouse.json out.png.
The pipeline is the same one a GPU runs, written out in JavaScript:
Mesh culling with bounding spheres against the six frustum planes
Vertex stage: model-view-projection, outcodes, projection onto a 1/16 sub-pixel grid
Primitive stage: trivial reject, homogeneous Sutherland-Hodgman clipping only against near/far and a guard band, back-face culling by signed area
Rasterization: half-space edge functions in exact integer math with the top-left fill rule, per-row spans solved analytically (no per-pixel inside tests), attributes as plane equations (one add per pixel), 1/w depth buffer
Two quality modes
High (default) | Fast | |
Lighting | per pixel (deferred G-buffer), linear color space, extra fill/rim lights | per vertex (Gouraud) |
Materials | metalness, roughness, Fresnel reflections of a sky or studio environment, textures | color only |
Shadows | directional shadow map, adjustable soft edges, cached per scene | none |
Ambient occlusion | screen-space AO, half resolution, depth-aware blur | none |
Tone mapping | ACES filmic + sRGB | ACES filmic + sRGB |
Anti-aliasing | temporal (TAA) while things move, progressive averaging of jittered frames when the view is still | none |
Threads | the whole frame on all cores: vertex stage, rasterization, shadows, AO, lighting, anti-aliasing (Web Workers / worker_threads, shared memory) | one |
Left: the first release (fast mode). Right: high quality. Same scenes, same recipes.
The Smartphone scene before and after metal and glass materials, studio softbox reflections, a textured display, squircle bodies and camera details. Close-up of the camera module: docs/phone-camera.png.
Multi-threaded, temporal, adaptive
All cores: the main thread only builds the draw list (well under a millisecond); a pool of render threads does the rest over
SharedArrayBuffers: vertex stage, triangle binning, rasterization in interleaved row bands, shadow maps of moving objects, AO, lighting, atmosphere and anti-aliasing. One message per thread and frame, barriers in shared memory, work claimed from atomic counters so no core idles, and a fallback to one thread if a thread fails. The result is pixel-identical to one thread. The cpu3d server sends the cross-origin isolation headers this needs; on GitHub Pages a tiny service worker (coi-sw.js) adds them. Without isolation the editor falls back to one thread.Temporal anti-aliasing while orbiting, zooming or playing an animation: every frame is jittered, the previous result is reprojected with motion vectors (Catmull-Rom sampling), clipped to the variance of the current neighbourhood and blended in: as a running average while a pixel stays put (no flicker), faster when it moves. Animated objects bring their own motion vectors. Edges, AO and soft shadows stay smooth in motion instead of shimmering.
Seamless refinement: when the view stops, the progressive 16-sample average starts from the temporal history, so there is no drop in quality.
Adaptive resolution: if a full frame would take longer than about 34 ms, motion is rendered at a reduced resolution (down to 40%) and scaled up; the still image is always full resolution.
Shadow cache: static objects go into a cached shadow map shared by all renderers; during an animation only the moving objects are drawn again.
Turbofan, 900×852 in the editor (Apple Silicon, 8 worker threads) | Before | Now |
Frame while orbiting or playing (with TAA) | ~110 ms | 24 ms |
GIF export, 45 frames × 6 samples, 560×350 | 12.7 s | 5.7 s |
Frame with TAA, 960×540, 8 threads (Node, Apple Silicon) | Triangles | Shading on threads only | Whole frame on threads |
Seagrass meadow (first version) | 463k | 105 ms | 39 ms |
Neon district | 29k | 42 ms | 21 ms |
Fairground at dusk | 98k | 23 ms | 16 ms |
Skeleton watch | 33k | 24 ms | 17 ms |
The editor refines the image up to 16 samples when the camera stops; render_view returns 8-sample renders to agents.
Scene (1280×720, one core, Node 23, Apple Silicon) | Triangles | Fast | High (1 sample) |
Showcase | 23k | 3.3 ms | 33 ms |
Terrain | 97k | 7.5 ms | 45 ms |
Stress test (36 torus knots) | 224k | 16.5 ms | 47 ms |
The fast path pushes about 12 million triangles and up to 280 million pixels per second on a single thread. Coverage is verified pixel-exact against a brute-force reference in the test suite. Run npm run bench or open demo/ for the interactive benchmark; the details are in docs/how-it-works.md.
Use it as a library
import { Renderer, Camera, Mesh, tube, paths, sweep, shapes } from 'cpu3d';
const renderer = new Renderer({ canvas: document.querySelector('canvas') }); // or { width, height } in Node
const knot = tube(paths.torusKnot(2, 3, 256, 1.5), 0.14, 12, { closed: true });
const column = sweep(shapes.star(6, 0.45, 0.28), paths.line([0, 0, 0], [0, 2, 0], 60), { twist: Math.PI });
const scene = { meshes: [new Mesh(knot, { color: [1, 0.55, 0.2] }), new Mesh(column, { position: [3, 0, 0] })] };
const camera = new Camera({ position: [0, 3, 8] });
renderer.quality = 'high'; // or 'fast'
renderer.render(scene, camera); // first sample
for (let i = 0; i < 7; i++) renderer.render(scene, camera, { accumulate: true }); // refine
// Node: renderer.pixels is an RGBA Uint8ClampedArrayProject layout
bin/cpu3d.js CLI: serve, mcp (stdio), render
server/ HTTP server (editor, SSE, REST, MCP Streamable HTTP), MCP protocol, PNG encoder
src/renderer.js the software rasterizer
src/geometry.js geometry builder: rims, lathe, sweep, extrude, ear clipping, OBJ
src/recipes.js JSON recipes -> geometry, validation, agent reference
src/document.js scene document, validation, undo/redo
src/tools.js the tool API used by agents and the editor
src/scene.js document -> renderable scene, camera, ray picking
editor/ the editor UI (vanilla JS, no build step)
demo/ interactive renderer benchmark
examples/ gallery scenes, thumbnails and build.mjs that creates them
test/ node:test suiteSecurity
The server binds to 127.0.0.1 and rejects requests whose Host or Origin is not localhost, which protects against DNS rebinding. Recipes are data, never code. See SECURITY.md.
Roadmap
Bloom for emissive surfaces, depth of field, glossy floor reflections
Path tracing mode for final renders (global illumination)
Bevels for box and extrude, crease angle for smoothing groups
Groups and hierarchy, boolean operations (CSG)
Textures with perspective-correct UVs
glTF export
Groups / parenting for keyframed assemblies, video (MP4/WebM) export
MCP resources for scenes and live notifications
Ideas and pull requests are welcome, see CONTRIBUTING.md.
License
MIT. Inspired by the procedural approach of the old Babylon.js GeometryBuilder extension.
This server cannot be deployed
Maintenance
Related MCP Connectors
Generate game-ready 3D models, textures, and audio from natural language, over MCP.
Create, inspect, validate, and save editable 3D building scenes with Pascal's hosted MCP server.
Generate, edit, and deploy immersive 3D/WebGL web projects from any MCP assistant.
Screenshot and HTML render MCP server for AI agents
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables AI assistants like Codex or ChatGPT to inspect and control a local Blender scene, including creating objects, editing materials, setting cameras and lights, rendering previews, and saving safe copies of .blend files.1MIT
- AlicenseBqualityDmaintenanceExposes procedural material and isometric terrain generation as MCP tools, allowing agents to create deterministic PBR textures and 2:1 isometric tiles from JSON recipes.121MIT
- AlicenseAqualityBmaintenanceMCP server that lets an LLM agent drive StableProjectorz, a 3D modeling app, by inspecting the loaded model, app state, viewport screenshots, and triggering UI actions via a loopback socket bridge.11MIT
- AlicenseNot gradedqualityAmaintenanceA local MCP server that lets coding agents turn conversational prompts into deterministic, re-runnable recipes for 3D objects, walkable worlds, and playable games, all stored on your own disk without API keys or cloud rendering. Those recipes can be edited in place and exported to the browser, Godot, Unity, Unreal, Blender, glTF/OpenUSD, or print-ready STL and 3MF at true scale.3Apache 2.0