# Scenery Scripting -- API Reference, runtime types (v0.3.0) Types the JavaScript runtime defines: object descriptors and traits, materials, anchors, animation builders, plus the global functions and static extensions. Sibling bundle (engine types -- entities, scene, meshes, GPU): https://scenery.app/docs/scripting/api/llms-full.txt Sibling bundle (concepts, how-to, worked examples): https://scenery.app/docs/scripting/guide/llms-full.txt Global instances available in every script without declaration: - `experience` -- `Experience` - `scene` -- `Scene` - `environment` -- `Environment` - `http` -- `HTTP client (promisified). Methods: get(url, options?), post(url, body, options?), request(url, options). All return Promise<{status, data}>` - `websocket` -- `WebSocket client. Methods: connect(url, options?) returns WebSocket` - `httpClient` -- `HTTPClient (low-level, callback-based -- prefer `http` instead)` - `webSocketManager` -- `WebSocketManager (low-level -- prefer `websocket` instead)` Any docs page is also available as raw markdown by appending `.md` -- e.g. https://scenery.app/docs/scripting/api/mesh.md, https://scenery.app/docs/scripting/guide/examples.md. Authoritative for runtime v0.3.0. If an API is not listed here or in the sibling bundles, it does not exist in this version -- do not invent signatures. --- ## Runtime Classes ### `Anchor` Anchor types for object placement **Static Methods:** - `Anchor.position(xOrVector: Vector3 | number, y: number, z: number)` → `Object` - Anchor at fixed world position - `Anchor.geoLocation(latitude: number, longitude: number, altitude: number)` → `any` - Anchor at geographic location - `Anchor.camera(xOrVector: Vector3 | number, y: number, z: number, lerpFactor: number)` → `any` - Anchor relative to camera - `Anchor.currentPOV(xOrVector: Vector3 | number, y: number, z: number, resetRotation: boolean)` → `Object` - Anchor at user's current point of view (captures current camera position) - `Anchor.screenSpace(options: Object, options.alignment: string, options.insets: number | Object, options.respectsSafeArea: boolean)` → `Object` - Anchor a UI panel in screen space -- a flat 2D overlay pinned to a screen edge or corner, rather than a plane placed in the world. Use for HUDs and controls that should stay put wherever the viewer looks. - `Anchor.horizontalPlane(classification: string, minWidth: number, minHeight: number)` → `Object` - Anchor on detected horizontal plane (floor, table, etc.) - `Anchor.verticalPlane(classification: string, minWidth: number, minHeight: number)` → `any` - Anchor on vertical plane - `Anchor.hand(chirality: string, joint: string, trackingScope: string, lerpFactor: number, providesDiscoveryHint: boolean)` → `Object` - Anchor to user's hand (visionOS hand tracking) - `Anchor.image(imageUrl: string, physicalWidth: number, identifier: string, orientation: string, tracksContinuously: boolean, hideIfTrackingLost: boolean, providesDiscoveryHint: boolean)` → `Object` - Anchor to image marker (image tracking) ### `Material` Chainable builder for an inline material. Six kinds: `unlit`, `pbr`, `occlusion`, `customShader`, `materialX`, `video`. Use the matching factory (`Material.unlit({...})`, etc.) or `new Material(kind)`. Properties map to the underlying material data model with web-standard names: - Colors: `color`, `emissive`, `sheenColor`, `specularColor` -- flat tint. - Maps: `map`, `emissiveMap`, `roughnessMap`, `metalnessMap`, `normalMap`, `aoMap`, `specularMap`, `sheenMap`, `clearcoatMap`, `alphaMap` -- textures accept either a URL/asset-id string or `{ texture, scale }`. - Scalars: `roughness`, `metalness`, `clearcoat`, `opacity`, `emissiveIntensity`. - Rendering: `opaque`, `transparent`, `opacityThreshold`, `blendMode`, `faceCulling`, `wireframe`, `writesDepth`, `readsDepth`. **Static Methods:** - `Material.unlit(opts: Object)` → `Material` - Flat-shaded material. Renders the surface color regardless of scene lighting -- useful for UI, billboards, vertex-colored point clouds, etc. - `Material.pbr(opts: Object)` → `Material` - Physically-Based material -- the realistic-rendering default for surfaces that should respond to scene lighting. - `Material.occlusion(opts: Object)` → `Material` - Occlusion material -- invisible itself but hides geometry behind it. Use for matte holdouts, real-world geometry masks, portals. - `Material.customShader(opts: Object)` → `Material` - Custom shader material -- author-supplied surface shader and/or geometry modifier from a compiled shader library. - `Material.materialX(opts: Object)` → `Material` - ShaderGraph material from a bundled `.usdz`. Reference by file path plus the `/Root/` path inside. - `Material.video()` → `Material` - Video texture material. Use `.videoSource(urlOrId)` for the playback source and `.videoOptions({ loops, streamContent, volume })` for playback config. **Instance Methods:** - `opacity()` → `any` - Material opacity. Values < 1 also flip `isOpaque` to `false` so the blending state matches. - `materialXAsset()` → `any` - MaterialX (ShaderGraph): URL or asset id of the .usdz, plus the path to the material inside it (e.g. `"/Root/MyMaterial"`). - `setParameter(name: string, value: any, typeHint: Object)` → `Material` - Set a constant value on a shader parameter. Works on `customShader` and `materialX` kinds -- routes to the right options blob automatically. Warns and no-ops on kinds without shader parameters. For runtime variable bindings, use `entity.representation.bindMaterialParameter(name, variableId, opts?)`. - `clone()` → `any` - Deep-copy the material with a fresh `id`. Use for the get → clone → tweak → apply pattern when overriding a library material for a single entity without mutating the library entry. - `toString()` → `any` - Useful per-kind summary for `console.log(mat)` -- includes kind, id, name, and the meaningful state set on the material (channel colors, scalar values, shader params, etc.) so authors can see "what's on this material" at a glance. For the full serialized shape, use `JSON.stringify(mat, null, 2)`. ### `Instances` Instance-data handles for `rep.setInstances(...)` / `entity.setInstances(...)` -- GPU mesh instancing draws one copy of a mesh per transform, far cheaper than real entities. Instances are rendering-only (no physics, collision, or per-instance identity); use `clone()` for objects the user interacts with. Gate with `environment.features.has('instancing')`. **Static Methods:** - `Instances.transforms(list: Array)` → `Object` - Build an instance-data handle from a list of transforms. Each entry is a `Transform` (full pose) or a `Vector3` (a copy placed at that position). A bare array is also accepted -- `setInstances([...])` is sugar for `setInstances(Instances.transforms([...]))`. ### `Texture` GPU-only / runtime-managed texture. Authors construct via the static factories below; the returned handle is opaque and passes to material parameters (future) and compute kernel `inputTextures` / `outputTextures` maps (today, for `Texture.compute(...)` only). **Static Methods:** - `Texture.compute(options: Object, options.pixelFormat: string, options.textureType: string, options.width: number, options.height: number, options.depth: number, options.arrayLength: number, options.mipmapLevelCount: number, options.semantic: string, options.usage: Array)` → `Promise` - Allocate a GPU-only texture written by a compute kernel. Supports 2D, 3D, cube, and array textures with optional mipmap chains. Async because the dynamic-texture asset-provider funnel allocates the underlying GPU resource and registers it in the runtime's manager cache (so material binding finds the same instance later). Authors `await` once at allocation; subsequent kernel dispatches are sync. - `Texture.image(urlOrId: string, options: Object, options.semantic: string)` → `Promise` - Static image-asset texture. Reads an image asset (PNG / JPG / etc.) from the experience's asset library or an absolute URL and binds it as a sampleable texture -- typical use is a hand-painted normal map or albedo map fed to `Material.pbr({ normalMap: tex })`. - `Texture.video(urlOrId: string, options: Object, options.semantic: string, options.loops: boolean, options.autoplays: boolean, options.volume: number, options.streamContent: boolean, options.isShared: boolean)` → `Promise` - Video-asset texture. Plays a video file (mp4 / mov) as a sampleable texture and binds it to a material -- typical use is a looping background, an animated diorama, or a UI-overlay video sticker. The video starts playing automatically by default. Pass `{ autoplays: false }` and call `videoTexture.play()` later when the entity becomes visible. - `Texture.cameraFeed(options: Object, options.semantic: string)` → `Promise` - Live camera feed as a sampleable texture. Binds the device's camera capture as a regular texture handle -- typical uses are first-person portal effects, augmented-reality color grading on detected planes, or piping the feed into a compute kernel for a real-time filter. Available on iOS / iPadOS only -- Mac Catalyst and visionOS don't expose the AR camera capture. Always gate with `environment.features.has('cameraFeed')`. ### `Kernel` Opaque handle to a compiled GPU compute kernel. Authors construct via `Kernel.fromSource(...)` or `Kernel.fromAsset(...)`, then pass to `mesh.runCompute(kernel, options)`. **Static Methods:** - `Kernel.fromSource(options: Object, options.source: string, options.functionName: string)` → `Promise` - Compile a compute kernel from inline MSL source. Handy for prototypes and tests; production scripts should prefer `Kernel.fromAsset(...)` so the source lives in the experience's asset library. - `Kernel.fromAsset(options: Object, options.assetId: string, options.functionName: string)` → `Promise` - Compile a compute kernel from a shader-library asset declared in the experience's asset library. ### `Buffer` Raw GPU buffer for compute kernels. Construct via the static factories below; pass the handle to `mesh.runCompute(...)`'s `inputBuffers` / `outputBuffers` maps to bind it as a kernel argument. **Static Methods:** - `Buffer.float32(length: number, initialValue: number)` → `Buffer | null` - Allocate a Float32-typed GPU buffer. - `Buffer.uint32(length: number, initialValue: number)` → `Buffer | null` - Allocate a Uint32-typed GPU buffer. - `Buffer.uint8(length: number, initialValue: number)` → `Buffer | null` - Allocate a Uint8-typed GPU buffer. - `Buffer.atomic(initialValue: number)` → `Buffer | null` - Allocate a single-element atomic-uint counter -- common pattern for marching-cubes' triangle emitter, particle compaction, etc. ### `ObjectTraits` Builder object passed to the compatibility-only `.traits(t => ...)` callback. New code should skip this entirely and use the direct descriptor methods (`.physics(...)`, `.material(...)`, `.shadow(...)`, `.gestures(...)`, `.transform(...)`, `.opacity(...)`, `.fittingBox(...)`, `.pivot(...)`), which expose the same configuration and chain. **Instance Methods:** - `transform(transform: Transform)` → `ObjectTraits` - Set initial transform - `fittingBox(size: number)` → `ObjectTraits` - Scale model to fit within a cubic bounding box - `pivot(pivot: string)` → `ObjectTraits` - Set pivot adjustment - `opacity(opacity: number)` → `ObjectTraits` - Set opacity adjustment - `shadow(options: Object, options.directional: boolean, options.grounding: boolean | Object)` → `ObjectTraits` - Configure how this object interacts with the scene's two shadow systems. Mirrors `t.physics({...})` / `t.gestures({...})`: pass only the keys you want to change. - `material(materialOrId: string | Material, target: Object, target.type: string, target.models: Array, target.materialSlots: Array)` → `ObjectTraits` - Apply a material -- either a library reference by ID or an inline Material instance. - `physics(options: Object, options.mode: string, options.shape: string, options.mass: number, options.gravity: boolean, options.linearDamping: number, options.angularDamping: number, options.friction: number, options.restitution: number, options.translationLock: Object, options.rotationLock: Object)` → `ObjectTraits` - Give the object a physics body so it can collide, fall, and be pushed. Mirrors the editor's Physics inspector, so anything set here stays visible and editable there. Sub-groups are written only when you supply at least one of their keys -- `t.physics({ mode: 'static' })` produces a plain static body with no mass, damping, or material overrides. Physics also needs scene-level setup: enable the floor mesh and scene mesh collisions in the scene's settings, or bodies will fall forever. - `gestures(options: Object, options.drag: Object | boolean, options.rotate: Object | boolean, options.resize: Object | boolean, options.releaseBehavior: string, options.momentumScale: number, options.angularMomentumScale: number, options.disableAudio: boolean)` → `ObjectTraits` - Let the user move, rotate or resize this object with a gesture, and choose what happens when they let go. Omit a gesture to leave it disabled -- an object with no gestures configured cannot be manipulated at all. - `set(path: string, value: any)` → `ObjectTraits` - Directly set a property path in traits - `build()` → `Object` - Build and return the traits object ### `ObjectDescriptor` Descriptor for creating scene objects dynamically **Instance Methods:** - `name(value: string)` → `ObjectDescriptor` - Set the object name - `anchor(anchor: Object)` → `ObjectDescriptor` - Set the anchor - `asset(urlOrId: string)` → `ObjectDescriptor` - Set / replace the object's **source asset**, kind-routed to the right field (`model` → the model asset, image / video / GIF → the media source). Same-kind swap only -- it does **not** change the object's kind: pointing a model at a video URL gives a broken model, not a video (use `.representation(...)` to change kind). Warns for kinds with no source (primitive, container). Accepts an HTTPS URL or an asset id from the project. - `representation(sourceDescriptor: ObjectDescriptor)` → `ObjectDescriptor` - Fully replace this object's visual **representation** with the one from a freshly built descriptor (`createBox`, `createModel`, `createVideo`, ...) -- the clean way to change kind (model → primitive, model → video). Keeps this object's identity and wiring: its id, representation id, anchor (placement), and events. Takes the source's `kind` **and its traits** -- configure the new look via the factory chain, e.g. `d.representation(createBox(0.1,0.1,0.1).gestures({ drag: true }))`. Note: the authored **transform trait** rides inside the old kind and is dropped by the swap ("keeps placement" means the anchor, not the transform) -- re-apply via the source chain if needed. Element-level fields on the source (`.name()`, `.anchor()`, events) are ignored; only its representation is taken. - `clone()` → `ObjectDescriptor` - Deep-copy this descriptor with a **fresh id graph** (element id + every nested representation id + events), so it can be added alongside the original without an id collision. Use it to spawn variants of an authored object: `scene.getObjectDescriptor({ name: 'can' }).clone().transform({ position: p })`, then `scene.createEntity(...)`. The copy inherits the original's events (re-wired to the copy); clear them with `copy.data.events = []` if unwanted. - `traits(configureFn: function)` → `ObjectDescriptor` - Configure traits via a callback. Traits already on the descriptor (e.g. from `createMesh({ materials: [...] })`) are preserved -- calls add on top. - `physics(options: Object)` → `ObjectDescriptor` - Give this object a physics body. See ObjectTraits.physics for the full options. - `gestures(options: Object)` → `ObjectDescriptor` - Enable manipulation gestures (drag / rotate / resize). See ObjectTraits.gestures. - `material(materialOrId: string | Material, target: Object)` → `ObjectDescriptor` - Apply a material -- a library id or an inline `Material`. See ObjectTraits.material. - `shadow(options: Object)` → `ObjectDescriptor` - Configure the object's shadows (directional + grounding). See ObjectTraits.shadow. - `transform(transform: Object)` → `ObjectDescriptor` - Set the object's transform (position / rotation / scale). See ObjectTraits.transform. - `opacity(opacity: number)` → `ObjectDescriptor` - Set the object's opacity (0-1). See ObjectTraits.opacity. - `fittingBox(size: number)` → `ObjectDescriptor` - Scale a model to fit a box of the given size. See ObjectTraits.fittingBox. - `pivot(pivot: string)` → `ObjectDescriptor` - Adjust the model's pivot. See ObjectTraits.pivot. ### `EntityAnimation` Entity animation factory - create animation descriptors for use with entity.play() **Static Methods:** - `EntityAnimation.to(toProperties: Object, duration: number, options: Object)` → `EntityAnimation` - Animate to target properties - `EntityAnimation.fromTo(fromProperties: Object, toProperties: Object, duration: number, options: Object)` → `EntityAnimation` - Animate from starting to target properties - `EntityAnimation.by(byProperties: Object, duration: number, options: Object)` → `EntityAnimation` - Animate by relative values - `EntityAnimation.fromBy(fromProperties: Object, byProperties: Object, duration: number, options: Object)` → `EntityAnimation` - Animate from starting properties by relative values - `EntityAnimation.spin(revolutions: number, duration: number, options: Object, options.axis: Array)` → `EntityAnimation` - Spin animation - rotate around local axis - `EntityAnimation.orbit(config: Object, config.axis: Array | Vector3, config.rotationCount: number, config.clockwise: boolean, config.orientToPath: boolean, config.startTransform: Object, duration: number, options: Object)` → `EntityAnimation` - Orbit animation - rotate around a point - `EntityAnimation.keyframes(frames: Array, duration: number, options: Object, options.tweenMode: string)` → `EntityAnimation` - Keyframe animation - animate through multiple property states - `EntityAnimation.model(name: string, options: Object, options.trimStart: number, options.trimEnd: number, options.duration: number)` → `EntityAnimation` - Play embedded model animation (USDZ animations) - `EntityAnimation.group(animations: Array, options: Object)` → `EntityAnimation` - Group multiple animations to play together - `EntityAnimation.emphasize(style: string, duration: number, options: Object)` → `EntityAnimation` - Emphasize animation - attention-grabbing effect ### `GeoCoordinate` A geographic coordinate. Construct one for a point of interest, or receive a live fix from `environment.location.current()` (which additionally populates `horizontalAccuracy` and `timestamp`). **Instance Methods:** - `distanceTo(other: GeoCoordinate)` → `number` - Great-circle distance to another coordinate, in metres (haversine, 6371 km). - `bearingTo(other: GeoCoordinate)` → `number` - Initial great-circle bearing to another coordinate, in degrees (0-360, from north). ## Runtime Functions - `wait(seconds: number)` → `Promise` - Wait for specified seconds - `animateValue(options: Object, options.from: number | Vector2 | Vector3 | Vector4 | Color | Rotation, options.to: number | Vector2 | Vector3 | Vector4 | Color | Rotation, options.duration: number, options.curve: string, options.spring: Object, options.spring.duration: number, options.spring.bounce: number, options.bezier: Array, options.delay: number, options.repeatCount: number, options.reverseOnRepeat: boolean, options.autoStart: boolean, options.onUpdate: function, options.onComplete: function)` → `ValueAnimation` - Create and start a value animation Automatically interpolates between from/to values based on their type. Supports numbers, Vector2, Vector3, Vector4, Color, and Rotation. Rotations use spherical interpolation (slerp) automatically. Animations clean up automatically when complete. For infinite animations, call destroy() to stop, or they clean up when the scene ends. - `createBox(width: number, height: number, depth: number, cornerRadius: number, options: Object)` → `ObjectDescriptor` - Create a box primitive descriptor - `createSphere(radius: number, options: Object)` → `ObjectDescriptor` - Create a sphere primitive - `createPlane(orientation: string | number, width: number, height: number, cornerRadius: number)` → `ObjectDescriptor` - Create a plane primitive - `createModel(urlOrId: string, options: Object)` → `ObjectDescriptor` - Create a 3D model object descriptor - `createMedia(kind: string, urlOrId: string, width: number, aspectRatio: number, options: Object, options.cornerRadius: number, options.doubleSided: boolean, options.showLoading: boolean, options.immersive: boolean, options.video: Object, options.video.volume: number, options.video.loops: boolean, options.video.stream: boolean)` → `ObjectDescriptor` - Create a visual media object (image, video, or animated GIF) - `createImage(urlOrId: string, width: number, aspectRatio: number, options: Object)` → `ObjectDescriptor` - Create an image - `createVideo(urlOrId: string, width: number, aspectRatio: number, options: Object)` → `ObjectDescriptor` - Create a video - `createAnimatedGif(urlOrId: string, width: number, aspectRatio: number, options: Object)` → `ObjectDescriptor` - Create an animated GIF - `createContainer(children: Array)` → `ObjectDescriptor` - Create a container/composition - `createPanel(content: Object, options: Object, options.panelSize: any | any | Array | any)` → `any` - Build a UI panel descriptor wrapping the given root view. Pass to `scene.createEntity(panel)` to instantiate. - `createMesh(opts: Object, opts.vertexCapacity: number, opts.indexCapacity: number, opts.indexType: string, opts.attributes: Object, opts.parts: Array, opts.materials: Array, opts.interleavedGroups: Array>)` → `ObjectDescriptor` - Create a scriptable dynamic mesh with CPU-driven vertex/index updates. Returns an ObjectDescriptor -- pass to `scene.createEntity(...)`. After the entity loads, reach the mesh via `entity.representation.mesh` and write buffer data with `mesh.writeVertices(...)` / `mesh.writeIndices(...)`. Bytes flow straight from `Float32Array` / `Uint32Array` into the GPU-side buffer -- single memcpy per call, no per-element overhead. ## Static Extensions ### `Rotation` - `Rotation.quaternion(x: number, y: number, z: number, w: number)` → `Rotation` - Create a rotation from quaternion components ### `Color` - `Color.rgb(r: number, g: number, b: number)` → `Color` - Create a color from RGB values (alpha defaults to 1) - `Color.hex(hex: string)` → `Color | null` - Create a color from hex string - `Color.hsl(h: number, s: number, l: number)` → `Color` - Create a color from HSL values - `Color.white()` → `Color` - White color (1, 1, 1, 1) - `Color.black()` → `Color` - Black color (0, 0, 0, 1) - `Color.red()` → `Color` - Red color (1, 0, 0, 1) - `Color.green()` → `Color` - Green color (0, 1, 0, 1) - `Color.blue()` → `Color` - Blue color (0, 0, 1, 1) - `Color.clear()` → `Color` - Transparent color (0, 0, 0, 0) ### `Math` - `Math.toRadians(degrees: number)` → `number` - Convert degrees to radians - `Math.toDegrees(radians: number)` → `number` - Convert radians to degrees - `Math.lerp(a: number, b: number, t: number)` → `number` - Linear interpolation between two values - `Math.clamp(value: number, min: number, max: number)` → `number` - Clamp value between min and max - `Math.map(value: number, inMin: number, inMax: number, outMin: number, outMax: number)` → `number` - Map value from one range to another - `Math.fract(x: number)` → `number` - Get fractional part of number - `Math.smoothstep(edge0: number, edge1: number, x: number)` → `number` - Smooth interpolation with easing