useThree gives you the three.js context from inside a <Canvas> — the renderer, scene, camera, raycaster, and more.
Signature
// The full context objectuseThree(): Context
// A reactive accessor for one derived valueuseThree<T>(selector: (context: Context) => T): Accessor<T>Call it with no arguments for the whole context. Pass a selector to derive a single value reactively:
const camera = useThree(context => context.camera)// camera() is an Accessor<Camera>Returns
| Property | Type | Description |
|---|---|---|
bounds | Measure | Reactive canvas bounds measurement. |
viewport | Viewport | Viewport measurements — width, height, top, left, plus factor, distance, and aspect. |
camera | CameraKind | The current camera (PerspectiveCamera | OrthographicCamera). |
setCamera | (camera: CameraKind) => () => void | Push a camera onto the stack, making it active. Returns a cleanup that pops it. Accepts only a PerspectiveCamera or OrthographicCamera. |
canvas | HTMLCanvasElement | The canvas DOM element. |
clock | Clock | The three.js clock, for timing. |
dpr | number | Device pixel ratio of the active renderer. Falls back to 1 for renderers without getPixelRatio (e.g. CSS3DRenderer, SVGRenderer). |
gl | Meta<ResolvedRenderer> | The active renderer, wrapped with meta so you can read solid-three metadata via getMeta(three.gl). Narrow it project-wide with Register augmentation. |
raycaster | Raycaster | EventRaycaster | The current raycaster used for pointer events. |
setRaycaster | (raycaster: Raycaster) => () => void | Push a raycaster onto the stack. Returns a cleanup that pops it. |
render | (timestamp: number, frame?: XRFrame) => void | Render one frame now. Pass a timestamp (e.g. performance.now()); the optional XRFrame is forwarded to useFrame callbacks. This is the per-frame primitive you hand to gl.setAnimationLoop when driving a WebXR session. |
requestRender | () => void | Request a render on the next frame. Skipped while an XR session is presenting (the session owns the loop). |
scene | Meta<Scene> | The root scene, wrapped with meta. |
props | CanvasProps | The props the host <Canvas> was rendered with. |
Behavior
The camera and raycaster are each managed as a stack. The camera and raycaster from <Canvas> props sit at the bottom; whatever is on top is the active one that three.camera / three.raycaster return.
setCamera and setRaycaster push a new one onto the stack, making it active, and return a cleanup that pops it back off — restoring the previous one. Pair the cleanup with onCleanup so the previous camera or raycaster comes back when your component unmounts.
WebXR
solid-three does not manage XR sessions for you — entering and exiting a session is the consumer's job. For almost all cases, reach for createXR, which handles the session-ordering rules for you.
If you need to drive the renderer directly instead, the rule to remember is: install the render callback before setSession runs.
const { gl, render } = useThree()
// enter XRgl.setAnimationLoop(render) // must be set before setSessiongl.xr.enabled = trueconst session = await navigator.xr.requestSession("immersive-vr")await gl.xr.setSession(session)
// exit XRgl.setAnimationLoop(null)gl.xr.enabled = falseWhile a session is presenting, the renderer's own loop (driven by the headset) owns rendering, so solid-three's window loop steps aside automatically. The same code works for both WebGLRenderer and WebGPURenderer. For XR with WebGPURenderer on three ≤ r184, construct it with { forceWebGL: true }.
Examples
Switching to an orthographic camera while a signal is set, and restoring the previous one on cleanup:
const three = useThree()const [useOrtho, setUseOrtho] = createSignal(false)
createEffect(() => { if (useOrtho()) { const orthoCamera = new OrthographicCamera(-5, 5, 5, -5, 0.1, 1000) orthoCamera.position.set(0, 0, 5)
const restore = three.setCamera(orthoCamera) onCleanup(restore) }})See also
<Canvas/>— sets the default camera, raycaster, and scene this hook reads.- Raycasters — the raycaster types
setRaycasteraccepts. - Metadata — reading solid-three metadata off
glandscene.
Last updated: 6/8/26, 11:20 AM