ARScene
A Scene rendered over the device camera feed with world tracking — everything from
Scene (options, add/remove, events, overlays) applies. What it adds: an async open()
that requests the camera and starts tracking, anchor nodes that follow the real world, and
ready-made object-placement gestures via addControls.
At a glance
const scene = new ARScene()
const model = await Model.load(asset('./chair.glb'))
scene.root.add(model)
scene.add(model)
const controls = scene.addControls(model) // drag / pinch / twist to place it
await scene.open()
model.addEventListener('track', () => console.log('anchored to the world'))Creating & opening
new ARScene(options?: SceneOptions & {
mode?: 'default' | 'markers' | 'arcore' | 'detached' // tracking mode; default 'default'
})
scene.mode // read-only: the mode it was created with
scene.useWarmRender = true // open() pre-warms shaders first (default true)
await scene.open(): Promise<void> // request camera → warm render → launch AR → become active
scene.close(): void // stop the AR session and tear down the viewopen() is asynchronous — it asks for camera permission, warm-renders (when useWarmRender is
on), and launches tracking before the scene becomes active. It rejects if the camera is denied
or AR can't launch, so await it and handle failure.
Anchors
scene.root: Node // world root anchor (read-only)
scene.createAnchor(source: FetchResponse, physicalWidth = 0.2): Node // image-target anchorAn anchor is a Node whose transform is driven by tracking — parent your content under
it. root is the world origin anchor; createAnchor makes one that follows a tracking source
(e.g. an image target fetched with fetch), with physicalWidth the target's real-world width in
meters (default 0.2).
Anchor nodes report tracking state:
anchor.addEventListener('track', () => {}) // began tracking
anchor.addEventListener('untrack', () => {}) // lost tracking
anchor.isTracked // current state (false for non-anchor nodes)root is not available in 'markers' mode. Anchor support is host-gated — the
web viewer does not implement createAnchor.
Placement controls — addControls
scene.addControls(target: Node, options?: {
minScale?: number // smallest uniform scale the pinch allows; default 0.08
maxScale?: number // largest; default 2
pan?: boolean // one-finger drag; default true
pinch?: boolean // two-finger scale; default true
twist?: boolean // two-finger rotate; default true
}): { remove(): void }The staple AR object-placement interaction, prebuilt:
- One finger drags the target across the ground plane, relative to where the camera looks (screen-up moves it away from you). Height (world Y) stays fixed.
- Two fingers pinch to scale (uniform, clamped by
minScale/maxScale) and twist to rotate the target around its Y axis.
Built entirely on the public touch API (scene touchstart + ev.track) — it's a convenience, not
a primitive. Call .remove() on the returned handle to detach the listeners.
the pinch clamp allows slight overshoot past the stated bounds — the effective range
is [minScale × 0.4, maxScale × 1.5].
See also
- Scene — everything inherited: options, add/remove, overlays, warmRender, events
- Node —
track/untrackevents,isTracked, hierarchy - Model — loading the GLB you're placing
- Pointer events & gestures — the touch surface
addControlsis built on