Skip to content

Your own three.js scenes

Mixture’s 3D scenes come with forms — flat, cylinder, sphere, extrude, shatter, device models. When the piece needs something those don’t cover (a particle field, a wall of cards each playing a slice of a video, a procedural product rig, a custom GLSL material), a scene layer can run a script: a three.js module that builds the geometry and poses it for every frame.

The rest of the layer stays exactly what it is. The camera, the lights and the studio environment are the scene layer’s own settings. The layer’s children reach the module as live textures, so a video keeps playing and a designed group keeps animating on whatever surface the script puts them. Scrubbing, stills and export all render the same pixels, because the module is asked for a frame at a time, never left to run on its own clock.

Not everything a script draws should be 3D. The same layer runs flat Canvas 2D and p5.js scripts — a chart that draws itself, a counter, a noise field behind real type — see Canvas and p5 scripts.

This is an agent feature first. Describe the idea and the agent writes the module, creates it as a script asset in the project and points a scene layer at it:

Make the product shot a wall of 12×7 cards that each show part of the screen recording, rippling gently as the camera drifts.

If a module fails, the agent sees the error in its own render check and fixes it. You can also upload a .js file as an asset yourself and pick it in the layer’s Form → Script menu.

Select the scene layer, set Form to Script, and choose the script asset. Any parameters the module declares (a // @param header, the same grammar as custom shader effects) appear as controls underneath — and can be animated through the layer’s paramAnimations, like a model’s settings. Errors from the module show in the same place.

Lighting, camera, spin and the environment work as for every other 3D form. The layer’s children can be selected on canvas wherever the script shows them.

A script never runs with your session. It executes in a sandboxed frame with no cookies, no storage and no network — it can only see the pixels and parameters Mixture hands it, and it can only hand back an image. A module that hangs is stopped and reported; it can’t take the editor with it.

The module contract, the world units, what you can import and two worked examples live in the agent guide — the same text agents read: get_docs(topic: "threejs"), or the threejs topic in the agent docs. The short version:

export default function build({ THREE, addons, items, params, size, random }) {
const group = new THREE.Group();
// build meshes; items[i].texture is a live layer texture
return {
group,
update({ time, params }) { /* pose everything from time */ },
dispose() { /* free what you made */ },
};
}

Three rules keep it a Mixture layer and not a web page: pose from time only (no animation loops, no clocks, no Math.random — use the seeded random), import only three and the listed addons (write anything else in the module), and return a group instead of creating a renderer or a camera.