threesmith.
v0.3.0 · Made for three.js

A little less guessing. A lot more creating.

Less debugging.
More dimension.

Your agent brings the ideas. Threesmith checks the three.js, inspects the scene, and helps you make something worth exploring.

$npx -y threesmith doctor

Local. Open source. MIT licensed. Yours to build with.

The creation space01 / ROBOT
Friendly orange-and-white robot built by Threesmith
Say hello to possibility.

Real output of model build robot --param scheme=1 -o robot.glb

Real Threesmith model · interactive preview optional

One toolkit. Your favorite agent.Claude CodeCodexCursorVS CodeAny MCP client

FROM FIRST IDEA TO LAST FIX

A creative partner.
With a reality check.

Keep your flow. Give your agent the installed API, a second pair of eyes, and an actual browser to check its work.

01 / KNOW

The right API.
For your version.

No invented methods. Look up the three.js release installed in your project, with signatures and the right import paths.

Explore the tools
02 / CHECK

See what
actually happens.

Run the page headless. Find broken assets, shader errors and black canvases, then inspect the live scene.

Look inside the check
03 / MAKE

Something from
a few lines of code.

Build, view and lint 110 kinds of 3D models as clean .glb files, with a named node for every part.

Meet the models

A REAL SCENE. A REAL DIFFERENCE.

Good ideas deserve
more than a black canvas.

The same example, before and after the fixes. Move the slider to compare the actual renders.

Fixed scene: a lit crate and character model
Original scene: a black canvas
BeforeAfter

As the agent wrote it. 3 review errors, 2 asset paths that 404, a black canvas.

After fix + doctor’s list. Review 100/100, check passes, every asset loads.

Real run on examples/agent-mistakes. Mechanical fixes plus the manual fixes listed by doctor; not an automatic one-click repair.

Read the actual diagnostic output

THE NEXT STEP, MADE CLEAR

A diagnosis.
And a way forward.

The scene in the comparison, as a coding agent wrote it (examples/agent-mistakes). three_doctor reads the files, groups the problems by cause, most urgent first, and says which ones three_fix does by itself. Real output, unedited:

Read the full doctor report
threesmith doctor
Threesmith doctor: 5 error(s), 8 warning(s), review 73/100 (C), three r187, none (import map / CDN)

1. ✖ Why the scene shows nothing (or nothing right) (1): nothing else can be judged while the picture is black or empty
   [add-gltf-result] main.js:27
     GLTFLoader hands over an object holding scene, animations and cameras, not an Object3D: scene.add(gltf) logs "object not an instance of THREE.Object3D" and the model never shows. Fix: scene.add( gltf.scene );

2. ✖ Assets that will not load (2): a missing or mis-cased file is a 404, which the loader reports as a parse error far from the cause
   [asset-missing] main.js:22
     "/textures/crate.jpg" is not in the project (looked in public/textures/crate.jpg, textures/crate.jpg). The server answers with an HTML page, which the loader then fails to parse ("Unexpected token '<'"). Fix: Add the file under public/ (served at /), or fix the path.
   [asset-case] main.js:26
     "/models/Robot.glb" only matches public/models/robot.glb with different capitals: it loads on macOS and Windows and is a 404 on Linux servers and most hosts. Fix: Write the path exactly as the file is named (/models/robot.glb), or rename the file.

3. ✖ Outdated or removed three.js API (3): removed names throw or silently do nothing in the installed release
   [buffer-geometry-alias] main.js:18 (three_fix)
     `BoxBufferGeometry` and friends were renamed; the plain name is the BufferGeometry now.
   [addons-path] x2 index.html:8, main.js:3 (three_fix)
     `three/examples/jsm/...` still works, but `three/addons/...` is the documented path and the one import maps use.

4. ✖ Colours (2): wrong colour spaces make everything look washed out or too dark
   [output-encoding] main.js:7 (three_fix)
     `outputEncoding` was replaced by `outputColorSpace`.
   [texture-colorspace-missing] main.js:23
     Textures loaded with TextureLoader are used as color maps but `colorSpace` is never set, so colors look washed out or too dark. Fix: texture.colorSpace = THREE.SRGBColorSpace; (not for normal/roughness/metalness data maps).

