name: sceneview-web
description: Build 3D and WebXR (AR/VR) experiences in the browser with SceneView for Web — Filament.js (WebGL2/WASM) wrapped in a Kotlin/JS DSL and a plain-JavaScript API on window.sceneview. Use whenever the user asks for "3D in the browser", "a web model viewer", "WebXR AR/VR", or any browser 3D/AR app where the dependency is the sceneview-web npm package or its CDN script. For Jetpack Compose use the sceneview skill; for SwiftUI use sceneview-ios. Skip for raw Three.js / Babylon.js / model-viewer / A-Frame work.
license: Apache-2.0
metadata:
author: SceneView
source: https://github.com/sceneview/sceneview
last-updated: '2026-06-04'
keywords:
- sceneview
- sceneview-web
- 3d
- web
- webxr
- webgl
- wasm
- filament
- filament.js
- model viewer
- augmented reality
- virtual reality
- kotlin/js
- gltf
- glb
What SceneView for Web is
SceneView for Web is the browser half of the SceneView SDK. It renders with Filament.js — the same Filament engine as SceneView Android, compiled to WebAssembly + WebGL2. It ships two API surfaces:
Kotlin/JS DSL —
SceneView.create(canvas, configure = { … })with a type-safe builder, plusARSceneView/VRSceneView/WebXRSessionfor WebXR. This is the source-of-truth API; the package is built fromsceneview-web/src/jsMain/.Plain-JavaScript API — when loaded via a
<script>tag the library registers itself onwindow.sceneview, exposingcreateViewer,modelViewer, etc. for use with no bundler and no Kotlin.npm package —
sceneview-web(currently4.18.0).Renderer — Filament.js (WebGL2/WASM). Requires Chrome 79+, Edge 79+, Firefox 78+, Safari 15+.
Authoritative API reference
Always treat llms.txt in the repo root as the source of truth — its
"SceneView Web (Kotlin/JS + Filament.js)" section carries the complete DSL,
the JS API, the WebXR ARSceneView / VRSceneView / WebXRSession surface,
and the threading rules.
https://github.com/sceneview/sceneview/blob/main/llms.txt
The Kotlin/JS source lives in sceneview-web/src/jsMain/kotlin/io/github/sceneview/web/
— SceneView.kt (the DSL + SceneViewBuilder), SceneViewJS.kt (the
JS-facing SceneViewer class), Main.kt (the window.sceneview bindings),
and xr/ (WebXR). The samples/web-demo/ app is a working reference.
When to use this skill
Trigger on any of:
- "Render a glTF / GLB model in a browser."
- "Build a web 3D viewer / product configurator."
- "Add WebXR AR or VR to a web page."
- "Embed a 3D scene with no build step / just a
<script>tag." - "Use SceneView from Kotlin/JS."
Skip for raw Three.js, Babylon.js, <model-viewer>, A-Frame, or PlayCanvas
work that does NOT use sceneview-web.
Setup — two ways
Script tag (no bundler)
filament.js MUST load before sceneview-web.js:
<canvas id="viewer" style="width:100%;height:100vh;display:block"></canvas>
<script src="https://sceneview.github.io/js/filament/filament.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sceneview-web@4.18.0/sceneview-web.js"></script>
<script>
sceneview.modelViewer('viewer', 'https://sceneview.github.io/models/platforms/DamagedHelmet.glb')
.then(function (sv) { sv.setAutoRotate(true); });
</script>
npm
npm install sceneview-web filament
The minimal correct example — plain JS
The JS API is registered on window.sceneview after the script loads.
Verified against Main.kt (jsModelViewer, jsCreateViewer):
// Simplest — creates a viewer and loads a model
sceneview.modelViewer('viewer', 'model.glb')
.then(function (sv) {
sv.setAutoRotate(true);
sv.setBackgroundColor(0.05, 0.05, 0.12, 1.0); // RGBA 0-1
sv.setEnvironment('studio_ibl.ktx');
});
// More control
sceneview.createViewer('viewer').then(function (sv) {
sv.loadModel('model.glb').then(function () { sv.fitToModels(); });
}).catch(function (err) {
// The Promise REJECTS if Filament fails to initialize — handle it,
// don't assume createViewer always resolves.
console.error('SceneView init failed', err);
});
SceneViewer instance methods (from SceneViewJS.kt): loadModel(url) →
Promise, setEnvironment, setEnvironmentWithSkybox, setCameraOrbit,
setCameraTarget, setAutoRotate, setAutoRotateSpeed, setZoomLimits,
setBackgroundColor, fitToModels, startRendering, stopRendering,
resize, dispose.
The minimal correct example — Kotlin/JS DSL
Verified against SceneView.kt (create, SceneViewBuilder):
SceneView.create(
canvas = canvas, // HTMLCanvasElement
configure = {
camera {
eye(0.0, 1.5, 5.0)
target(0.0, 0.0, 0.0)
fov(45.0)
}
light {
directional()
intensity(100_000.0)
direction(0.6f, -1.0f, -0.8f)
}
model("models/helmet.glb") { autoAnimate(true) }
cameraControls(true)
autoRotate(true)
},
onError = { error -> console.error(error) }, // init failed — wire to your reject path
onReady = { sceneView -> sceneView.startRendering() }
)
The minimal correct WebXR AR example
Verified against xr/ARSceneView.kt. AR session creation MUST happen inside a
user-gesture handler (a click/tap listener):
ARSceneView.checkSupport { supported ->
if (supported) {
// call ARSceneView.create from a click handler
ARSceneView.create(
canvas = canvas,
features = WebXRSession.Features(
required = arrayOf(XRFeature.HIT_TEST),
optional = arrayOf(XRFeature.DOM_OVERLAY, XRFeature.LIGHT_ESTIMATION)
),
onError = { msg -> console.error(msg) },
onReady = { arView ->
arView.onHitTest = { pose -> arView.loadModel("models/chair.glb") }
arView.onSelect = { source -> /* user tapped */ }
arView.start()
}
)
}
}
WebXR VR uses the same shape via VRSceneView; WebXRSession is the
lower-level unified AR+VR API. See llms.txt § WebXR.
Critical rules (verified — do not break)
Load filament.js BEFORE sceneview-web.js. The library needs the WASM Filament module present at init. Use
<script>tags, not ES imports, for the no-bundler path.The canvas must have non-zero pixel dimensions.
createViewerImplfalls back toclientWidth/clientHeightifwidth/heightare 0, so the canvas must be laid out (e.g.100vw/100vhor fixed px) beforecreateViewerruns.Everything is async.
SceneView.createandloadModelare Promise-based —.then(...)/awaitthem before calling instance methods.loadModel'sonLoadedfires only once external textures are fetched.WebXR session creation must be in a user gesture. Browsers reject
requestSessionoutside a click/tap handler. AlwayscheckSupportfirst, then callARSceneView.create/VRSceneView.createfrom the handler.One JS main thread. There are no background threads in browser JS — all Filament calls run on the main thread. Never call
destroy()/dispose()inside an animation-frame callback; defer to the next microtask.WebXR support is partial. AR: Chrome Android 79+, Meta Quest Browser, Safari iOS 18+. VR: Meta Quest Browser, desktop Chrome with a headset. Always gate on
checkSupportand provide a non-XR fallback.
Haptic feedback
sceneview-web exposes a SceneViewHaptic class that wraps the browser
Vibration API
(navigator.vibrate(...)) behind the same seven semantic presets as the
Android and iOS libraries, so cross-platform code paths stay symmetric.
// Plain JS — `sceneview.haptic` is a ready-to-use singleton:
sceneview.haptic.light(); // tap
sceneview.haptic.success(); // confirmation
sceneview.haptic.continuous(1.0, 200); // 200 ms; intensity ignored on Web
sceneview.haptic.pattern([10, 50, 20]);// custom on/off durations (ms)
- Presets:
light()medium()heavy()success()warning()error()selection(). Pluscontinuous(intensity, durationMs)andpattern(durationsMs[]). - The Web Vibration API exposes durations only — there is no intensity
knob — so the
intensityargument is accepted for cross-platform parity but ignored at runtime. - Desktop browsers and Safari on iOS do not expose
navigator.vibrate; every call is then a silent no-op. Some browsers also restrict vibration to user-gesture handlers. Seellms.txt § Haptic Feedback.
Performance / hot paths
Preallocate scratch arrays and mutate them in place — never build fresh
[x, y, z] / float3(...) / mat4 array literals inside a requestAnimationFrame
tick. Filament.js reads the array synchronously, so reuse is safe, and the small
JS heap on iOS Safari turns per-frame allocation into a GC sawtooth that drops
frames. SceneView's own OrbitCameraController keeps eyeScratch / centerScratch
/ upScratch and rewrites them per frame instead of allocating — follow that
pattern in your render loop. Full cross-platform guidance:
docs/docs/performance.md § Hot Paths & Allocation-Free APIs
(audit umbrella #2263).
Resources
- Cheat sheet — the Kotlin/JS DSL, the JS API,
and the WebXR surface, with signatures pulled from
sceneview-web/src/. - Recipes — model viewer, custom scene, procedural geometry, WebXR AR/VR — each with the verified entry point.
- Migration — Three.js /
<model-viewer>→sceneview-web, and cross-platform parity notes.
Workflow guidance
When the user asks for a SceneView-Web feature:
- Pick the API surface. Plain JS (
window.sceneview, script tag, no build) vs Kotlin/JS DSL (SceneView.create, bundler). Match the user's stack — don't give Kotlin to a vanilla-JS project. - Load filament.js before sceneview-web.js in any HTML you generate.
- Give the canvas explicit dimensions.
- Treat creation and
loadModelas async — chain with.then/await. - For WebXR,
checkSupportfirst, create inside a click handler, and provide a non-XR fallback path. - Read
llms.txt § SceneView Webfor the full surface before inventing an API. The DSL, JS API, and WebXR sections are exhaustive.