Skip to main content

A scene in solid-three is a reactive view over a three.js graph. Anything that drives a Solid component also drives the scene — and the easiest way to see that is to hand a prop a signal.

Click the button repeatedly. The counter at the top says "App body has run: 1 time" — and it stays at 1, no matter how often you click. The component's body runs once. Only the small reactive expression that reads hot() re-runs, and all it does is hand a new value to material.color.set(...). The mesh stays mounted, the canvas keeps the same renderer, nothing else moves.

That's the through-line. The rest of this chapter is just what props you can pass.

Transforms

A three.js scene is a tree. Every object has a parent and a (possibly empty) list of children — in solid-three, that tree is your JSX. Nest one element inside another and you've made a parent-child relationship in the scene.

Every object accepts three transform props:

  • position={[x, y, z]}
  • rotation={[x, y, z]} (radians)
  • scale={[x, y, z]} (or a single number — scale={2} doubles every axis)

Composing transforms

When you nest, transforms compose. A child sits in its parent's frame: the parent's position, rotation, and scale all apply first, then the child's on top.

T.Group is the empty container you reach for when you want to move several things together without a visible mesh of their own.

Same two cubes, but now they sit inside a <T.Group> that's rotated. The rotation applies to the group's frame, so both cubes tilt together — including their positions, which now swing slightly toward and away from the camera.

Rotate the group instead of the cubes any time you want the arrangement to move, not just the individual shapes. Almost every scene you'll build is some tree of groups holding meshes.

Constructor arguments: args

Not everything has a setter. BoxGeometry's width, height, and depth are constructor parameters — you set them when the geometry is born. For cases like this, pass an args array:

args is spread into the constructor: new BoxGeometry(...args). Change args and the geometry is rebuilt — which is what you want, since geometries and materials don't have setters for these fundamentals.

Why arrays work on a Vector3

You've been writing position={[0, 0, 3]} — but Mesh.position isn't an array, it's a Vector3. solid-three is forgiving about the shape of what you hand it: arrays unpack into .set(...), single numbers broadcast via .setScalar(...), strings and hex go through .set(...) on a Color, and so on.

The principle: pass whatever's most ergonomic for the shape of data you have. solid-three checks which setter the target supports — .set(...), .setScalar(...), or .copy(...) — and uses the first one that fits. The full conversion table — plus how attach, dashed paths like shadow-mapSize-width={1024}, and refs work — lives on useProps.

Next: every Solid control-flow primitive you already know — <Show>, <For>, <Switch>, <Index>, <Suspense> — works inside the scene the same way it works inside a <div>.

Last updated: 6/8/26, 11:20 AM

solid threeA SolidJS renderer for three.js — learn by reading.
Community
github