5. ▲ Code that runs but does the wrong thing (4): these are bugs the user will see
   [controls-no-element] main.js:15
     Controls created without a DOM element listen to nothing (since r175 they need one), so mouse and touch do nothing. Fix: new OrbitControls( camera, renderer.domElement ), or call controls.connect( element ) later.
   [controls-damping-no-update] main.js:16
     `enableDamping` only works when controls.update() runs every frame. Fix: Call controls.update() inside the animation loop.
   [rotation-degrees] main.js:19
     Rotations are in radians; 45 here is about 7 turns, not 45 degrees. Fix: Use radians: THREE.MathUtils.degToRad( 45 ) (Math.PI / 4).
   [clip-action-unused] main.js:29
     clipAction() only creates the action; nothing plays until .play() is called on it. Fix: mixer.clipAction( clip ).play();

6. ▲ Performance (3): work per frame and GPU memory decide whether it runs smoothly on a phone
   [pixel-ratio-uncapped] main.js:8 (three_fix)
     `setPixelRatio(devicePixelRatio)` renders up to 9-16x the pixels on high-density screens.
   [alloc-in-loop] main.js:34
     A Vector/Matrix/Quaternion/Color is created with `new` inside the per-frame loop. That produces garbage every frame and causes stutter from garbage collection. Fix: Create the object once outside the loop (const _v = new THREE.Vector3()) and reuse it with .set()/.copy().
   [animation-loop] main.js:33
     `renderer.setAnimationLoop` is the supported loop: it also runs in WebXR and pauses correctly. Fix: renderer.setAnimationLoop((time) => { ...; renderer.render(scene, camera); });

7. ▲ Resize and cleanup (1): leaks and stretched views show up after the first minutes of use
   [no-resize-handling] main.js:6
     A renderer and camera exist but nothing reacts to a resize (no resize listener or ResizeObserver). Fix: On resize: camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setSize(w, h);

Next:
  1. Call three_fix (dry run), then three_fix write: true for the mechanical renames.
  2. Fix the asset paths (three_assets lists every reference and where it was looked for).
  3. Fix the 'shows nothing' group first, then confirm with three_check (screenshot) or three_inspect (why objects are not visible).
  4. Fix the remaining 1 error(s) by hand; three_api gives the exact names for the installed release.
  5. Call three_review with only_new: true after each change, until no errors are left.
  6. Run three_check on the page (index.html) before you call it done.

BEYOND THE SOURCE CODE

Then it opens
the actual page.

A review reads text. three_check runs the page in headless Chromium with software WebGL 2 (it works in CI) and reports what a user would see: page and console errors with their cause, failed requests, blank frames, and a screenshot. When the frame is blank, the scene inspector reads the live scene through three's devtools hook and says why nothing shows.

threesmith fix
Would fix 5 place(s) in 2 file(s) (add --write to apply):
  index.html: 1 (addons-path)
  main.js: 4 (addons-path, buffer-geometry-alias, output-encoding, pixel-ratio-uncapped)
Run `threesmith review` again; the rest needs a decision.
threesmith check
Threesmith check: FAIL – http://127.0.0.1:5173/examples/agent-mistakes/index.html
canvases 1 · contexts webgl2 · frames 0 · three r187
✖ [page-error] THREE.BoxBufferGeometry is not a constructor
    why: The class was removed or renamed (Geometry, Face3, *BufferGeometry), or it is an addon used as THREE.X without importing it.
    fix: Use the current name and import addons explicitly. three_api tells whether it exists and where.
    `BoxBufferGeometry` does not exist in three r187. Did you mean `BufferGeometry`?
✖ [blank] The screenshot is 100.0% one color: nothing visible was drawn (no lights, camera inside the object, or nothing added to the scene?).
✖ [scene] The renderer exists but render() was never called. Fix: Call renderer.render(scene, camera) every frame, for example in renderer.setAnimationLoop(...).
✖ [scene] No camera was found for the scene. Fix: Create a PerspectiveCamera and pass it to renderer.render(scene, camera).
✖ [scene] The rendered scene has no meshes, points, lines or sprites. Fix: Add your objects with scene.add(object) (for loaded models: scene.add(gltf.scene) inside the load callback).

Why it may not look right:
✖ [never-rendered] The renderer exists but render() was never called.
    fix: Call renderer.render(scene, camera) every frame, for example in renderer.setAnimationLoop(...).
✖ [no-camera] No camera was found for the scene.
    fix: Create a PerspectiveCamera and pass it to renderer.render(scene, camera).
✖ [empty-scene] The rendered scene has no meshes, points, lines or sprites.
    fix: Add your objects with scene.add(object) (for loaded models: scene.add(gltf.scene) inside the load callback).

WebGLRenderer: canvas 800x600 @1, 0 draw calls, 0 triangles, 0 geometries, 0 textures, 0 shader programs

