Three.js effect
threeEffect connects Motion’s animation engine to Three.js objects, materials, and uniforms. Register it once, then use the same animate() API you use for DOM elements and plain objects.
import { animate } from '@humanspeak/svelte-motion'
import { threeEffect } from '@humanspeak/svelte-motion/three'
animate.addEffect(threeEffect)
animate(mesh, { x: 1.5, rotateY: 360 }, { type: 'spring' })import { animate } from '@humanspeak/svelte-motion'
import { threeEffect } from '@humanspeak/svelte-motion/three'
animate.addEffect(threeEffect)
animate(mesh, { x: 1.5, rotateY: 360 }, { type: 'spring' })Register at module scope rather than from a component. The effect registry is global and does not reference-count, so removing threeEffect when one component unmounts would unregister it for every other component still animating a mesh. See custom effects for the full rule.
Supported subjects and values
The adapter claims the following Three.js-shaped subjects without importing three itself:
| Subject | Animated values |
|---|---|
Object3D (meshes, cameras, lights) | x, y, z, rotateX, rotateY, rotateZ, scaleX, scaleY, scaleZ, and scale |
| Materials | Direct properties and colour keys such as color, emissive, and specular |
| Uniforms objects | Any { key: { value } } entry, including vector components such as offsetX |
| TSL uniform nodes | Uniform-node values assigned to slots such as material.colorNode |
Rotation shorthands — rotateX, rotateY, and rotateZ — are in degrees. They are converted to radians on write, like DOM rotate, so a full turn is 360, not Math.PI * 2.
Shader uniforms
Bind a MotionValue directly to a uniforms object when you want to control it independently from the mesh:
import { animate, motionValue } from '@humanspeak/svelte-motion'
import { threeEffect } from '@humanspeak/svelte-motion/three'
const progress = motionValue(0)
const uniforms = { progress: { value: 0 } }
const unbind = threeEffect(uniforms, { progress })
animate(progress, 1, { duration: 1 })
// When the integration is no longer active:
unbind()
progress.destroy()import { animate, motionValue } from '@humanspeak/svelte-motion'
import { threeEffect } from '@humanspeak/svelte-motion/three'
const progress = motionValue(0)
const uniforms = { progress: { value: 0 } }
const unbind = threeEffect(uniforms, { progress })
animate(progress, 1, { duration: 1 })
// When the integration is no longer active:
unbind()
progress.destroy()Frame timing
threeEffect writes values in frame.preRender. Schedule the Three.js render loop with frame.render so every object transform and uniform update lands before the frame is drawn.
import { cancelFrame, frame } from '@humanspeak/svelte-motion'
const render = () => renderer.render(scene, camera)
frame.render(render, true)
// On cleanup, stop the render loop and release any values you bound.
// Leave the effect registered: the registry is global and shared.
cancelFrame(render)
unbind()import { cancelFrame, frame } from '@humanspeak/svelte-motion'
const render = () => renderer.render(scene, camera)
frame.render(render, true)
// On cleanup, stop the render loop and release any values you bound.
// Leave the effect registered: the registry is global and shared.
cancelFrame(render)
unbind()Related
- Custom effects — create and register adapters for other non-DOM subjects
- Three.js effect example — spring a mesh and ripple its shader with complete source
Based on Motion 13.2’s motion/three.