LeCodesdocs

Scene

A 3D world: a draw set, a Camera, lights and environment. Opening a scene brings up the host's 3D engine — only the active scene renders and receives pointer events. For a camera-feed AR session, use ARScene (a subclass).

At a glance

TypeScript
const scene = new Scene({ skybox: '#202030', bloom: true })
scene.add(
  Light.sun({ shadowsQuality: 2 }),
  Mesh.box({ material: Material.lit({ color: '#e33' }), position: [0, 0.5, -2] }),
)
scene.camera.position = [0, 1.5, 2]
scene.open()

scene.addEventListener('click', ev => {
  console.log('hit', ev.target?.name ?? 'nothing')
})

Creating

TypeScript
new Scene(options?: {
  ibl?: boolean                    // image-based ambient lighting; default true
  environmentIntensity?: number    // IBL intensity; default 20000
  bloom?: boolean                  // bloom post-processing; default false
  bloomIntensity?: number          // bloom strength; default 0.2 (only with bloom: true)
  skybox?: ColorInput              // solid background / clear color
  antialias?: boolean              // 4× MSAA; default false
})

Lighting is explicit: IBL gives every scene ambient light by default (turn ibl: false if you light it entirely yourself); add a Light.sun() for direct light and shadows.

Note

options are constructor-only except the background (scene.skybox = … setter) and antialiasing (setAntialias). There is no runtime toggle for ibl or bloom.

Adding & removing nodes

TypeScript
scene.add(...nodes: Node[]): this
scene.remove(...nodes: Node[]): this

Registers nodes with this scene's draw set. This is distinct from parentingnode.add(child) builds the hierarchy (see Node); scene.add(node) puts it in the world.

Opening & closing

TypeScript
scene.open(): void        // become the active scene (closes any other)
scene.close(): void       // tear down the 3D view
Scene.active              // static: the currently active Scene, or null

Only one scene is active at a time; open() on a second scene replaces the first. After close(), Scene.active is null (if this was the active one). ARScene.open() is async — see ARScene.

Overlays

TypeScript
scene.createOverlay(options?: SceneOptions): Scene

A second scene drawn on top of this one, sharing its camera — a 3D HUD layer that always renders over the parent's content. Takes the same options as the constructor; add nodes to it like any scene. It renders with its parent — don't open() it separately.

warmRender

TypeScript
scene.warmRender(): Promise<void>

Renders the scene once so shaders compile and resources upload before it's shown. If the first visible frame hitches, await scene.warmRender() during a loading screen, then open(). (ARScene.open() does this automatically.)

Rendering knobs

TypeScript
scene.skybox = '#87ceeb'                                  // background color (set only)
scene.setAntialias(enabled: boolean, scale = 4): void     // MSAA on/off + sample count
scene.occlusionMaterial: Material                         // the scene's occlusion material (read-only)
scene.setMaterialGlobalParameter(i, x, y, z, w): void     // scene-wide vec4 slot i, read by custom shaders

occlusionMaterial is a Material instance — set its uniforms like any other.

Note

occlusionMaterial is host-gated: the web viewer does not implement it (accessing it throws). Use it only on AR-capable native hosts.

Scene-level pointer events

TypeScript
scene.addEventListener('click', (ev: ClickEvent<Node | null>) => void): void
scene.addEventListener('touchstart', (ev: TouchStartEvent<Node | null>) => void): void
scene.removeEventListener(channel, callback): void

Scene listeners fire for every tap on the active scene; ev.target is the hit Node (one with a Shape pick body) or null for a miss. Individual nodes can also listen — see Node events and Pointer events & gestures.

VRScene

TypeScript
const scene = new VRScene(options?: SceneOptions)
await scene.open()   // rejects on hosts without a VR runtime ("VR is not supported on this device")
scene.close()

A Scene subclass rendered in a VR headset (OpenXR — e.g. Meta Quest). The headset drives the camera: both eyes render from the tracked head pose every frame, so scene.camera position / lookAt have no effect while the scene is open. The world origin is at floor level (stage space) — author content with the ground at y = 0 and the user standing at the origin. Everything else (nodes, lights, materials, aspects) works exactly as in a regular Scene.

See also

  • ARScene — AR session: async open, anchors, placement controls
  • Camerascene.camera: fov, screen rays
  • LightLight.sun() for direct light + shadows over the IBL ambient
  • Node — transform, hierarchy, events
  • Material — what occlusionMaterial and mesh materials expose