Scene graph (1 objects, 0 meshes, 0 lights):
Scene
screenshot: ./examples/agent-mistakes/.threesmith/last.png

Your agent, without and with Threesmith

Each row is a mistake coding agents make in three.js projects, and the tool that catches it.

Your agent…On its ownWith Threesmith
writes three.jsGeometry, outputEncoding, examples/js: old habits97 rules pinned to the installed release, each with the fix; three_fix does the pure renames, undoable
calls an APIguesses a name or import path from memorythree_api reads node_modules/three: signature, deprecation, the right three/addons/… path
writes a shader#include <encodings_fragment>, a patch on a chunk that is goneincludes checked against the installed ShaderChunk; patches that silently do nothing found
loads a model/models/Robot.glb: works on a Mac, 404 on the serverthree_assets resolves every path like the host does; names missing Draco, meshopt and KTX2 setup
says "it works"never opened the pagethree_check: errors with causes, blank frames, screenshots, baselines with a diff
fixes a bugcannot show it was there, or that it is gonethree_play judges claims frame by frame; three_scenario keeps it as a regression test
makes it fastchanges things and hopesthree_perf: draw calls, triangles, programs against a budget; three_leaks: what is never disposed
ships itbuilds, deploys, sees a 404three_build: copies of three, missing assets, sub-path URLs, then the built page headless
needs a 3D modela placeholder cubethree_model_build: a clean .glb from 110 kinds, shown as text views, linted

31 MCP tools, one CLI

Load the sets you need: --tools core,run. Most tools are also CLI commands (threesmith <command> --help).

core

  • three_doctor what is wrong, in order
  • three_scan the project map
  • three_api · three_search installed API
  • three_review 97 rules, 0-100
  • three_types tsc, answered for three
  • three_fix · three_undo
  • three_explain cause of a message
  • three_lessons · three_lesson_add
  • three_rules · three_feedback · three_version

run

  • three_check headless page, screenshot
  • three_inspect why objects are invisible
  • three_play steps, watch, claims
  • three_scenario regression tests
  • three_perf draw calls, budgets
  • three_leaks what grows per cycle

live

  • three_session a page kept open
  • three_page eval, steps, screenshots

build

  • three_assets paths, case, decoders
  • three_build the deployed output

model

  • three_model_brief · three_model_identify
  • three_model_spec · three_model_build
  • three_model_view text views
  • three_model_lint · three_model_inspect

A SMALL START. A WHOLE WORLD OF POSSIBILITIES.

Make your next
“what if” tangible.

110 ready-made model kinds. Clean .glb files. No Blender needed. These are actual Threesmith models, rendered by three.js.

Explore all 110 kinds From a JSON spec to a model you can make your own.

READY WHEN YOU ARE

A new tool.
A better creative flow.

Node.js 22.12+ and three in your project. Browser checks also need Chromium and playwright-core; threesmith doctor --env shows what is missing.

Start with a diagnosis of the current project.

npx -y threesmith doctor
All clients and one-click installs

Honest limits

  • WebGL 2 in headless Chromium is reliable, also in CI. WebGPU is best effort.
  • Frame times come from software rendering: compare before and after. Draw calls and triangles are exact.
  • The review reads text, not types (three_types adds the type checker). It can be wrong; mark it with three_feedback.
  • No benchmark results are published yet; bench/ has the tasks and the grader.

A FEW THINGS YOU MIGHT WONDER

Good questions.
Clear answers.

Does it need a GPU or a browser window?

No. Most tools read files. The browser tools use headless Chromium with software WebGL 2, which also runs in GitHub Actions.

Which three.js version does it check against?

The one in your node_modules/three. A rule knows the release that removed or renamed an API, so the same line is an error on a new release and a warning on an old one, and a rule whose replacement does not exist yet in your release stays quiet.

Does it work with React Three Fiber?

Yes: rules for useFrame (state set every frame, allocations), objects created in render and render priority, and rules R3F handles itself (dispose, colour space) are skipped.

Does it send my code anywhere?

No. There is no telemetry. Lessons and false-alarm feedback stay in ~/.threesmith, scrubbed of names, paths and code.

Is there one for Godot?

Yes: Godotwright is the same toolkit for Godot 4. Threesmith follows its design.

MADE BY LAAIELICHTER. BUILT IN THE OPEN.

The next dimension
is yours to make.

Bring your ideas. Give your agent the right tools.

Find it useful? A GitHub star is always welcome.