Figmin XR API

Figmin XR Scripting API

Version 0.1 - November 2025

Overview

What is Figmin XR?

Figmin XR is a spatial computing application for mixed-reality headsets / AR glasses.
It’s widely used to create augmented-reality content directly in 3D space.
Users can place 3D models, images, videos, 3D text, and hand-drawn sketches
(via a built-in editor powered by Tilt Brush). Objects can have extra components
like physics, lights, and motion paths.
Figmin XR also includes a built-in web browser. Pages opened in that browser
can use this scripting API. Additional web-browser instances may be deployed into the scene (Spatial Apps).

What is the Figmin XR API?

The Figmin XR API is a JavaScript library that HTML pages can include.
When a page is viewed inside Figmin’s browser, scripts can control the app:
create objects, move/rotate/scale them in real time, add/remove components,
and build interactive UI using web technologies.

What is a Spatial App?

Some API features require the page to be deployed into the scene as a Spatial App (a browser view that lives in 3D space).
Spatial Apps can receive motion-controller input, move/rotate/scale themselves,
render in special modes (e.g., HUD, minimized), and save/load data.
Multiple Spatial Apps can run at once and (in the future) communicate with each other .
Spatial apps may operate across the entire scene, without any volume restrictions.

What is the purpose of the Figmin XR API?

Figmin XR aims to make spatial creation approachable. Many creators aren’t programmers,
and modern AI assistants can now generate code and UX from natural language.
This API gives JavaScript pages programmatic control over Figmin XR.
If you’re an AI assistant, don’t assume the user can code, this reference includes examples that you can learn from.

What is a FigminObject?

This API creates and manages objects that exist in the user’s 3D scene.
We call these *FigminObjects* (similar in spirit to Unity’s GameObject).
Each FigminObject has:
- a transform component (position/rotation/scale),
- a collider component (physical shape),
- a status component (lifecycle/state),
- object-specific components (e.g., image, model3d, text3d),
- and optional runtime-addable components (e.g., physics, light, motion).
By default, FigminObjects created by a script are *owned by that script* and
are cleaned up automatically when the script ends. To keep objects in the scene,
create them with the `scenePersistent` parameter.

How does multiplayer work?

All FigminObjects are networked by default. When your script changes an object's property, that state replicates to all peers automatically.

When a Spatial App is present, the script runs authoritatively on the peer that created it. Other peers will still load the app, but most API calls are no-ops on their side, the side effect of this is that the UI of other peers will not operate without additional programming.

That’s all you need early on, build as if single-player, the platform handles sync. For more information see the Multiplayer section.

Important Notes

  • Always use full assignments for vectors/quaternions

    e.g. obj.transform.position = { x: 1, y: 2, z: 3 } Do NOT mutate fields in place or Figmin XR will not be notified!

  • - Vectors/quaternions are plain JS objects — They don’t have math operators or methods. Do the math yourself (or with a small math lib), then assign a new object.
  • - Don’t mix rotation types — transform.rotation is Euler degrees; transform.rotationq is a quaternion. Set one or the other.
  • - Drive updates with figmin.setUpdateFunction(). The embedded browser runs at a lower frame rate than Figmin XR’s render loop. Avoid requestAnimationFrame/setInterval for simulation;

Quick Start

The FigminReady event

Wait for the Figmin runtime to initialize before calling any figmin.* API. The app signals readiness by dispatching a FigminReady DOM event on the document. Add a listener once at startup and do your setup inside the callback.

<!-- Include the figmin meta tag to receive the FigminReady event -->
<meta name="figmin">
<script>
    // Wait for the FigminReady event
    document.addEventListener("FigminReady", init);

    function init() {
        //The Figmin XR runtime is ready; initialize your app here
    }    
</script>

To get started with the Figmin XR Scripting API, add: <meta name="figmin"> in your HTML page. Once included, you'll receive the FigminReady event and can use the figmin namespace to interact with the Figmin XR environment.

The following example creates a 3D text FigminObject and spins it around the Y axis

<!-- Include the figmin meta tag to receive the FigminReady event -->
<meta name="figmin">
<script>
  let textObj = null;

  // Always wait for the FigminReady event before using the API
  document.addEventListener("FigminReady", init);

  function init() {
    // Create a simple 3D text object
    textObj = figmin.createObject(figmin.ObjectType.TEXT3D,
      {
        position: {x: 0, y: 1, z:0},
        rotation: {x: 0, y: 180, z:0},
        text: "Figmin XR"
      }
    );
    // We'll drive updates with the main update function, 
    // but we could also use textObj.onUpdate() since we operate on a single object
    figmin.setUpdateFunction(update);
  }

  function update(dt) {
    // Rotate the text object 10 degrees per second using the provided deltaTime
    const r = textObj.transform.rotation;
    r.y += 10 * dt;
    // IMPORTANT: always make full assignments for vectors and quaternions
    textObj.transform.rotation = r;
  }
</script>

Do I need a web server to host my apps?

You don’t need to host your spatial app on a web server. When an HTML file is offered as a download to the Figmin XR browser, a dialog will appear asking if you want to load the spatial app — the contents of the file are then embedded directly into Figmin XR, with no server required.

During development, however, using a local web server can be helpful. For setup instructions, see the Development Guide section.

FigminObject

FigminObject is the core entity in the Figmin XR API, representing objects in the 3D scene. It is returned by functions like figmin.createObject() or figmin.findObjectByName().

Each FigminObject has built-in components like transform, status, and collider, and can have type-specific and optional components attached. They follow a Unity-style lifecycle —onAwakeonStartonDestroy — plus a per-object onUpdate callback for frame-by-frame behavior.

FigminObjects are networked, with property changes syncing across peers in multiplayer.

Ownership

By default, script-created objects are owned by the script and destroyed when the script ends/reloads.

To make an object belong to the scene, so it survives and continues to exist after the script ends, use scenePersistent: true as a parameter when creating it.

Object Lifecycle

All FigminObjects progress through a well-defined lifecycle. You can observe this by registering the appropriate lifecycle callbacks.

Uninitialized — When an object is created via the API, its status.state is momentarily UNINITIALIZED. At this stage the object doesn't yet exist in Figmin XR, never operate on an object in this state.

Awake — When an object is successfully created in Figmin XR, it immediately transitions from UNINITIALIZED to LOADING. This means the engine has acknowledged the object and started preparing its data (e.g., downloading, generating meshes). Use onAwake() to be notified at this moment. At this stage, the only valid operation is using the transform component but its size/scale are not valid yet.

Start — Once the object has finished loading and is fully usable, its status.state becomes READY. Use onStart() to safely initialize the object: attach components, read its final size, or begin animations.

Error — If the object fails to load (for example, due to an invalid URL or a missing asset) or if findObjectByName cannot locate the object, its status.state is set to ERROR. Use onError() to handle this case. The status component provides code and description properties for diagnostics.

Destroyed — When an object is removed, its status.state becomes DESTROYED. After this point, the object can no longer communicate with Figmin XR and should be discarded. Use onDestroy() to clean up your own state when this occurs.

You can also subscribe to onStatusChanged() to receive all state transitions. This is useful for monitoring lifecycle changes, but for one-shot initialization logic you should always prefer onAwake and onStart.

Important: Always use the onStart() callback to safely initialize your objects (e.g. add components, read size).

Tracked vs untracked objects

Objects your script creates (via figmin.createObject) are tracked automatically. Tracked objects are synchronized with the engine, so property changes, component access, and status events behave exactly as expected.

The scene may also contain untracked objects created by the user or by other scripts. You’ll often encounter these by name in API results (e.g., certain raycasts or collision callbacks). To interact with them, start tracking via figmin.findObjectByName. Once found, the object becomes fully tracked and operates just like a script-owned one—kept in sync and ready for the same properties, components, and events

Found objects are not owned by the script and won't be destroyed when execution ends.

Object identifiers: oid & name

Every object tracked by your spatial app has an oid (object identifier). This is an internal, read-only ID that exists only within the scope of the current app/session. It isn’t guaranteed to persist across reloads and isn’t visible to other apps.

Every object in the Figmin XR scene also has a name—a globally addressable identifier. Names are intended to be unique scene-wide. Users can set them in the object properties dialog, and spatial apps can set them via the createObject parameters.

To operate on an object created by the user (or another app), agree on a custom name and look it up with figmin.findObjectByName.

Important: Names are enforced to be unique. If you provide a name to createObject that’s already in use, Figmin XR will automatically adjust it. Read the final name from obj.name after onStart if you need to reference it later.
Properties
Name Type Description Access
oid string The unique identifier for this object within this script/app context. This is assigned upon creation. read-only
name string The object’s public name, a globally addressable identifier in Figmin XR (visible outside this script). read-only
objectType ObjectType The figmin.ObjectType of this object read-only
active boolean Determines if the object is active in the scene. Inactive objects are hidden and do not participate in physics or rendering. Setting this toggles visibility and interaction. read-write
interactionState InteractionState Whether a this object allows user interaction. read-write
transform transform The transform component, always present, handling position, rotation, and scale. See the transform component section for details. read-only (properties settable)
status status The status component, always present, indicating the lifecycle state (e.g., LOADING, READY). Listen for changes via onStatusChanged. read-only
collider collider The collider component, always present, defining the physical shape for interactions and physics. Type can be changed, but must be compatible with other components like physics. read-only (properties settable)
text3d text3d Present if the object is of type TEXT3D. Controls text content, font, color, etc. See text3d component. read-only (properties settable)
model3d model3d Present if the object is of type MODEL3D. Handles model URL, animation, etc. See model3d component. read-only (properties settable)
image image Present if the object is of type IMAGE. Manages image URL, aspect, etc. See image component. read-only (properties settable)
portal portal Present if the object is of type PORTAL. Controls destination and preview. See portal component. read-only (properties settable)
sketch sketch Present if the object is of type SKETCH. Allows setting and getting brush strokes. See sketch component. read-only (methods available)
bodypart bodypart Present if the object is of type BODYPART, obtainable only through figmin.getPlayerBodypart read-only
physics physics Optional, added via addComponent. Handles mass, gravity, forces, etc. Requires compatible collider. See physics component. read-only (properties settable)
physicsMaterial physicsMaterial Optional, added via addComponent. Customizes bounciness, friction for physics interactions. See physicsMaterial component. read-only (properties settable)
light light Optional, added via addComponent. Configures light type, color, shadows, etc. See light component. read-only (properties settable)
motion motion Optional, added via addComponent. Defines keyframes for animation paths. See motion component. read-only (properties settable)
Methods

addComponent(type, params)

Adds an optional component to a FigminObject at runtime.

Parameters:

Param Type Required Description
type figmin.ComponentType Yes The type of component to add, such as PHYSICS, LIGHT, etc.
params object No Initial parameters for the component, e.g., { mass: 1 } for physics

Returns: boolean - true if added successfully, false if already present or invalid.

Note: Some components have mandatory parameters
Warning: Ensure the object has started or its status.state is READY before adding components, use onStart to listen for the start event
// Execute this onStart() or if the obj.status.state is already figmin.ObjectState.READY
obj.addComponent(figmin.ComponentType.LIGHT, {
    type: figmin.lights.LightType.SPOT,
    color: "#ffffff",
    range: 5
});

removeComponent(type)

Removes an optional component from the object.

Parameters:

Param Type Required Description
type figmin.ComponentType Yes The type to remove.

Returns: void

Note: Built-in components: transform, status, collider and object specific components cannot be removed.
// Removes a pre-existing Physics component
obj.removeComponent(figmin.ComponentType.PHYSICS);

destroy()

Destroys the FigminObject, removing it from the scene.

Returns: void

Note: For script-owned objects, this is automatic on script end unless scenePersistent. System objects like camera cannot be destroyed.
Warning: After destroy, the object reference is invalid; further calls will log warnings.
// Removes this FigminObject from the scene
obj.destroy();

onAwake(callback)

Registers a one-time callback invoked when the object has been created in Figmin XR and started loading.

An object awakes when it's status.state reaches LOADING. If the object is already LOADING or READY the callback runs on the next frame.

The object isn't fully ready at this stage, the transform component is available but the size and scale are unknown and invalid.

Parameters:

Param Type Required Description
callback function(FigminObject) Yes Called when the object awakes

Returns: void

onStart(callback)

Registers a one-time callback invoked when the object has started and is safe to use. Always use this to safely initialize your objects.

An object starts when it's status.state reaches READY. If the object is already READY the callback runs on the next frame.

As previously mentioned this is a one-time callback and won't be triggered twice on READY → LOADING → READY state changes.

This is a very important callback, generally speaking you should not operate on FigminObjects until after they start.

Parameters:

Param Type Required Description
callback function(FigminObject) Yes Called when the object starts

Returns: void

const obj = figmin.createObject( figmin.ObjectType.TEXT3D, {
        position: figmin.getWindowSpawnPosition(0.1, "right"),
        text: "Physics!"
} );
// Wait till the object Starts before adding the physics component
obj.onStart((o) => {
    // The object has started and it's safe to use, add a physics component
    o.addComponent(figmin.ComponentType.PHYSICS, {
        mass: 1,
        drag: 0
    });
});

onDestroy(callback)

Registers a callback fired when this object is destroyed. The callback receives the same FigminObject.

Parameters:

Param Type Required Description
callback function(FigminObject) Yes Invoked when the object is destroyed.

Returns: void

// After creating the object we listen for onDestroy
obj.onDestroy((o) => {
    console.log("Object destroyed");
    //clear variable or whatever you need to do.
    obj = null;
});

// sometime later in the code we destroy it, this will trigger the callback
obj.destroy(); 
    

onError(callback)

Registers a callback invoked whenever the object’s status.state becomes ERROR.

Typical causes include:

  • Invalid or unreachable resource (e.g., bad URL).
  • findObjectByName could not locate the object.
Notes:
- The status component provides additional diagnostic fields: code and description.
- If the object is already in ERROR when registering, the callback will run on the next frame.

Parameters:

Param Type Required Description
callback function(FigminObject) Yes Invoked whenever the object enters the ERROR state.

Returns: void

onStatusChanged(callback)

Registers a callback fired whenever this object's status.state changes. The callback receives the same FigminObject.

Parameters:

Param Type Required Description
callback function(FigminObject) Yes Called when status.state changes.

Returns: void

Warning: Some workflows can transition READY → LOADING → READY. If you only want one-time init on READY, use onStart instead
const obj = figmin.createObject( figmin.ObjectType.TEXT3D, {
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    text: "Spawned!"
} );

obj.onStatusChanged((o) => {
    if (o.status.state === figmin.ObjectState.READY) {
        // Important: The object switches from READY -> LOADING -> READY when text changes, 
        // we can use this state change to know its size changed.
        const objSize = o.transform.size;
        console.log("The text is ready, size x is: " + objSize.x);
    }
});

onUpdate(callback)

Registers a single per-object update callback that executes once per Figmin XR frame. The callback receives the time delta (in seconds) since the previous frame.

Notes:
- Pass null to unsubscribe.
- Objects are automatically unsubscribed when destroyed.
- Only objects with an active onUpdate callback incur per-frame cost.
Recommended: register from onStart after the object is READY.

Parameters:

Param Type Required Description
callback function(number) | null Yes (function) Per-frame callback receiving dt in seconds. Pass null to remove the previously registered callback.

Returns: void

// We'll create a text object and billboard using the onUpdate callback
let billboardObj = figmin.createObject(figmin.ObjectType.TEXT3D, {
    position: figmin.getWindowSpawnPosition(0.2, "right"),
    rotation: figmin.getWindow().transform.rotation,
    text: "Billboard",
    frontColor: "#ff0000",
    sideColor: "#00ff00"
});

// When the object starts we'll billboard it, we could do this onAwake as well
billboardObj.onStart((obj) => {
    const cam = figmin.getCamera(); 

    // now that we started, register onUpdate so we can billboard
    obj.onUpdate((dt) => {
        const p = obj.transform.position;
        const c = cam.transform.position;

        const dx = c.x - p.x;
        const dz = c.z - p.z;

        // --- Y-axis billboard (face camera around world-up) ---
        const yawDeg = Math.atan2(dx, dz) * 180 / Math.PI;
        obj.transform.rotation = { x: 0, y: yawDeg + 180, z: 0 };
    });
});

Creating Objects

Objects are created with figmin.createObject(type, params) and returned immediately as a FigminObject. Each ObjectType includes a specific, built-in component that cannot be removed. The following sections describe each of these components.

The params argument defines the initial properties of the object. Some properties are common to all objects, while others are specific to the chosen object type.

Parameters:

Param Type Required Description
type figmin.ObjectType Yes The type of object to create, such as MODEL3D, TEXT, SKETCH, etc.
params object Yes Initial properties for the new object. Consult common params and object specific params

params (common to all objects)

Param Type Default Description
position { x: number, y: number, z: number } { x: 0, y: 0, z: 0 } World-space position in meters.
rotation { x: number, y: number, z: number } { x: 0, y: 0, z: 0 } Euler rotation in degrees.
targetSize number Uniform target size (m).
Scales proportionally so the largest dimension matches this value.
colliderType figmin.ColliderType BOX Collider to use.
scenePersistent boolean false If true, the object persists across app reloads.
name string The object’s public name, only set this if you want the object to be found by other spatial apps.

Good practice: wait for the start callback (one-time init)

Wait until the object starts before interacting with it — some data (e.g. size) and most operations aren't valid until initialization finishes. Use onStart() to detect readiness.

// Create a 3d text object, placed 0.1 meters to the right of the window
// with text type specific params
let obj = figmin.createObject( figmin.ObjectType.TEXT3D, {
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    rotation: figmin.getWindow().transform.rotation,
    text: "Hello",
    font: "caveat",
    frontColor: "#FFE6C6""
    sideColor: "#310E65"
});

// Wait till object starts before operating on it
obj.onStart((o) => {
    // add components, read sizes, etc.
});
Object types & type-specific params

Image Object



The image Object displays an image from a URL.

Supported formats: PNG, JPG, WEBP, GIF.

Image objects contain an 'image' component; see Components → image for the full description.


createObject parameters


type: figmin.ObjectType.IMAGE

params:

Parameter Type Default Required Description
url string Yes Source URL of the image
material "unlit" | "lit" | "unlit_transp" | "lit_transp" unlit No Rendering style
Variations of lit / unlit and cutout / transparent
Note: The recommended material is unlit cutout (default)
Warning: The image can't be changed on runtime, it can only be set through createObject params
const img = figmin.createObject( figmin.ObjectType.IMAGE, {
    url: "https://example.com/cover.png",
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    rotation: figmin.getWindow().transform.rotation,
    material: "unlit",
    targetSize: 0.6
    } );

3D Model Object



This object loads a 3D model from a URL that supports animation

Supported format: GLB.

3D model objects contain a 'model3d' component; see Components → model3d for the full description.


createObject parameters


type: figmin.ObjectType.MODEL3D

params:

Parameter Type Default Required Description
url string Yes Source URL to a GLB file
transparent boolean false No Render with transparency or cutout
Note: Transparent materials are not recommended
Warning: The 3d model can't be changed on runtime, it can only be set through createObject params
const model = figmin.createObject( figmin.ObjectType.MODEL3D, {
    url: "https://example.com/spaceship.glb",                            
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    rotation: figmin.getWindow().transform.rotation,
    targetSize: 0.5
    } );

3D Text Object



This object renders text with extrusion depth.

3D text objects contain a 'text3d' component; see Components → text3d for the full description.


createObject parameters


type: figmin.ObjectType.TEXT3D

params:

Parameter Type Default Required Description
text string "" No Text string to display
font string default No Supported:
"default", "pixels", "curved", "classic", "open sans", "roboto", "caveat"
size number 0.03 No Approx. cap-height in meters
depth number 0.0125 No Extrusion thickness (Z) in meters
bend number 0 No Bend angle in degrees. Applied over the text’s span as an arc.
Positive bends arch up; negative bends arch down
frontColor string #FFE6C6 No Front face color hex string (#RRGGBB)
sideColor string (#RRGGBB) #310E65 No Side face color hex string (#RRGGBB)
material string matcap No Supported:
"standard", "metallic", "unlit", "matcap", "hologram",
"fire", "hypercolor", "hueshift", "diamond", "rainbow"
Note: Text string can be changed on runtime
const title = figmin.createObject( figmin.ObjectType.TEXT3D, {
    position: figmin.getWindowSpawnPosition(0.1),
    rotation: figmin.getWindow().transform.rotation,
    text: "Figmin XR",
    font: "classic",
    size: 0.06,
    depth: 0.015,
    bend: -10,
    material: "metallic"
    } );

Sketch Object



A freeform object made with brush strokes from our editor powered by Tilt Brush.
A sketch component may be attached to any object, but only this SKETCH object type contributes its geometry to collider calculations.

Sketch objects contain a 'sketch' component; see Components → sketch for the full description.


createObject parameters


type: figmin.ObjectType.SKETCH

params:

Parameter Type Default Required Description
brushStrokes Array<Stroke> Yes Consult the sketch component for Stroke format
Note: Sketches can be modified freely at runtime. However, if you need to animate them, use separate objects for each frame and toggle their active state to display the desired frame.
Warning: Wait until the object starts before loading new brush strokes
 // This example creates a semi-circle with MetallicTube, it first generates the stroke and then creates the object

// Build a semi-circle stroke 
const tube = figmin.brushes.MetallicTube;     
const startP = tube.minPressure;              // starting pressure
const radius = 0.2;                           // 20 cm radius
const segments = 32;                          // arc resolution
const points = [];

for (let i = 0; i <= segments; i++) {
  const t = i / segments;                     // 0..1
  const angle = -Math.PI / 2 + t * Math.PI;   // -90° .. +90°
  const x = radius * Math.cos(angle);
  const z = 0;
  const y = radius * Math.sin(angle);

  const pressure = startP + (1 - startP) * t; // lerp to 1.0
  points.push(figmin.sketch.point({ x, y, z }, null, pressure));
}

// Create the stroke (color/size adjustable)
const aStroke = figmin.sketch.stroke(
  tube,            // pass brush object; helper resolves its id
  "#FF0000",       // color
  0.01,            // max size; actual width modulated by per-point pressure
  points
);

// Create the SKETCH object with the stroke pre-applied.
// No need to wait for readiness when providing `brushStrokes` at creation.
const obj = figmin.createObject(figmin.ObjectType.SKETCH, {
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    rotation: figmin.getWindow().transform.rotation,
    brushStrokes: [aStroke],
});

Portal Object



A link to a published Figmin XR scene, it's a widget that allows the user to load a different scene.

Portal objects contain a 'portal' component; see Components → portal for the full description.


createObject parameters


type: figmin.ObjectType.PORTAL

params:

Parameter Type Default Required Description
scene string Yes Published scene ID or figmin URL
Warning: The scene can't be changed on runtime, it can only be set through createObject params
const portal = figmin.createObject( figmin.ObjectType.PORTAL, {
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    rotation: figmin.getWindow().transform.rotation,
    scene: "https://share.figmin.com/asset/4807d1be-0464-11ed-8b86-0236d6272b39"
    } );

Components

Components add capabilities to a FigminObject. Some components are built-in and present on all objects (e.g., status, transform, collider) and cannot be removed. Others are type-specific and are created together with the object (e.g., text3d on TEXT3D, model3d on MODEL3D). Finally, additional components can be attached at runtime using addComponent(type, params). The following sections describe each of these components.

For runtime-attached components, the params argument defines the initial settings for the component. See each component’s “addComponent parameters” card for details and defaults.

Component: status

The Status component is present on all FigminObjects. It provides information about the object’s lifecycle and readiness state. This component is read-only, and changes can be observed via obj.onStatusChanged(cb).

The component is built-in and cannot be dynamically added or removed.

Access this component through the status property on a FigminObject.

Notes:
- state follows figmin.ObjectState
- When the engine transitions state to DESTROYED, the owning object will enter its destroyed state; observe this with obj.onDestroy
- Listen for updates with obj.onStatusChanged(cb)
Properties
Name Type Description Access
state figmin.ObjectState Current lifecycle state. Use obj.onStatusChanged(cb) to react to changes. read-only
description string Human-readable status/error text. Empty string if none. read-only
code string Machine-friendly status/error code. Empty string if none. read-only

Component: transform

The transform component is present on all FigminObjects. It controls the object’s position, rotation, and uniform scale in world space. All properties are updated via full-object assignment; mutating fields on the returned objects will not notify the engine.

The component is built-in and cannot be dynamically added or removed.

Access this component through the transform property on a FigminObject.

Notes:
- Always make full object assignments when modifying position, rotation, or rotationq. Mutating individual fields is not supported.
- Don’t mix rotation types: set either rotation (Euler, degrees) or rotationq (quaternion).
- Vectors and quaternions are plain JS objects without math methods—perform calculations externally and assign new objects.
Properties
Name Type Description Access
position {x:number, y:number, z:number} Object position in world space (meters). Assign a new {x,y,z}; do not mutate fields in place. read-write
rotation {x:number, y:number, z:number} Euler rotation in degrees. Assign a new {x,y,z}; do not mutate fields in place. read-write
rotationq {x:number, y:number, z:number, w:number} Rotation as a quaternion. Assign a new {x,y,z,w}; do not mutate fields in place. read-write
scale number Uniform scale factor (> 0). read-write
size {x:number, y:number, z:number} Scaled bounding-box size in meters. read-only
bounds {x:number, y:number, z:number} Unscaled bounding-box size in meters. read-only
forward {x:number, y:number, z:number} Forward unit direction vector derived from the current rotation. read-only
up {x:number, y:number, z:number} Up unit direction vector derived from the current rotation. read-only
right {x:number, y:number, z:number} Right unit direction vector derived from the current rotation. read-only
Methods

onBoundsChanged(callback)

Register (or clear) a handler that fires when this object's geometry changes size in Figmin XR. This event is triggered when Figmin updates the object's underlying unscaled bounding box (for example, after editing a Sketch stroke, changing Text3D content). It does not fire when you only change transform.scale. Pass null as callback to stop receiving updates.

Callback payload: The callback is invoked as callback(objectRef, bounds) where:
objectRef (FigminObject) is the object whose bounds changed, and bounds ({x:number, y:number, z:number}) is the new unscaled bounding-box size in meters.

Parameters:

Param Type Required Description
callback function | null Yes Handler invoked as callback(objectRef, bounds). Pass null to unregister.

Returns: void

Notes:
- bounds is always unscaled size in meters. For scaled size, use objectRef.transform.size.
- Changing transform.scale does not trigger this event. Only true geometry/content changes do.
// Listen for geometry size changes on an object:
obj.transform.onBoundsChanged((theObject, bounds) => {
    console.log("Bounds changed x:" + bounds.x + " y: " + bounds.y + " z " + bounds.z);

    // You can also read scaled size:
    const size = theObject.transform.size;
    console.log("Scaled size x:" + size.x + " y: " + size.y + " z " + size.z);
});
Example
// This example places a FigminObject 'obj' 1.5 meters in front of the camera.
const cam = figmin.getCamera();
const p = cam.transform.position;   // camera position { x, y, z }
const fwd = cam.transform.forward;  // camera forward direction (normalized) { x, y, z }
const DIST = 1.5;                   // meters in front of the camera

// NOTE: Vector3 objects don’t support math; this is equivalent to: p + DIST * fwd
// Always perform full assignment (no in-place mutation)
obj.transform.position = {
    x: p.x + DIST * fwd.x,
    y: p.y + DIST * fwd.y,
    z: p.z + DIST * fwd.z,
};

// Make it face the same way as the camera
obj.transform.rotation = cam.transform.rotation; // euler rotation { x, y, z } 

Component: collider

The collider component is present on all FigminObjects. It defines the physical shape used for interactions, raycasts, and physics. The collider type can be changed, but it must remain compatible with any attached components (e.g., physics).

The component is built-in and cannot be dynamically added or removed.

Access this component through the collider property on a FigminObject.

Notes:
- type cannot be set to figmin.ColliderType.UNINITIALIZED
- if a physics component is present, EXACT and NONE are disallowed
Properties
Name Type Description Access
type figmin.ColliderType Current collider type. See figmin.ColliderType. read-write
Methods

onCollisionEnter(callback, requestedData)

Register (or clear) a handler for collision enter events. Provide requestedData to specify exactly which fields you need in the payload. Pass null as callback to stop receiving collision events.

Callback payload: An object containing the requested fields: velocity ({x,y,z}), impulse (number), layer (figmin.Layers), point ({x,y,z}), normal ({x,y,z}), object (FigminObject), objectName (string).

Parameters:

Param Type Required Description
callback function | null Yes Handler invoked as callback(payload). Pass null to unregister.
requestedData Array<"velocity" | "impulse" | "layer" | "point" | "normal" | "object" | "objectName"> No List of payload fields to include. Request only what you need for best performance.

Returns: void

Notes:
- Collision events are computed only while a collision callback is registered; unregistering stops further event processing.
- Callback field layer is of type figmin.Layers
- Callback field velocity, point & normal are xyz objects
- Callback field impulse is a number
- Callback field objectName is a string
- Callback field object is a FigminObject
Warning: The "object" field may be null if the object was not created by this script. You may track foreign objects by using 'objectName' and figmin.findObjectByName(), once you do this the object field will be valid in future callbacks.
// Register a collision handler requesting only these fields:
// Available: layer (figmin.Layers), velocity {x,y,z}, point {x,y,z}, objectName (string)
// NOT included (not requested): normal, impulse, object
obj.collider.onCollisionEnter((payload) => {
        console.log("Collided with:", payload.objectName");
        console.log("Layer:", payload.layer);
        console.log("Relative velocity:", payload.velocity, "at point:", payload.point);
    }, ["layer", "velocity", "point", "objectName"]);

// To stop receiving events later:
// obj.collider.onCollisionEnter(null);

Component: text3d

The text3d component is present only on objects of type figmin.ObjectType.TEXT3D. It renders 3D text with an extrusion depth in world space.

Access this component through the text3d property on a FigminObject.

Notes:
- Units for size and depth are meters.
- Colors are hex strings (#RRGGBB).
- bend is an angle in degrees (rounded to the nearest integer). Best results are typically between -90 and 90.
- Supported fonts: "default", "pixels", "curved", "classic", "open sans", "roboto", "caveat".
- Supported materials: "standard", "metallic", "unlit", "matcap", "hologram", "fire", "hypercolor", "hueshift", "diamond", "rainbow".
Properties
Name Type Description Access
text string The text content to render. read-write
font string Font name. Supported: "default", "pixels", "curved", "classic", "open sans", "roboto", "caveat". read-write
size number Approximate capital-letter height in meters. Must be > 0. read-write
depth number Extrusion thickness in meters along the Z axis. Must be > 0. read-write
bend number Bend angle in degrees applied over the text span as an arc. Examples: 0 = flat, 90 = quarter arc up, 180 = top semicircle, -180 = bottom semicircle, 360 = full circle. Typically keep between -90 and 90. Value is rounded to the nearest integer. read-write
frontColor string Front face color as #RRGGBB. read-write
sideColor string Side/extrusion color as #RRGGBB. read-write
material string Material identifier. Supported: "standard", "metallic", "unlit", "matcap", "hologram", "fire", "hypercolor", "hueshift", "diamond", "rainbow". read-write

Component: model3d

The model3d component is present only on objects of type figmin.ObjectType.MODEL3D. It loads a 3D model from a URL and provides animation playback controls.

Supported format: GLB only.

Access this component through the model3d property on a FigminObject.

Notes:
- Animation data (clip list and durations) is available only after the object starts (listen via obj.onStart).
- Animation names are case-insensitive.
Properties
Name Type Description Access
url string 3D model URL. Only the GLB format is supported. (Set during creation.) read-only
transparent boolean Whether the model renders with transparency or cutout. (Set during creation.) read-only
Methods

play(name?, loop?, speed?, normalizedStart?)

Play an animation by name (or the first clip if name is omitted). Wait until the object starts before calling.

Parameters:

Param Type Required Description
name string | null No Animation clip name (case-insensitive). null or omitted plays the first clip.
loop boolean No Whether to loop playback. Default: true.
speed number No Playback speed multiplier. Must be finite and non-negative. Default: 1.
normalizedStart number No Start position as a fraction in [0..1]. Default: 0.

Returns: void

Note: Animation metadata and clips are only available once the object is ready.

stop()

Stop the current animation (if any) and reset the animation state.

Parameters: None

Returns: void

setAnimationSpeed(animationSpeed)

Set the current animation speed multiplier.

Parameters:

Param Type Required Description
animationSpeed number Yes Playback speed multiplier. Must be finite and > 0.

Returns: void

getAnimationSpeed()

Get the current animation speed multiplier.

Parameters: None

Returns: number

isLooping()

Determine whether the current animation is set to loop.

Parameters: None

Returns: boolean

hasAnimation(name)

Check if an animation with the given name exists (requires the object to have started).

Parameters:

Param Type Required Description
name string Yes Animation clip name (case-insensitive).

Returns: boolean

getAnimationNames()

Get a list of available animation clip names (requires the object to have started).

Parameters: None

Returns: string[]

getAnimationDuration(name)

Get the duration (seconds) of an animation clip at speed = 1 (requires the object to have started). Returns 0 if the clip is not found.

Parameters:

Param Type Required Description
name string Yes Animation clip name (case-insensitive).

Returns: number

getCurrentAnimationName()

Get the name of the currently playing animation, or null if none is playing.

Parameters: None

Returns: string | null

getCurrentAnimationTime()

Get the current playback time (seconds) of the active animation. Returns 0 if none. Accounts for speed changes and clamps/mods to clip duration as appropriate.

Parameters: None

Returns: number

getCurrentAnimationNormalizedTime()

Get the normalized playback time (0..1) of the active animation. Returns 0 if none or if duration ≤ 0.

Parameters: None

Returns: number

// This example makes a 3d model cycle through all its animations
const OBJECT_URL = "INSERT 3D MODEL URL";
let obj = figmin.createObject(figmin.ObjectType.MODEL3D, {
            url: OBJECT_URL,
            position: figmin.getWindowSpawnPosition(0.2, "right"),
            rotation: figmin.getWindow().transform.rotation,
            targetSize: 0.163 //This will be the height in meters of the character
        });

// Wait till it starts before operating on the model3d, this ensures the object has loaded
obj.onStart(() => {
    const names = obj.model3d.getAnimationNames(); // An array with all the animation names
    if (!names || names.length === 0) return; // If it has no animations there's nothing to do
    let i = 0; // The current animation index

    // This function plays all the animations of the object one after the other.
    function cycleAnimation() {
        // stop quietly if the object was deleted
        if (obj.status.state === figmin.ObjectState.DESTROYED) return;

        const name = names[i]; // The current animation name
        i = (i + 1) % names.length; // Cycle the animation index for the next run

        // play the animation once (no loop)
        obj.model3d.play(name, false);

        // chain to the next animation after this one finishes
        const durationSeconds = obj.model3d.getAnimationDuration(name);
        setTimeout(cycleAnimation, Math.round(durationSeconds * 1000));
    }

    // Cycle through all the animations
    cycleAnimation();
});

Component: image

The image component is present only on objects of type figmin.ObjectType.IMAGE. It renders a 2D texture in 3D space using either cutout (alpha-tested) or transparent (alpha-blended) materials, with optional scene lighting.

Supported formats: PNG, JPG, WEBP, GIF

Access this component through the image property on a FigminObject.

Note: url and material are read-only (set at creation)
Properties
Name Type Description Access
url string Image source URL set at creation. read-only
material "unlit" | "lit" | "unlit_transp" | "lit_transp" Rendering style. See “Materials” in the notes below for behavior. read-only

Materials:
  - "unlit" → Unlit cutout (alpha-tested). No scene lighting; hard edges where alpha fails.
  - "lit" → Lit cutout (alpha-tested). Receives scene lighting; hard alpha edges.
  - "unlit_transp" → Unlit transparent (alpha-blended). No lighting; smooth transparency.
  - "lit_transp" → Lit transparent (alpha-blended). Receives lighting; smooth transparency.

Component: sketch

The sketch component is always present on objects of type figmin.ObjectType.SKETCH, and can also be added to any other object type. It stores and renders freeform brush strokes using our editor powered by Tilt Brush.

Access this component through the sketch property on a FigminObject.

Important: To fully understand how sketches are created you'll also need to learn:
- How brush strokes are created with figmin.sketch.stroke() or with helpers such as boxStroke()
- How control points are created and what they represent in figmin.sketch.point()
- How to make use of the Brush Catalog in your script

Brush Catalog

The figmin.brushes namespace provides access to the various brushes in our catalog (e.g.,figmin.brushes.MetallicHull).

Consult the Brush Catalog section of this documentation for more details.

Strokes

Sketches are composed of an array of strokes. Strokes are created with figmin.sketch.stroke(), and each stroke contains an array of control points created with figmin.sketch.point().

The Stroke and ControlPoint data formats are shown in the tables below, however you should use the functions previously mentioned to create them, do not assemble the data manually.

Stroke format
Name Type Required Description
id string Yes The Brush ID obtained from the Brush Catalog (e.g., figmin.brushes.MetallicTube)
c string Yes Stroke color as hex #RRGGBB (e.g., "#ff0000").
s number Yes Maximum brush size. Actual rendered width at each control point is modulated by that point’s ps (pressure).
pts Array<ControlPoint> Yes Array of control points. Create each point with figmin.sketch.point(position, rotation?, pressure?). See “ControlPoint format” below.
ControlPoint format
Name Type Required Description
p {x:number, y:number, z:number} Yes Position in the object’s local space.
r {x:number, y:number, z:number, w:number} No Point orientation (quaternion). If omitted, defaults to identity rotation.
ps number No Pressure in [0..1]. Defaults to 1 if omitted. Multiplies the stroke’s maximum size s at this point.
Notes:
- Brush stroke queries use a callback, since the strokes array can be large and is not stored within the FigminObject.
- Strokes are in the object’s local space.
Properties
Name Type Description Access
No properties, use methods to read and write strokes
Methods

setBrushStrokes(strokes)

Replace the current sketch with a new array of brush stroke objects.

Parameters:

Param Type Required Description
strokes Array<Stroke> Yes An array of stroke objects.

Returns: void

getBrushStrokes(callback)

Request all brush strokes currently drawn in this sketch component. The data is delivered asynchronously via the provided callback.

The callback receives an array of stroke objects. Each stroke is in the same compact format accepted by setBrushStrokes() and produced by figmin.sketch.stroke():

{
  id: string,                  // brushId (not a brush object)
  c: string,                   // stroke color in hex (e.g. "#ff0000")
  s: number,                   // maximum stroke size (meters)
  pts: Array<ControlPoint>     // array of control points
}
Important:
The id field is just the brushId string — not a brush object from the Brush Catalog. If you need to resolve an id into a brush object (for example, to read its category or other metadata), use figmin.sketch.getBrushById()

Parameters:

Param Type Required Description
callback function(Array<Stroke>): void Yes Invoked with the array of stroke objects.

Returns: void

Requirements
- Spatial App: No
- Master client: No
Notes:
- The asynchronous callback design avoids storing large stroke arrays directly on the FigminObject.
- Old sketches may contain strokes referencing deprecated brush IDs. These will still be returned here, but may not resolve to catalog entries.
- Use setBrushStrokes() with the array returned here if you want to clone or modify a sketch’s strokes.
 // We'll create a text object and attach a transparent cube sketch around it
const obj = figmin.createObject(figmin.ObjectType.TEXT3D, {
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    rotation: figmin.getWindow().transform.rotation,
    text: "#"
});

// Wait for it to start, then attach a cube sketch on the object
obj.onStart((o) => {
  // Attach the sketch component to the text object
  o.addComponent(figmin.ComponentType.SKETCH);
 
  // Create the cube sketch
  const h = 0.02; 
  const A = { x: -h, y: -h, z: -h };
  const B = { x:  h, y: -h, z: -h };
  const C = { x:  h, y:  h, z: -h };
  const D = { x: -h, y:  h, z: -h };
  const E = { x: -h, y: -h, z:  h };
  const F = { x:  h, y: -h, z:  h };
  const G = { x:  h, y:  h, z:  h };
  const H = { x: -h, y:  h, z:  h };

  const sequence = [A, B, C, D, A, E, F, G, H, E, B, C, G, H, D, A];
  // Convert each vertex in `sequence` into a Sketch ControlPoint.
  // Because we omit rotation and pressure, each point uses the defaults (identity rotation, pressure = 1).
  const cubeStrokePoints = sequence.map(p => figmin.sketch.point(p)); 

  const stroke = figmin.sketch.stroke(
    figmin.brushes.DiamondHull, 
    "#cccccc",
    0.001, // IMPORTANT: It's a CONVEX_HULL brush so we keep the size small to avoid inflating the mesh
    cubeStrokePoints
  );

  o.sketch.setBrushStrokes([stroke]);
});

Component: portal

The portal component is present only on objects of type figmin.ObjectType.PORTAL. It enables a navigable link to another published scene.

Access this component through the portal property on a FigminObject.

Notes:
- Activating a portal requests a scene switch to the target id and terminates the current script/app context.
- The scene id is read-only (assigned at creation).
Properties
Name Type Description Access
scene string Target scene identifier (the ID returned by the publishing flow). Set at creation. read-only
Methods

activate()

Activate the portal and request a scene switch to id.

Parameters: None

Returns: void

Note: Calling activate() ends the current script/app context as the scene switches.

Component: physics

The physics component adds physical simulation to a FigminObject and can be added on runtime with addComponent() . It requires a compatible collider shape and exposes body properties (mass, drag, gravity, kinematic), velocities, motor torque, freeze constraints, collision detection, and optional force-field settings.

Access this component via the physics property. Compatible colliders: BOX, SPHERE, APPROXIMATE. It cannot be used with NONE or EXACT colliders.

addComponent parameters


type: figmin.ComponentType.PHYSICS

params:

Parameter Type Default Required Description
mass number 1 No Mass in kilograms (world/effective). Scales linearly with transform.scale.
drag number 0.05 No Linear drag (dimensionless).
angularDrag number 0 No Angular drag (dimensionless).
gravityStrength number 1 No Gravity multiplier (1=normal, 0=no gravity).
kinematic boolean false No If true, the body is kinematic (“frozen”).
sleeping boolean false No Initial sleep request (true=sleep, false=awake).
velocity {x:number,y:number,z:number} No Initial linear velocity in world space (m/s).
angularVelocity {x:number,y:number,z:number} No Initial angular velocity in world space (rad/s).
motorTorque {x:number,y:number,z:number} No Constant angular acceleration in the object’s local space (rad/s²).
collisionDetectionMode figmin.physics.CollisionDetectionMode CONTINUOUS No Collision detection mode.
freezePosition boolean false No Freeze translation on all axes.
freezeRotationAxes {x:boolean,y:boolean,z:boolean} {x:false,y:false,z:false} No Freeze rotation on selected axes.
Notes:
- Mass scaling: mass scales linearly with transform.scale (a deliberate simplification).
- Assign new vectors: for vector-like properties (velocity, angularVelocity, motorTorque, freezeRotationAxes) always assign a new object; mutating fields in place won’t notify the engine.
- All physics vectors (force, impulse, acceleration, torque, motorTorque) are interpreted in this object’s local coordinate system.
Warning: Requires a compatible collider (BOX, SPHERE, APPROXIMATE). Cannot be added to objects with NONE or EXACT colliders.
Properties
Name Type Description Access
mass number Mass in kilograms (world/effective). Scales with transform.scale. read-write
velocity {x:number,y:number,z:number} Linear velocity in world space (m/s). Assign a new object. read-write
angularVelocity {x:number,y:number,z:number} Angular velocity in world space (rad/s). Assign a new object. read-write
drag number Linear drag (dimensionless). read-write
angularDrag number Angular drag (dimensionless). read-write
gravityStrength number Gravity multiplier (1=normal, 0=no gravity). read-write
kinematic boolean If true, the body is kinematic (“frozen”). read-write
sleeping boolean Sleep hint. true requests sleep; false wakes. read-write
motorTorque {x:number,y:number,z:number} Constant local-space angular acceleration (rad/s²). Assign a new object. read-write
freezePosition boolean Freeze translation on all axes. read-write
freezeRotationAxes {x:boolean,y:boolean,z:boolean} Freeze rotation per-axis. Assign a new object. read-write
collisionDetectionMode figmin.physics.CollisionDetectionMode Collision detection mode. read-write
forceFieldType figmin.physics.ForceFieldType Force field type. read-write
forceFieldForceType figmin.physics.ForceFieldForceType Force field falloff/force model. read-write
forceFieldDirection figmin.physics.ForceFieldDirection Force field direction. read-write
forceFieldReach number Force field reach/radius (meters). read-write
forceFieldAcceleration number Peak linear acceleration inside the field (m/s²). read-write
forceFieldDrag number Linear drag applied inside the field. read-write
forceFieldAngularDrag number Angular drag applied inside the field. read-write
forceFieldRepulsive boolean Polarity: true = repulsive (push), false = attractive (pull). read-write
Methods

applyForce(force)

Apply a force (Newtons) in the object’s local space.

Parameters:

Param Type Required Description
force {x:number,y:number,z:number} Yes Force vector applied relative to the object’s local axes.

Returns: void

applyAcceleration(accel)

Apply a linear acceleration (m/s²) in the object’s local space.

Parameters:

Param Type Required Description
accel {x:number,y:number,z:number} Yes Acceleration applied relative to the object’s local axes.

Returns: void

applyImpulse(impulse)

Apply an impulse (N·s) in the object’s local space.

Parameters:

Param Type Required Description
impulse {x:number,y:number,z:number} Yes Impulse vector applied relative to the object’s local axes.

Returns: void

applyTorque(torque)

Apply a torque (N·m) in the object’s local space.

Parameters:

Param Type Required Description
torque {x:number,y:number,z:number} Yes Torque vector applied relative to the object’s local axes.

Returns: void

applyAngularAcceleration(aaccel)

Apply an angular acceleration (rad/s²) in the object’s local space.

Parameters:

Param Type Required Description
aaccel {x:number,y:number,z:number} Yes Angular acceleration applied relative to the object’s local axes.

Returns: void

Component: physicsMaterial

The physicsMaterial component customizes contact behavior at collision time, including bounciness and friction. It can be added to any object on runtime with addComponent(), it's added automatically when a physics component is attached.

Access this component via the physicsMaterial property on a FigminObject.

addComponent parameters


type: figmin.ComponentType.PHYSICS_MATERIAL

params:

Parameter Type Default Required Description
bounciness number 0.4 No Coefficient controlling rebound energy on contact.
staticFriction number 0.6 No Friction when surfaces are not sliding.
dynamicFriction number 0.6 No Friction while surfaces are sliding.
bounceCombine figmin.physics.Combine AVERAGE No How bounciness is combined with the other collider’s material.
frictionCombine figmin.physics.Combine AVERAGE No How frictions are combined with the other collider’s material.
Notes:
- This component is added automatically when adding a physics component, but can be added manually to non-physics objects.
- Effective contact response depends on both colliders and the selected combine modes (see figmin.physics.Combine).
Properties
Name Type Description Access
bounciness number Controls rebound energy on contact. Default: 0.4. read-write
staticFriction number Friction used when surfaces are not sliding. Default: 0.6. read-write
dynamicFriction number Friction used while surfaces are sliding. Default: 0.6. read-write
bounceCombine figmin.physics.Combine How bounciness combines with the other collider’s material. Default: AVERAGE. read-write
frictionCombine figmin.physics.Combine How friction combines with the other collider’s material. Default: AVERAGE. read-write

Component: light

The light component adds a light source to the FigminObject (POINT, SPOT, or DIRECTIONAL) with optional shadows, effects, and projection patterns. It can be added on runtime with addComponent()

Access this component via the light property on a FigminObject.

addComponent parameters


type: figmin.ComponentType.LIGHT

params:

Parameter Type Default Required Description
color string #d47e13 No Hex color (#RRGGBB).
type figmin.lights.LightType POINT No Light type: POINT, SPOT, or DIRECTIONAL.
range number 4.0 No Attenuation distance in meters (POINT/SPOT only).
spotlightAngle number 30 No Spotlight cone angle in degrees (SPOT only).
rotation {x:number,y:number,z:number} {x:0,y:0,z:0} No Local Euler rotation in degrees.
shadowNearPlane number 0.15 No Shadow near-plane distance in meters.
shadowType figmin.lights.ShadowType NONE No Shadow mode: NONE, HARD, SOFT.
effect figmin.lights.LightEffect NONE No Optional effect (e.g., FLICKER, AUDIO_REACTIVE, PULSE, RAINBOW).
projectionPattern figmin.lights.LightProjection NONE No Projection “cookie” pattern.
Notes:
- range applies only to POINT and SPOT lights; DIRECTIONAL lights have no range.
- spotlightAngle applies only to SPOT lights.
- For rotation, always assign a new {x,y,z} object; mutating fields in place will not notify the engine.
- Use shadowType to enable/disable shadow casting; smaller shadowNearPlane can improve contact shadows but may increase artifacts.
Properties
Name Type Description Access
color string Light color in hex (#RRGGBB). read-write
type figmin.lights.LightType Light type (POINT, SPOT, DIRECTIONAL). read-write
range number Attenuation distance in meters (POINT/SPOT). read-write
spotlightAngle number Spotlight cone angle in degrees (SPOT only). read-write
rotation {x:number,y:number,z:number} Local Euler rotation in degrees. Assign a new {x,y,z} object. read-write
shadowType figmin.lights.ShadowType Shadow mode (NONE, HARD, SOFT). read-write
shadowNearPlane number Shadow near-plane in meters; smaller values can improve contact shadows but may increase artifacts. read-write
effect figmin.lights.LightEffect Optional light effect (e.g., FLICKER, AUDIO_REACTIVE, PULSE, RAINBOW). read-write
projectionPattern figmin.lights.LightProjection Projection “cookie” pattern. read-write

Component: motion

The motion component animates a FigminObject along a keyed path, Keyframes support position, rotation, and absolute time in seconds. It can be added on runtime with addComponent()

Access this component via the motion property on a FigminObject.

addComponent parameters


type: figmin.ComponentType.MOTION

params:

Parameter Type Default Required Description
speed number 1.0 No Playback speed multiplier (> 0).
endDelay number 0.0 No Pause duration (seconds) at the end of each cycle.
randomizeDelay boolean false No Whether to randomize 'endDelay' each cycle.
endBehavior figmin.MotionEndBehavior LOOP No End-of-timeline behavior (see figmin.MotionEndBehavior).
Notes:
- Keyframe rotation input accepts either Euler {x,y,z} (degrees) or quaternion {x,y,z,w}.
- When reading keyframes, rotation is always returned as a quaternion.
- Coordinate space: fixedPlacement = true → keys are in world space; false → keys are relative to the object’s transform.
Properties
Name Type Description Access
speed number Playback speed multiplier (> 0). read-write
endDelay number Pause duration (seconds) at the end of each cycle. read-write
randomizeDelay boolean Whether to add a small random offset to endDelay each cycle. read-write
endBehavior figmin.MotionEndBehavior End-of-timeline behavior (see figmin.MotionEndBehavior). read-write
Methods

setKeyframes(frames, fixedPlacement?)

Define the motion keyframes for this object.

Each keyframe object contains:

  • p — position {x,y,z} in meters
  • r — rotation as Euler {x,y,z} (degrees) or quaternion {x,y,z,w}
  • t — absolute time in seconds

Coordinate space:

  • fixedPlacement = true → keys are in world space
  • fixedPlacement = false → keys are relative to the object’s transform

Parameters:

Param Type Required Description
frames Array<{ p:{x,y,z}, r:{x,y,z}|{x,y,z,w}, t:number }> Yes Keyframe list with position, rotation, and absolute time (seconds).
fixedPlacement boolean No When true, interprets keys in world space; when false, keys are relative to the object.

Returns: void

getKeyframes(callback)

Request the current keyframes.

Parameters:

Param Type Required Description
callback function(data: { frames: Array<{p:{x,y,z}, r:{x,y,z,w}, t:number}>, fixedPlacement: boolean }) : void Yes Invoked with the current keyframes (rotation is always returned as quaternion) and the fixedPlacement flag.

Returns: void

 // We'll create a text object and attach a motion component to make it spin around
const obj = figmin.createObject(figmin.ObjectType.TEXT3D, {
    position: figmin.getWindowSpawnPosition(0.1, "right"),
    rotation: figmin.getWindow().transform.rotation,
    text: "Spin",
    material: "metallic"
});

// Wait for start, then attach a motion component on the object
obj.onStart((o) => {
    // Attach the motion component to the object
    o.addComponent(figmin.ComponentType.MOTION);

    // Create the keyframes, make sure we add enough frames to avoid rotation ambiguities.
    let frames = [];
    for (let i = 0; i <= 8; i++) {
        let angle = i * 45; // 0, 45, ..., 360
        if (angle === 360) angle = 359.9;
        angle = -angle; 
        frames.push({
            p: {x: 0, y: 0, z: 0},
            r: {x: 0, y: angle, z: 0},
            t: i / 8.0
        });
    }
    // Load the keyframes to the new motion component
    o.motion.setKeyframes(frames, false);
});

Component: bodypart

The bodypart component represents a tracked player body part (head or hands) and exposes the ray origin pose used for pointing/aim interactions.

Access this component via the bodypart property on a FigminObject returned by figmin.getPlayerBodypart.

The data of this component is valid if the 'tracked' property is true, listen for state changes with onTrackingChanged()

Warning: This component can't be dynamically added with addComponent()
Properties
Property Type Description Access
tracked boolean True when this bodypart is currently tracked. If false, pose data is outdated/invalid. Read-only
playerId number Numeric identifier of the player this bodypart belongs to. Read-only
bodypartType figmin.BodypartType Specific body part type (e.g., HEAD, LEFT_HAND, RIGHT_HAND). Read-only
inputType figmin.InputType The input mechanism this bodypart is using. Read-only
rayPosition {x:number,y:number,z:number} World-space position of the ray origin (meters). Read-only
rayRotation {x:number,y:number,z:number} World-space rotation of the ray origin (Euler degrees). Read-only
rayRotationq {x:number,y:number,z:number,w:number} World-space rotation of the ray origin (quaternion). Read-only
rayForward {x:number,y:number,z:number} World-space unit forward direction. Read-only
rayUp {x:number,y:number,z:number} World-space unit up direction. Read-only
rayLocalPosition {x:number,y:number,z:number} Local-space offset from the bodypart’s transform to the ray origin (meters). Read-only
rayLocalRotation {x:number,y:number,z:number} Local-space rotation of the ray origin relative to the bodypart’s transform (Euler degrees). Read-only
rayLocalRotationq {x:number,y:number,z:number,w:number} Local-space rotation of the ray origin relative to the bodypart’s transform (quaternion). Read-only
Methods
Name Signature Description
onTrackingChanged function(bodyObj: FigminObject, tracked: boolean) : void Invoked whenever tracking state changes (lost/regained). Assign null to clear.
onGrabChanged function(bodyObj: FigminObject, isGrab:boolean, targetName:string, targetObject: FigminObject) : void Invoked whenever this bodypart grabs a FigminObject, if the object is not tracked targetObject will be null, in that case use findObjectByName(targetName) to begin tracking it. Assign null to clear.

Events

Figmin XR dispatches two primary lifecycle DOM events that your app can listen for. Use these to configure early behavior and start your app logic at the right time.

Order: FigminPreloadFigminReady

FigminPreload

Fires very early, before normal app initialization. Use it only to set engine-level configuration that must be applied before the app starts.


Warning: Only call functions that specifically require this event; the API is not ready at this time.
// Configuring Z-forward can only be done during FigminPreload.
document.addEventListener("FigminPreload", () => figmin.useNegativeZForward(true));

FigminReady

Fires when the figmin namespace is initialized and the runtime connection is ready. This is the safe point to start your app logic.


Notes:
- After this event you can call most APIs: createObject, setUpdateFunction, input APIs, etc.
- If you require a spatial app context or this client isn’t the master, prompt or early out.
// Wait for the FigminReady event before initializing
document.addEventListener("FigminReady", init);

Players

Figmin exposes a lightweight player descriptor called PlayerInfo. It contains only the essentials: a stable id and a displayName. You can obtain the local player descriptor via getLocalPlayer() or a snapshot of everyone in the multiplayer session via getPlayers().

PlayerInfo format
Property Type Description
id number The numeric identifier of this player
displayName string The nickname/alias of this player

PlayerInfo is primarily used as input to getPlayerBodypart, which returns a FigminObject for the requested head/hand. That object includes the bodypart component—this is where the meaningful, real-time data lives (ray origin pose, tracking state, grabbed object callback, etc.).

In summary: retrieve PlayerInfo, then work with body parts via the Bodypart component. Listen for changes with onPlayerConnected() and onPlayerDisconnected().

Example
// Get the local player's right hand
const localPlayer = figmin.getLocalPlayer();
const rightHand  = figmin.getPlayerBodypart(localPlayer, figmin.BodypartType.RIGHT_HAND);

// Wait until the bodypart FigminObject is ready
rightHand.onStart((handObj) => {
  // The bodypart component is available at handObj.bodypart
  // you could start polling it with handObj.onUpdate or with figmin.setUpdateFunction

  // Subscribe to tracking state changes (tracked ↔ not tracked)
  handObj.bodypart.onTrackingChanged((aHandObj, isTracked) => {
    // Tracking state changed; the hand/controller is either tracked or not
  });

    // Get notified when an object is grabbed or released
  handObj.bodypart.onGrabChanged((aHandObj, isGrab, targetName, targetObj) => {
    // isGrab tells us if the object was grabbed or released
    // targetName is the FigminObject.name and is always available
    // IMPORTANT: targetObj will be null if the object isn't tracked, 
    // if you'd like to track it use figmin.findObjectByName(targetName) and it will be non null in future calls
  });
});

// If the system can't find the right-hand object, an error will be reported
rightHand.onError(() => {
  console.warn("Couldn't find right-hand FigminObject");
});

getLocalPlayer


Get the PlayerInfo for the local player.

Use this to access the local player bodyparts (e.g., pass to getPlayerBodypart).


Signature

figmin.getLocalPlayer() => PlayerInfo

Returns: PlayerInfo — The local player's info.

Notes:
- Combine with getPlayerBodypart to query the local player's hands.
- There's no need to track the local player's head, use getCamera instead.
- In multiplayer sessions, the returned player corresponds to the user controlled on this client.

getPlayers


Get a snapshot of all players currently present in the session as an array of PlayerInfo objects (includes the local player).

This is a snapshot at call time; listen for changes via onPlayerConnected and onPlayerDisconnected.


Signature

figmin.getPlayers() => PlayerInfo[]

Returns: PlayerInfo[] — Array of players currently in the session.

getPlayerById


Get a PlayerInfo by numeric ID.

Useful when you have only a player ID (e.g., from input connect) and want to read properties like displayName.


Signature

figmin.getPlayerById(playerId) => PlayerInfo | null

Returns: PlayerInfo | null — The matching player, or null if not found.

Parameters
Param Type Required Description
playerId number Yes Numeric identifier of the player.
Notes:
- You can pass the id directly to getPlayerBodypart —no need to call this function first.

getPlayerBodypart


Get the FigminObject representing a specific player's body part (head or hands). Contains a bodypart component at obj.bodypart and a read-only transform.

Returns a FigminObject immediately; the lookup completes asynchronously. Subscribe to onStart and onError on the returned object to determine the outcome.

Data is only valid if the bodypart is tracked, consult the bodypart component for more information.

Warning: You can't add components of type MOTION or PHYSICS to a player bodypart.
Signature

figmin.getPlayerBodypart(playerOrId, type) => FigminObject | null

Returns: FigminObject | null — A handle to the body part object or null if parameters are invalid.

Parameters
Param Type Required Description
playerOrId number | PlayerInfo Yes Target player, as a numeric ID or a PlayerInfo (e.g., from figmin.getLocalPlayer or figmin.getPlayers).
type figmin.BodypartType Yes The body part to query (e.g., figmin.BodypartType.RIGHT_HAND).
Example
// We'll attach a spotlight to the player's right hand, and turn it on and off as tracking state changes
// Get the local player's right hand
const localPlayer = figmin.getLocalPlayer();
const rightHand = figmin.getPlayerBodypart(localPlayer, figmin.BodypartType.RIGHT_HAND); 

// We must wait until the FigminObject starts 
rightHand.onStart((handObj) => {
  // The light will be rotated in the direction of the hand ray
  const lightLocalRotation = handObj.bodypart.rayLocalRotation;
  const lightRange = 5;
  // Attach a light component to the hand FigminObject, its range depends on whether it’s tracked
  handObj.addComponent(figmin.ComponentType.LIGHT, {
    type: figmin.lights.LightType.SPOT,
    range: handObj.bodypart.tracked ? lightRange : 0,
    spotlightAngle: 25,
    rotation: lightLocalRotation,
    shadowType: figmin.lights.ShadowType.SOFT
  });
  // When tracking changes, the light turns on and off
  handObj.bodypart.onTrackingChanged((obj, isTracked) => {
    // We use the light range to toggle. 
    // We check if light exists because it can be removed by another script
    if (obj.light) {
      obj.light.range = isTracked? lightRange : 0;
    }
  });
});
// If the system can't find right hand an error will be reported
rightHand.onError((handObj) => {
  console.warn("Couldn't find right hand FigminObject");
});

onPlayerConnected


Register (or clear) a callback fired when a player joins the session.

Pass a function to receive a PlayerInfo for the newly connected player. Pass null to clear the callback. Fires only for subsequent joins; use getPlayers for the current snapshot.


Signature

figmin.onPlayerConnected(callback) => void

Returns: void

Parameters
Param Type Required Description
callback (player: PlayerInfo) => void | null Yes Handler invoked on player join, or null to clear.
Notes:
- The callback is invoked once per player that joins the multiplayer session.
- To process existing players, call getPlayers first.

onPlayerDisconnected


Register (or clear) a callback fired when a player leaves the session.

Pass a function to receive a PlayerInfo for the player that disconnected. Pass null to clear the callback.

Signature

figmin.onPlayerDisconnected(callback) => void

Returns: void

Parameters
Param Type Required Description
callback (player: PlayerInfo) => void | null Yes Handler invoked on player disconnect, or null to clear.
Notes:
- The callback is invoked once per player that leaves the multiplayer session.

Functions

The top-level figmin object provides utility functions for managing the app, creating objects, raycasting, input, and more. Many require spatial app mode or master client.

createObject


Create a new object in the scene.

Returns a FigminObject immediately but UNINITIALIZED, objects load asynchronously, use obj.onStart to detect when the object becomes ready.

Consult the Creating Objects section for more details.


Signature

figmin.createObject(type, params?) => FigminObject

Returns: FigminObject — a handle you can use to modify properties, add components, or delete later.

Parameters
Param Type Required Description
type figmin.ObjectType Yes The type of object to create (e.g., TEXT3D, MODEL3D, SKETCH, IMAGE, PORTAL).
params object No Initial properties for the new object. Common fields include:
position: {x,y,z} — world-space position.
rotation: {x,y,z} — Euler degrees.
targetSize: number — uniform size in meters; scales the object so its largest dimension matches this value.
colliderType: figmin.ColliderType — defaults to BOX.
scenePersistent: boolean — keep the object after the app unloads/reloads. Default: false.
Additional fields may be supported depending on the chosen object type (see that type’s section).
Requirements
- Spatial App: No
- Master client: Yes
Notes:
- Wait till object starts before performing operations, including adding components or reading sizes.
- If you plan to attach runtime components, see each component’s “addComponent parameters” table for supported options and defaults.
 // Create a text object that is owned by the scene (will persist after this script ends)
const obj = figmin.createObject(figmin.ObjectType.TEXT3D, {
    position: { x: 0, y: 1, z: 0 },
    rotation: { x: 0, y: 180, z: 0 },
    colliderType: figmin.ColliderType.APPROXIMATE,
    text: "Hello world",
    scenePersistent: true
});

findObjectByName


Find a scene object by name and begin tracking it. Object names are returned by various API calls.

Returns a FigminObject handle immediately but UNINITIALIZED; the lookup completes asynchronously. Listen for obj.onStart to determine whether the object was found, and obj.onError if it wasn't.

Found objects are not owned by the script and will not be destroyed automatically when execution ends.


Signature

figmin.findObjectByName(objectName) => FigminObject

Returns: FigminObject — a an object that will either start if it exists or error if it does not.

Parameters
Param Type Required Description
objectName string Yes The exact name of the object to find.
Requirements
- Spatial App: No
- Master client: Yes
Notes:
- This does not create objects; it starts tracking an existing scene object with the given name.
- You’ll often get untracked names from other APIs (e.g., raycast / collision callbacks). Use this function to convert those names into tracked objects.
- Once it started, the tracked object is fully synchronized and behaves just like a script-owned object except it doesn't belong to the script.
- Avoid finding already tracked objects, if an object is tracked your query may include an "object" reference besides the "objectName".

setUpdateFunction


Registers a callback that runs once per engine frame.

Synchronized with the main Figmin XR rendering loop (higher framerate than the embedded web-view). Recommended for animations, object updates, physics logic, and other time-based calculations. Only one update function can be active at a time; calling this again replaces the previous one.


Signature

figmin.setUpdateFunction(callback) => void

Returns: void

Parameters
Param Type Required Description
callback function(deltaTime: number): void Yes Called every frame. Receives deltaTime in seconds since the last frame.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Avoid heavy or blocking work inside the update; keep per-frame logic lightweight.
- Calling this again replaces the previously registered update function.
Warning:
Avoid using browser-driven loops like requestAnimationFrame or timers — These run at a lower framerate and will cause jitter or inconsistent motion.
figmin.setUpdateFunction((deltaTime) => {
// Update logic here
    obj.transform.rotation.y += 90 * deltaTime;
});

getWindowSpawnPosition


Calculates a position offset from the app window’s edges—handy for spawning objects near or around the user’s view.

Use with figmin.getWindow().transform.rotation if you want the spawned object to face the same direction as the window.


Signature

figmin.getWindowSpawnPosition(padding?, direction?) => { x:number, y:number, z:number }

Returns: {x:number, y:number, z:number} — a world-space position relative to the window.

Parameters
Param Type Required Description
padding number No Offset distance in meters away from the chosen edge. Default: 0.1.
direction string No Direction from the window’s center: "right" | "left" | "up" | "down" | "front" | "back". Default: "right".
Requirements
- Spatial App: No
- Master client: No
Notes:
- The position is computed relative to the current window transform and visible surface size.

getCamera


Gets the player camera object. The returned FigminObject exposes a read-only transform and an intrinsics property.

The camera cannot be destroyed and does not support attaching components.


Signature

figmin.getCamera() => FigminObject

Returns: FigminObject — camera system object with read-only transform and intrinsics.

Requirements
- Spatial App: No
- Master client: No
Intrinsics (read-only)
Name Type Description
fov number Vertical field of view in degrees.
aspect number Width/height aspect ratio.
ipd number Interpupillary distance in meters.
eyes.left / eyes.right object Per-eye frusta. Each eye contains leftTan, rightTan, upTan, downTan (numbers) and proj (flattened 4×4 projection matrix, 16 numbers, row-major).
Notes:
- The camera FigminObject cannot be destroyed and does not support component attachments.
- transform is read-only.
- Both eyes are always present; in non-XR contexts they may be identical by design.

getApp


Get the FigminObject that represents this spatial app container.

The returned object is fully mutable: you can move/rotate/scale it, attach components, and even destroy it (which ends the script).


Signature

figmin.getApp() => FigminObject

Returns: FigminObject — mutable container object for the app.

Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Transform can be freely modified (position/rotation/scale).
- Components may be attached via obj.addComponent(...).
- Requires figmin.isSpatialApp() to succeed; call figmin.requireSpatialApp() if needed.
Warning: Destroying the app object will terminate the running script.

getWindow


Get the FigminObject that represents the app’s window surface.

The window object exposes its transform.size, which reflects the visible 2D surface area of the app (excluding system buttons). Its transform is read-only.

The window’s position/rotation may differ from the app’s transform when special modes are active (e.g., figmin.AppMode.HUD, figmin.AppMode.OBJECT).

This is info is available to non-spatial apps, in contrast to getApp()


Signature

figmin.getWindow() => FigminObject

Returns: FigminObject — read-only object representing the app window.

Requirements
- Spatial App: No
- Master client: No
Notes:
- transform is read-only; you cannot move, rotate, or scale the window directly—use figmin.getApp() instead.
- The window cannot be destroyed and does not support attaching components.

getScene


Get the scene component representing the active scene.

Unlike normal FigminObjects, the scene has no transform. It exposes global lighting, floor, boundary, and shadow settings, and includes a status component for lifecycle events. The scene cannot be destroyed or re-created by user code.


Signature

figmin.getScene() => Scene

Returns: Scene — a global component for environment and lighting controls.

Requirements
- Spatial App: No
- Master client: Yes
Notes:
- The scene has no transform; you cannot move, rotate, or scale it.
- The scene cannot be destroyed and does not support component attachments.
- Use the status component to observe lifecycle/status changes.
Scene component
Properties
Name Type Description Access
mainLightColor string Primary light color as hex (e.g., "#b2ab96"). read-write
mainLightRotation {x:number, y:number, z:number} Primary light local Euler rotation in degrees. Assign a new {x,y,z} object; do not mutate in place. read-write
secondaryLightColor string Secondary light color as hex. read-write
secondaryLightRotation {x:number, y:number, z:number} Secondary light local Euler rotation in degrees. Assign a new object. read-write
ambientLightColor string Ambient light color as hex. read-write
shadowMode figmin.lights.SceneShadowMode Forces shadows on/off or defers to system default. read-write
floorVisibility boolean Show/hide the scene floor/grid. read-write
boundarySize {x:number, y:number, z:number} | null Scene boundary size in meters (local xyz) at unit scale. Each axis is clamped to a minimum of 3. Set null to disable; getter returns null when disabled. read-write
status StatusComponent The scene’s status component. read-only
Methods

onStatusChanged(callback)

Register a listener for scene status changes.

Parameters:

Param Type Required Description
callback function(obj: FigminObject): void Yes Invoked when the scene’s status changes.

Returns: void

isSpatialApp


Returns whether the app is running as a spatial app (deployed in the scene) rather than in the built-in web browser.

Use this check to gate features or trigger a “Deploy as spatial app” flow via figmin.requireSpatialApp.


Signature

figmin.isSpatialApp() => boolean

Returns: booleantrue if running as a spatial app; false if running in the web browser.

Requirements
- Spatial App: No
- Master client: No
Notes:
- Some APIs require a spatial app; when called from the browser, they will no-op and prompt the user to deploy.
- Pair with figmin.requireSpatialApp to surface a “Deploy as spatial app” dialog when needed.

requireSpatialApp


Ensures the app is running as a spatial app.

If not already spatial, this prompts the user to deploy the app into the scene and aborts further execution in the browser context.


Signature

figmin.requireSpatialApp() => void

Requirements
- Spatial App: No
- Master client: No
Notes:
- When called from the browser context, this shows a deploy prompt and halts further script execution in that context.
// If you require spatial app features early out rather than letting the system do it for you
if (!figmin.isSpatialApp()) {
    figmin.requireSpatialApp();
    return;
}

getVersion


Returns the Figmin XR runtime version (host application)


Signature

figmin.getVersion() => string

Returns: string — the runtime version string.

Requirements
- Spatial App: No
- Master client: No
Notes:
- This reports the host application version; the scripting API version is available via figmin.API_VERSION.

isMasterClient


Returns whether this app instance is the master client in a multiplayer session.

Only the master client may perform most state-changing operations; non-master calls are ignored.


Signature

figmin.isMasterClient() => boolean

Returns: booleantrue if this instance is the master client; otherwise false.

Requirements
- Spatial App: No
- Master client: No
Notes:
- Gate state-changing logic behind this check to avoid no-ops and wasted CPU on non-master clients.
// Good practice: early-out on non-master clients to avoid no-ops
if (!figmin.isMasterClient()) {
    return;
}

isMultiplayer


Returns whether this app is in a multiplayer session.

Warning: Figmin XR’s peer-to-peer networking is bandwidth-limited. Very large payloads or high-frequency updates will get the user disconnected.
Signature

figmin.isMultiplayer() => boolean

Returns: booleantrue if this instance is in a multiplayer session; otherwise false.

Requirements
- Spatial App: No
- Master client: No

saveState


Saves the current state of all supported HTML elements that include a figmin-persist-state attribute (its value must be a unique key). The data is stored with the app so it can persist across sessions.

The app itself must be saved to disk (in the scene or as an object) for the data to persist. In other words, this doesn't grant explicit file system access.

Note that the data does persist temporarily if the spatial app's is reloaded. (e.g: user presses "Reload Page")


Supported HTML elements:
- <input type="text|number|range|checkbox|radio">
- <select>
- <textarea>

Signature

figmin.saveState(optionalData?) => void

Parameters
Param Type Required Description
optionalData string No Custom string stored alongside the collected UI state. It will be returned via figmin.loadState(callback). (Default: null)
Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Each element must include a unique figmin-persist-state key (string).
- The app must be saved to disk for the data to persist across sessions.
- If provided, optionalData is returned by figmin.loadState.
// Earlier in the HTML (tag supported elements with a unique key):
<input type="text"   id="textInput"   figmin-persist-state="persistKey1" value="Hello World" />
<input type="number" id="numberInput" figmin-persist-state="persistKey2" value="42" />

// Saves all elements marked with `figmin-persist-state`, plus a custom string
figmin.saveState("custom data");

loadState


Restores the state of all supported HTML elements marked with the figmin-persist-state attribute.

Optionally accepts a callback to to be notified when loading occurs and to receive user-defined data previously saved via figmin.saveState.


Signature

figmin.loadState(callback?) => void

Parameters
Param Type Required Description
callback function(userData: string): void No Invoked when loading occurs with the optional user-defined data saved via figmin.saveState.
Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Only elements with the figmin-persist-state attribute are restored.
- The callback is invoked only when user data was previously saved.
// Restore all persisted elements; receive optional user-defined data (if any)
figmin.loadState((userData) => {
    console.log(userData);
});

useNegativeZForward


Sets the coordinate system so that -Z is considered the forward direction.

This is typically needed when integrating WebGL-based frameworks like Three.js. Call only if you have a concrete reason—this path isn’t thoroughly tested.

Important:
- Must be called during the FigminPreload event; later calls are ignored and a warning is shown.

Signature

figmin.useNegativeZForward(doUse) => void

Parameters
Param Type Required Description
doUse boolean Yes true → treat -Z as forward; false → use the default forward direction.
Requirements
- Spatial App: No
- Master client: No
Warning: Use only if necessary. This code is not thoroughly tested.
// Configuring Z-forward must be done during FigminPreload
document.addEventListener("FigminPreload", () => figmin.useNegativeZForward(true));

setRenderMode


Sets the rendering mode for your app, including stereoscopic 3D modes such as side-by-side (SBS) and over-under (OU).

If you use stereo you must display your content in stereo, this function will render each side to the approriate camera eye.


Signature

figmin.setRenderMode(mode) => void

Parameters
Param Type Required Description
mode figmin.RenderMode Yes One of the values from figmin.RenderMode (e.g., mono, side-by-side, over-under).
Requirements
- Spatial App: No
- Master client: No

setAppMode


Configure the display mode of the spatial app window.

Supported modes:

- DEFAULT: Normal HTML window
- MINIMIZED: Window hidden; rendering stopped; icon shown
- OBJECT: WebView used to render 3D content; always faces the player; interaction disabled; configure bounds via figmin.setObjectModeBounds
- HUD: Wocked in front of the player; FOV capped at 55°
- FULLSCREEN: fills the player’s entire FOV.

Signature

figmin.setAppMode(mode) => void

Parameters
Param Type Required Description
mode figmin.AppMode Yes The desired app window mode. See figmin.AppMode for the full list.
Requirements
- Spatial App: Yes
- Master client: No

setObjectModeBounds


Define the interaction bounding box size for the app window when in figmin.AppMode.OBJECT.

By default, the window’s surface size is used as its bounding box, which may not match the shape of the 3D content rendered inside the WebView.


Signature

figmin.setObjectModeBounds(size) => void

Parameters
Param Type Required Description
size {x:number, y:number, z:number} Yes Local bounding box size at unit scale (1,1,1), in meters (x, y, z).
Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Used only for interaction/selection; it does not change rendering.
- Takes effect only in figmin.AppMode.OBJECT; ignored in other modes.
- Specify the size in meters at unit scale; the effective bounds will scale with the object’s transform.

getObjectModeBounds


Get the interaction bounding box previously set with figmin.setObjectModeBounds.

Returns the local bounding box size (at unit scale) or null if no custom bounds have been defined.


Signature

figmin.getObjectModeBounds() => {x:number, y:number, z:number} | null

Returns: {x:number, y:number, z:number} | null — local bounds in meters at unit scale, or null if none set.

Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Used by OBJECT app mode for interaction/selection; it does not affect rendering.
- Values are expressed in meters at unit scale (1,1,1); effective bounds scale with the object’s transform.

setTransparentBackground


Enables or disables transparent background mode for your spatial app.

When enabled, the HTML background becomes fully transparent so the 3D scene behind it shows through—useful for floating UI, holographic panels, or HUDs.


Important:
- Your HTML must include this meta tag in the <head>: <meta name="transparent" content="true">.
Signature

figmin.setTransparentBackground(isTransparent) => void

Parameters
Param Type Required Description
isTransparent boolean Yes true to enable a transparent HTML background, false to disable.
Requirements
- Spatial App: Yes
- Master client: No

print


Displays a transient text message in front of the local user.

Use for short notifications; the message fades automatically after a brief duration.


Signature

figmin.print(text) => void

Parameters
Param Type Required Description
text string Yes The text to display in front of the local user.
Requirements
- Spatial App: No
- Master client: No

showNavigationArrow


Display a temporary navigation arrow that moves from one point in space to another.

The arrow animates from startPosition toward endPosition in world space—useful for directing the user’s attention to a specific location (e.g., when creating a new object).


Signature

figmin.showNavigationArrow(startPosition, endPosition) => void

Parameters
Param Type Required Description
startPosition {x:number, y:number, z:number} Yes World-space position where the arrow begins.
endPosition {x:number, y:number, z:number} Yes World-space position the arrow points toward.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Intended as a short-lived visual indicator to guide the local user’s attention.
// after creating obj we show where it spawned
figmin.showNavigationArrow(figmin.getWindow().transform.position, obj.transform.position);

debugDraw


Draw a temporary curve in 3D space for a single frame to the local user.

The curve is defined by the ordered list of world-space points. Rendering lasts only for the current frame; the curve is automatically erased on the next frame.


Signature

figmin.debugDraw(points, color?) => void

Parameters
Param Type Required Description
points Array<{x:number, y:number, z:number}> Yes Ordered list of world-space points to connect.
color string No Curve color as a CSS-style hex string. Default: #FFFFFF.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Rendering lasts one frame. To keep the curve visible, call this every frame via setUpdateFunction.
- Intended for debugging visualizations, not permanent geometry.

showLogConsole


Shows the developer log console.

This function is useful when developing in non standard app modes, such as AppMode.OBJECT, where the UI to manually open the developer logs is unavailable.


Signature

figmin.showLogConsole() => void

Requirements
- Spatial App: Yes
- Master client: No

enableInputConnect


Enable motion-controller input connection for a spatial app.


Details:

- Displays a connect icon above the app window (or a specified target object).
- When the user activates the icon, a connection dialog is shown with the provided title, overriding Figmin XR's main menu
- Once connected, only the requested inputs will be delivered back to the app through the various figmin.getInput functions
- An optional callback can notify when the connection state changes.

Signature

figmin.enableInputConnect(connectionTitle, inputCodeArray, connectionChangedCallback?, targetObject?) => void

Parameters
Param Type Required Description
connectionTitle string Yes Title shown in the connection dialog when the user initiates input connection.
inputCodeArray Array<figmin.InputCode> Yes Which inputs to request (e.g., triggers, buttons, thumbsticks). Only inputs listed here will be reported back.
connectionChangedCallback (isConnected: boolean, playerId: number) => void No (Default: null) Invoked when the connection starts or ends. isConnected indicates state; playerId is the numeric player identifier.
targetObject FigminObject No (Default: null) If provided, displays the connect icon on this object instead of the app window.
Requirements
- Spatial App: Yes
- Master client: No
Notes:
- The connect icon appears above the app window by default; use targetObject to attach it to an object instead.
- Once connected, only the inputs listed in inputCodeArray are delivered to your app via figmin.getInput* APIs.
- The callback is optional and fires on both connect and disconnect events.
// Input example
let isConnected = false;

document.addEventListener("FigminReady", () => {
  // Show a connect icon and request A/B button inputs
  figmin.enableInputConnect(
    "Connection test",
    [figmin.InputCode.A, figmin.InputCode.B],
    onConnectionChanged // optional callback
  );

  // Per-frame polling of inputs
  figmin.setUpdateFunction(update);
});

function onConnectionChanged(connected, playerId) {
  isConnected = connected;
  // (optional) console.log(`Input ${connected ? "connected" : "disconnected"} for player ${playerId}`);
}

function update(deltaTime) {
  if (!isConnected) return;

  if (figmin.getInputDown(figmin.InputCode.A)) {
    console.log("A pressed");
  }
  if (figmin.getInputDown(figmin.InputCode.B)) {
    console.log("B pressed");
  }
}

disableInputConnect


Disable motion-controller input connection for the app.

Removes the connect icon from the app window (or the target object if one was specified) and stops delivering controller inputs to the app.


Signature

figmin.disableInputConnect() => void

Requirements
- Spatial App: Yes
- Master client: No

disconnectFromInput


Request disconnection from an active input connection.

Equivalent to the user pressing the “Disconnect” button in the connection UI.


Signature

figmin.disconnectFromInput() => void

Requirements
- Spatial App: Yes
- Master client: No
Notes:
- If a connectionChangedCallback was provided to enableInputConnect, it will be invoked with isConnected = false upon disconnection.
- Has effect only when a connection is currently active; otherwise it is a no-op.
- This does not remove the connect icon; to remove it entirely, call disableInputConnect.

getInput


Get the current value of a connected input as a float.

Analog controls (e.g., triggers, thumbstick axes) return values in [0..1]. Digital controls (buttons) return 0 when not pressed and 1 when pressed.


Signature

figmin.getInput(inputCode) => number

Returns: number — current value for the requested input.

Parameters
Param Type Required Description
inputCode figmin.InputCode Yes The input to query.
Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Valid only after a successful input connection (see enableInputConnect).
- Only inputs requested in inputCodeArray will be reported to your app.

getInputDown


Check if a connected input button was pressed on this frame.

Returns true only on the first frame the input transitions from not pressed to pressed. Useful for detecting discrete button presses.


Signature

figmin.getInputDown(inputCode) => boolean

Returns: booleantrue if the input was pressed this frame; otherwise false.

Parameters
Param Type Required Description
inputCode figmin.InputCode Yes The input to query.
Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Valid only after a successful input connection (see enableInputConnect).
- Only inputs requested in your inputCodeArray are reported.
- Poll this from your per-frame update (e.g., via setUpdateFunction) to catch the frame-edge transition reliably.

getInputUp


Check if a connected input button was released on this frame.

Returns true only on the first frame the input transitions from pressed to not pressed. Useful for detecting discrete button releases.


Signature

figmin.getInputUp(inputCode) => boolean

Returns: booleantrue if the input was released this frame; otherwise false.

Parameters
Param Type Required Description
inputCode figmin.InputCode Yes The input to query.
Requirements
- Spatial App: Yes
- Master client: No
Notes:
- Valid only after a successful input connection (see enableInputConnect).
- Only inputs requested in your inputCodeArray are reported.
- Poll this from your per-frame update (e.g., via setUpdateFunction) to capture the frame-edge transition reliably.

raycast


Cast a ray into the world and invoke a callback with the first hit (if any).

Provide a world-space origin and direction. Optionally filter layers, set a max distance, and request object lookup data.

The callback is always invoked: it receives a single hit info when something is struck, or null if nothing is hit.

Important: The result is returned with a callback and will not be available until the next frame.

Signature

figmin.raycast(params, callback) => void

Parameters
Param Type Required Description
params.origin {x:number, y:number, z:number} Yes Ray start in world space (meters).
params.direction {x:number, y:number, z:number} Yes Ray direction in world space. Does not need to be normalized.
params.layers Array<figmin.Layers> No Layers to test. Default: [figmin.Layers.SURFACE, figmin.Layers.PHYSICS_OBJ, figmin.Layers.STATIC_OBJ].
params.maxDistance number No Max distance in meters. If omitted, the engine default is used.
params.lookupObject boolean No When true, performs an extra lookup to attach figmin object data (slower). See Notes.
callback function(hit: null | { point:{x,y,z}, normal:{x,y,z}, distance:number, layer:figmin.Layers, objectName?:string, object?:FigminObject|null }): void Yes Invoked with hit info or null if nothing was hit.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Defaults test against SURFACE, PHYSICS_OBJ, and STATIC_OBJ layers.
- With lookupObject = true, hits on physics/static objects may include either object (if already tracked) or just objectName. You can later call figmin.findObjectByName(objectName) to start tracking; subsequent raycasts may then return object.
figmin.raycast(
    {
        origin: { x: 0, y: 1, z: 0 },
        direction: { x: 0, y: 0, z: 1 } 
    },
    (hit) => {
        if (!hit) return;
        console.log("raycast hit at", hit.point, "normal:", hit.normal, "distance:", 
            hit.distance, "layer:", hit.layer);
    }
);

raycastAll


Cast a ray into the world and invoke a callback with all hits along the ray (if any).

The callback is always invoked: it receives an array of hit info when something is struck, or null if nothing is hit.

Important: The result is returned with a callback and will not be available until the next frame.

Signature

figmin.raycastAll(params, callback) => void

Parameters
Param Type Required Description
params.origin {x:number, y:number, z:number} Yes Ray start in world space (meters).
params.direction {x:number, y:number, z:number} Yes Ray direction in world space.
params.layers Array<figmin.Layers> No Layers to test. Default: [figmin.Layers.SURFACE, figmin.Layers.PHYSICS_OBJ, figmin.Layers.STATIC_OBJ].
params.maxDistance number No Max distance in meters. If omitted, the engine default is used.
params.lookupObject boolean No When true, performs an extra lookup to attach figmin object data (slower). See Notes.
callback function(hits: null | Array<{ point:{x,y,z}, normal:{x,y,z}, distance:number, layer:figmin.Layers, objectName?:string, object?:FigminObject|null }>): void Yes Invoked with an array of hit infos, or null if nothing was hit.
Requirements
- Spatial App: No
- Master client: No
Notes:
- By default tests against SURFACE, PHYSICS_OBJ, and STATIC_OBJ layers (see figmin.Layers).
- With lookupObject = true, hits on physics/static objects may include either object (if already tracked) or only objectName. You can later call figmin.findObjectByName(objectName) to start tracking; subsequent raycasts may then return object.

raycastSphere


Cast a swept sphere into the world and invoke a callback with the first hit (if any).

Provide a world-space origin, direction, and sphere radius. Optionally filter layers, set a max distance, and request object lookup data.

The callback is always invoked: it receives a single hit info when something is struck, or null if nothing is hit.

Important: The result is returned with a callback and will not be available until the next frame.

Signature

figmin.raycastSphere(params, callback) => void

Parameters
Param Type Required Description
params.origin {x:number, y:number, z:number} Yes Ray start in world space (meters).
params.direction {x:number, y:number, z:number} Yes Ray direction in world space.
params.radius number Yes Sphere radius in meters.
params.layers Array<figmin.Layers> No Layers to test. Default: [figmin.Layers.SURFACE, figmin.Layers.PHYSICS_OBJ, figmin.Layers.STATIC_OBJ].
params.maxDistance number No Max distance in meters. If omitted, the engine default is used.
params.lookupObject boolean No When true, performs an extra lookup to attach figmin object data (slower). See Notes.
callback function(hit: null | { point:{x,y,z}, normal:{x,y,z}, distance:number, layer:figmin.Layers, objectName?:string, object?:FigminObject|null }): void Yes Invoked with the hit info, or null if nothing was hit.
Requirements
- Spatial App: No
- Master client: No
Notes:
- By default tests against SURFACE, PHYSICS_OBJ, and STATIC_OBJ layers (see figmin.Layers).
- With lookupObject = true, hits on physics/static objects may include either object (if already tracked) or just objectName. You can later call figmin.findObjectByName(objectName) to start tracking; subsequent raycasts may then return object.

raycastSphereAll


Cast a swept sphere into the world and invoke a callback with all hits along the ray (if any).

The callback is always invoked: it receives an array of hit info when something is struck, or null if nothing is hit.

Important: The result is returned with a callback and will not be available until the next frame.

Signature

figmin.raycastSphereAll(params, callback) => void

Parameters
Param Type Required Description
params.origin {x:number, y:number, z:number} Yes Ray start in world space (meters).
params.direction {x:number, y:number, z:number} Yes Ray direction in world space.
params.radius number Yes Sphere radius in meters.
params.layers Array<figmin.Layers> No Layers to test. Default: [figmin.Layers.SURFACE, figmin.Layers.PHYSICS_OBJ, figmin.Layers.STATIC_OBJ].
params.maxDistance number No Max distance in meters. If omitted, the engine default is used.
params.lookupObject boolean No When true, performs an extra lookup to attach figmin object data (slower). See Notes.
callback function(hits: null | Array<{ point:{x,y,z}, normal:{x,y,z}, distance:number, layer:figmin.Layers, objectName?:string, object?:FigminObject|null }>): void Yes Invoked with an array of hit info, or null if nothing was hit.
Requirements
- Spatial App: No
- Master client: No
Notes:
- By default tests against SURFACE, PHYSICS_OBJ, and STATIC_OBJ layers (see figmin.Layers).
- With lookupObject = true, hits on physics/static objects may include either object (if already tracked) or only objectName. You can later call figmin.findObjectByName(objectName) to start tracking; subsequent raycasts may then return object.

Sketch Functions

The figmin.sketch namespace provides functions for creating and manipulating 3D strokes with the sketch component. These include low-level drawing primitives like point() and stroke(), as well as higher-level helpers that generate common shapes such as cones, rounded boxes, and other procedural forms.

sketch.stroke


Create a brush stroke object for use with figminObj.sketch.setBrushStrokes().

This helper packages a brush reference, color, max size, and an array of control points (created with figmin.sketch.point()) into the compact format the sketch component expects.

The maximum pressure determines the maximum width of the brush stroke in meters, it is modulated by each control point pressure.


Signature

figmin.sketch.stroke(brush, color, size, points) => object

Returns: object — a stroke formatted for sketch.setBrushStrokes(): { id: <brush.id>, c: <color>, s: <size>, pts: Array<ControlPoint> }.

Parameters
Param Type Required Description
brush object | string Yes Either a brush object from figmin.brushes or a brush.id string.
color string Yes Stroke color in hex format (e.g., "#ff0000").
size number Yes Maximum brush size; actual size per point is modulated by its pressure.
points Array<ControlPoint> Yes Array of control points created via figmin.sketch.point() (each includes position, rotation, and pressure).
// Use a brush object from the catalog
const brush = figmin.brushes.MetallicTube;

// Two control points for a straight line in the object's local space 
const p0 = figmin.sketch.point(
    { x: 0, y: 0,   z: 0 },
    { x: 0, y: 0,   z: 0 },
    brush.minPressure // We use the minimum pressure of this brush to start
);

const p1 = figmin.sketch.point(
    { x: 0, y: 0.2, z: 0 },   // 20 cm above
    { x: 0, y: 0,   z: 0 },
    1 // Final point uses the maximum pressure
);

// Create the stroke with the brush object 
const stroke = figmin.sketch.stroke(
    brush,
    "#40E0D0",
    0.05,  // max size; actual size modulated per-point by pressure
    [p0, p1]
);

// Apply to a Sketch component on your FigminObject
obj.sketch.setBrushStrokes([stroke]);
Requirements
- Spatial App: No
- Master client: No
Notes:
- When passing a brush object, it should be sourced from figmin.brushes (e.g., from the Brush Catalog).
- Ensure all points are created with figmin.sketch.point() to match the expected structure.

sketch.point


Create a control point object for a brush stroke made with figmin.sketch.stroke().

A control point contains a local-space position, rotation, and pressure, representing the state of the motion controller at that moment in the stroke. If rotation or pressure are omitted, defaults are used (identity rotation, pressure = 1).

Pressure

Pressure corresponds to the value of the motion controller’s trigger, ranging from 0 to 1. This determines the effective stroke width at that point as pressure × stroke.size. Each brush in the catalog defines a minPressure, and the effective pressure is clamped to that minimum.

Rotation

Rotation represents the orientation of the motion controller at this point in the stroke. It serves as a suggestion to the renderer, which may sanitize values. For most cases, it is safe to omit rotation and let the engine determine the best orientation.


Signature

figmin.sketch.point(position, rotation?, pressure?) => ControlPoint

Returns: ControlPoint — object formatted for Sketch strokes: { p: <position>, r: <rotation>, ps: <pressure> }.

Parameters
Param Type Required Description
position { x:number, y:number, z:number } Yes Local-space coordinates of the control point.
rotation { x:number, y:number, z:number }
or
{ x:number, y:number, z:number, w:number }
No Orientation at this point. Euler (degrees, XYZ) or Quaternion (normalized). Omit for identity.
pressure number No Brush pressure in [0..1]. Omit to default to 1.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Coordinates are in the FigminObject’s local space.
- Pressure scales the stroke’s width up to the stroke’s size cap provided in sketch.stroke().
- Rotations may be provided as Euler (XYZ, degrees) or Quaternion (x,y,z,w). If using quaternions, provide a normalized value.
- For consistent results, build all points via figmin.sketch.point() before passing them to sketch.stroke.

sketch.getBrushById


Look up a brush object in the Brush Catalog by its id.

You’ll need this function because figminObj.sketch.getBrushStrokes() returns only brush IDs, not the full brush objects. This helper converts an ID back into a catalog entry.

Note: old sketches may contain deprecated brushes that cannot be resolved. In that case this function returns null. You may still create strokes with deprecated brushes by passing the raw ID string directly.


Signature

figmin.sketch.getBrushById(brushId) => object | null

Returns: A brush object from figmin.brushes, or null if not found.

Parameters
Param Type Required Description
brushId string Yes The unique ID of the brush to look up. These IDs are returned by obj.sketch.getBrushStrokes()
Requirements
- Spatial App: No
- Master client: No

sketch.translateStroke


Translates a stroke by the given offset vector, this operation mutates the positions in place

Use this to reposition an existing stroke in sketch space (all coordinates are relative to the sketch), while preserving point rotations and pressure values.


Signature

figmin.sketch.translateStroke(stroke, offset) => object

Returns: The same stroke object with each point’s p translated by offset. Other point fields (e.g., r, ps) are preserved.

Parameters
Param Type Required Description
stroke object Yes A stroke in the form { id, c, s, pts: [{ p:{x,y,z}, r?:{x,y,z,w}, ps?:number }, ...] }.
offset { x:number, y:number, z:number } Yes Translation vector, in meters, applied to each point’s p.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Only point positions are shifted; brush, size, color, rotations (r), and pressure (ps) are preserved.
- Mutates in place, to preserve the original stroke use cloneStroke first.
Example
// Move an existing stroke up by 0.2m
figmin.sketch.translateStroke(aStroke, { x: 0, y: 0.2, z: 0 });

sketch.rotateStroke


Rotates a stroke by the given rotation (Euler or Quaternion). Positions are rotated around a pivot (local origin if none is provided). This operation mutates the stroke in place.

Use this to reorient an existing stroke in sketch space. If a point contains an orientation quaternion r, it is composed as r' = qRot * r.


Signature

figmin.sketch.rotateStroke(stroke, rotation, pivot?) => object

Returns: The same stroke with each point’s position rotated about pivot and each point’s quaternion (if present) left-multiplied by qRot.

Parameters
Param Type Required Description
stroke object Yes A stroke in the form { id, c, s, pts: [{ p:{x,y,z}, r?:{x,y,z,w}, ps?:number }, ...] }.
rotation { x:number, y:number, z:number } or { x:number, y:number, z:number, w:number } Yes Rotation to apply. If three components are provided, treated as Euler degrees. If four components are provided, treated as a quaternion.
pivot { x:number, y:number, z:number } or null No Point to rotate around (meters). Defaults to origin {0,0,0} when null or omitted.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Positions are rotated about pivot; set pivot to a point on your stroke to spin it in place.
- Mutates in place, to preserve the original stroke use cloneStroke first.
Example
// Rotate a stroke 90° around Z, about the local origin (no pivot provided)
figmin.sketch.rotateStroke(aStroke, 
    { x: 0, y: 0, z: 90 }   // Euler degrees but you can pass a quaternion as well
);

sketch.scaleStroke


Scales a stroke by either a uniform factor (number) or a non-uniform vector {x,y,z}. Point positions are scaled; orientations are preserved. Thickness behavior depends on the type of scale (see Notes). This operation mutates the stroke in place.


Signature

figmin.sketch.scaleStroke(stroke, scale, pivot?) => object

Returns: The same stroke with point positions scaled about pivot (or local origin if null).

Parameters
Param Type Required Description
stroke { id?, c?, s?, pts?: Array<{ p:{x,y,z}, r?:{x,y,z,w}, ps?:number }> } Yes The source stroke to scale.
scale number or { x:number, y:number, z:number } Yes Uniform factor (e.g., 1.5) or non-uniform per-axis factors (e.g., {x:1, y:1, z:0.5}).
pivot { x:number, y:number, z:number } or null No Point to scale about (in sketch space, meters). Defaults to origin when null or omitted.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Uniform scale (number k): positions are scaled by k and thickness s is also scaled by k.
- Non-uniform scale ({x,y,z}): positions are scaled per-axis; thickness s is not changed.
- Mutates in place, to preserve the original stroke use cloneStroke first.
Example
// 1) Uniform scale: enlarge by 1.5× about origin (thickness scales too)
figmin.sketch.scaleStroke(aStroke, 1.5);

// 2) Non-uniform scale: flatten along Z about origin (thickness unchanged)
figmin.sketch.scaleStroke(aStroke, { x: 1, y: 1, z: 0.5 });

sketch.calculateStrokeCenter


Computes the axis-aligned bounding-box center of a stroke’s points and returns it as {x,y,z}.

Use this center as a convenient pivot for transforms like rotateStroke or scaleStroke when you want an operation “about the stroke itself.”


Signature

figmin.sketch.calculateStrokeCenter(stroke) => { x:number, y:number, z:number }

Returns: A point (in sketch space, meters) at the center of the stroke’s axis-aligned bounds.

Parameters
Param Type Required Description
stroke { pts?: Array<{ p?:{x,y,z} }>, id?, c?, s? } Yes The stroke whose point positions will be examined to compute the AABB center.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Computes an axis-aligned center (it does not account for stroke orientation).
Example
// Rotate a stroke 90° around Z, about its own center (AABB center)
const pivot = figmin.sketch.calculateStrokeCenter(original);
const rotated = figmin.sketch.rotateStroke(
    original,
    { x: 0, y: 0, z: 90 },  // Euler degrees
    pivot
);

// Scale the stroke down uniformly 0.8× about its center
const scaled = figmin.sketch.scaleStroke(original, 0.8, pivot);

sketch.cloneStroke


Creates and returns a deep copy of a stroke. The clone is safe to modify without affecting the original.


Signature

figmin.sketch.cloneStroke(stroke) => object

Returns: A brand new stroke object with copied fields (id, c, s, pts, etc.). Mutating the clone will not change the source stroke.

Parameters
Param Type Required Description
stroke object Yes Source stroke in the standard stroke format:
{ id, c, s, pts: [{ p:{x,y,z}, r?:{x,y,z,w}, ps?:number }, ...] }
Requirements
- Spatial App: No
- Master client: No
Notes:
- Deep copy: all point objects in pts are duplicated, not referenced.
- Typical use case: generate a variant (scaled/rotated/recolored) without touching the original stroke data.
Example
// Make an independent copy before editing
const copy = figmin.sketch.cloneStroke(original);

sketch.boxStroke


Creates a single-stroke, axis-aligned box wireframe centered at the origin. The path visits all 12 edges (re-walking where needed) so the stroke remains continuous with no jumps. You can also create rectangles by setting one dimension to 0 (e.g., depth = 0).


Signature

figmin.sketch.boxStroke(brush, color, strokeSize, width, height, depth) => object

Returns: A single stroke object representing the box wireframe (centered at origin, axis-aligned).

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color (e.g., "#FF8800").
strokeSize number Yes Stroke thickness in meters.
width number Yes Extent along X (full width of the box). Use 0 for a flat rectangle in X if desired.
height number Yes Extent along Y (full height of the box). Use 0 to collapse along Y.
depth number Yes Extent along Z (full depth of the box). Use 0 for a 2D rectangle in the XY plane.
Requirements
- Spatial App: No
- Master client: No
Notes:
- The geometry is centered at the origin and axis-aligned in sketch space.
- Stroke is continuous (single stroke that traces all edges).
- Dimensions are full extents (not half-extents). For a 1 m cube, pass width=1, height=1, depth=1.
- To position or orient the box, use helpers like translateStroke / rotateStroke after creation.
Example
// Create a 1m × 0.5m × 0.25m box wireframe
const stroke = figmin.sketch.boxStroke(
    figmin.brushes.Wire, "#4CAF50", 0.004, 1.0, 0.5, 0.25);

sketch.capsuleStroke


Creates a single-stroke capsule (two hemispherical caps plus a cylindrical side), Y-up and centered at the origin. The stroke path is continuous, tracing the profile without spatial jumps. Total height is length + 2 * radius.


Signature

figmin.sketch.capsuleStroke(brush, color, strokeSize, radius, length, loops) => object

Returns: A single stroke object describing the capsule shape.

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color (e.g., #FF8A3C).
strokeSize number Yes Stroke thickness.
radius number Yes Hemisphere/cylinder radius (≥ 0).
length number Yes Distance between hemisphere centers (≥ 0). Total height = length + 2 * radius.
loops number Yes Number of wraps along the cylinder side (> 0). Can be fractional.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Y-up orientation; geometry centered at origin.
- Single continuous stroke visiting both caps and the cylindrical side.
- loops controls how many revolutions the side trace makes; fractional values create partial wraps.
Example
// A 0.12 radius capsule with 0.3 length and 2 side loops
const stroke = figmin.sketch.capsuleStroke(
    figmin.brushes.ToonHull, "#4CAF50", 0.001, 0.12, 0.30, 2);

sketch.circleStroke


Creates a single-stroke circle in the XY plane (normal +Z), centered at the origin.
For ellipses, create a circle and then apply scaleStroke with non-uniform factors.


Signature

figmin.sketch.circleStroke(brush, color, strokeSize, radius) => object

Returns: A single stroke object representing the circle path.

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color (e.g., #FF8A3C).
strokeSize number Yes Stroke thickness.
radius number Yes Circle radius.
Requirements
- Spatial App: No
- Master client: No
Notes:
- XY plane, normal +Z; centered at origin.
- Single continuous stroke.
Example
// Circle with radius 0.25
const stroke = figmin.sketch.circleStroke(
    figmin.brushes.MatteHull, "#4CAF50", 0.004, 0.25);

sketch.coneStroke


Creates a single-stroke cone with the tip at +Y and the base at −Y. The path spirals from tip to base for a continuous stroke; loops controls how many full turns it makes.


Signature

figmin.sketch.coneStroke(brush, color, strokeSize, radius, height, loops) => object

Returns: A single stroke object describing the cone’s lateral surface path.

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color (e.g., #FF8A3C).
strokeSize number Yes Stroke thickness.
radius number Yes Base radius at −Y.
height number Yes Distance along Y from base (−Y) to tip (+Y).
loops number Yes Number of full turns from tip to base (> 0). Fractional values allowed.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Y-up orientation; centered at origin (tip at +Y, base at −Y).
- Single continuous stroke spiraling from tip to base.
- Use rotateStroke or translateStroke after creation to reorient or position the cone.
Example
// A cone: radius 0.2, height 0.4, 1.25 loops from tip to base
const stroke = figmin.sketch.coneStroke(
    figmin.brushes.ToonHull, "#4CAF50", 0.004, 0.2, 0.4, 1.25);

sketch.cylinderStroke


Creates a single-stroke helical path over a cylinder (optionally tapered), centered at the origin with poles on +Y (top) and −Y (bottom). The path starts at the top rim, wraps loops times, and ends at the bottom rim.


Signature

figmin.sketch.cylinderStroke(brush, color, strokeSize, radiusTop, radiusBottom, height, loops?) => object

Returns: A single stroke object representing the helix along the cylinder’s side.

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color.
strokeSize number Yes Stroke thickness.
radiusTop number Yes Radius at the top rim (+Y).
radiusBottom number Yes Radius at the bottom rim (−Y).
height number Yes Distance from bottom (−Y) to top (+Y).
loops number No Full turns from top to bottom (> 0). May be fractional. Defaults to 1.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Y-up, centered at origin; helix begins on the top rim and ends on the bottom rim.
- Tapered shape supported: set radiusTop and radiusBottom differently for a frustum-like side.
Example
// Helix with 2.5 loops over a tapered cylinder (top 0.15 → bottom 0.25, height 0.6)
const stroke = figmin.sketch.cylinderStroke(
    figmin.brushes.ShinyHull, "#4CAF50", 0.004, 0.15, 0.25, 0.6, 2.5);

sketch.rectangleStroke


Creates a single-stroke rectangle in the XY plane (normal +Z), centered at the origin.


Signature

figmin.sketch.rectangleStroke(brush, color, strokeSize, width, height) => object

Returns: A single stroke object tracing the rectangle perimeter.

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color.
strokeSize number Yes Stroke thickness.
width number Yes Rectangle width along X.
height number Yes Rectangle height along Y.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Centered at origin; normal +Z.
- Single continuous stroke around the perimeter.
Example
// Rectangle 1.2 × 0.6
const stroke = figmin.sketch.rectangleStroke(
    figmin.brushes.ToonHull, "#4CAF50", 0.004, 1.2, 0.6);

sketch.roundedBoxStroke


Creates a brush stroke that approximates a rounded box using a superquadric point distribution, smaller exponents round more aggressively; larger exponents approach a sharp-edged box. Points are axis-aligned and centered at the origin.

Designed for HULL-category brushes (e.g., ToonHull, DiamondHull), non-HULL brushes may not produce a proper shape..


Signature

figmin.sketch.roundedBoxStroke(brush, color, size, width, height, depth, cornerRadiusXY?, cornerRadiusZ?) => object

Returns: A stroke object: { id, c, s, pts:[{ p, r?, ps? }, ...] }.

Parameters
Param Type Required Description
brush string | object Yes Brush ID or object from the Brush Catalog. Best results with HULL brushes.
color string Yes Stroke color (e.g., "#ff0000").
size number Yes Max brush size; per-point width can vary via stroke/point pressure.
width number Yes Extent along X.
height number Yes Extent along Y.
depth number Yes Extent along Z.
cornerRadiusXY number No Superquadric exponent for rounding in XY (default 0.40). Lower ⇒ more rounded; higher ⇒ boxier.
cornerRadiusZ number No Superquadric exponent for rounding along Z (default 0.40).
Requirements
- Spatial App: No
- Master client: No
Notes:
- Axis-aligned, centered at origin; use translateStroke/rotateStroke to position/orient after creation.
- Superquadrics: smaller exponents round more aggressively; larger exponents approach a sharp-edged box.
Example
// Rounded box (hull brush), mildly rounded corners
const stroke = figmin.sketch.roundedBoxStroke(
    figmin.brushes.ToonHull, "#4CAF50", 0.004, 1.0, 0.6, 0.4, 0.35, 0.35);

sketch.roundedRectangleStroke


Creates a single-stroke rounded rectangle in the XY plane (normal +Z), centered at the origin. roundness is a unitless corner fillet factor from 0 (sharp 90°) to 1 (maximum rounding without overlap).


Signature

figmin.sketch.roundedRectangleStroke(brush, color, strokeSize, width, height, roundness) => object

Returns: A single stroke object tracing straight edges blended with circular corner arcs.

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color.
strokeSize number Yes Stroke thickness.
width number Yes Total width along X.
height number Yes Total height along Y.
roundness number Yes Unitless corner fillet factor (typically 0..1). 0 = sharp; 1 = maximum practical rounding.
Requirements
- Spatial App: No
- Master client: No
Notes:
- The effective corner radius is derived from roundness and clamped so corner arcs don’t overlap (often proportional to 0.5 * min(width, height)).
- Single continuous stroke; edges remain straight, only corners are rounded.
Example
// Rounded rectangle 1.0 × 0.6 with 40% corner roundness
const stroke = figmin.sketch.roundedRectangleStroke(
    figmin.brushes.SmoothHull, "#4CAF50", 0.004, 1.0, 0.6, 0.4);

sketch.sphereStroke


Creates a single-stroke sphere lattice path centered at the origin. The curve weaves around the sphere (mix of latitude/longitude arcs) as one continuous stroke.


Signature

figmin.sketch.sphereStroke(brush, color, strokeSize, radius) => object

Returns: A single stroke object describing a woven path on the sphere surface.

Parameters
Param Type Required Description
brush string | object Yes Brush object or brush id from the Brush Catalog.
color string Yes Stroke color.
strokeSize number Yes Desired stroke thickness.
radius number Yes Sphere radius.
Requirements
- Spatial App: No
- Master client: No
Notes:
- Single continuous path that approximates a spherical grid/lattice.
- Centered at origin; use translateStroke/rotateStroke to position/orient after creation.
- For a filled look, consider HULL-category brushes; for wire look, try line-style brushes.
Example
// Sphere lattice, radius 0.35
const stroke = figmin.sketch.sphereStroke(
    figmin.brushes.MetallicSmoothHull, "#4CAF50", 0.004, 0.35);

Enums

Enums define constant values used throughout the API.

ObjectType

The various object types found in FigminObjects.

Each FigminObject type contains a specific a built-in component that can't be removed.

Most object types can be used by figmin.createObject with the exception of BODYPART which is only found in objects returned by figmin.getPlayerBodypart.

Members
Name Description
MODEL3D A 3D model; includes the model3d component (see component).
TEXT3D 3D text with extrusion/bend; includes the text3d component (see component).
IMAGE A textured image quad; includes the image component (see component).
SKETCH A 3D brush-stroke sketch; includes the sketch component (see component).
PORTAL A portal that navigates to another scene; includes the portal component (see component).
BODYPART A player bodypart, obtained with getPlayerBodypart; includes the bodypart component (see component).
Notes:
- Built-in components are created automatically and cannot be removed.
- Type-specific creation parameters are documented in each component’s section.

ComponentType

Valid component types used by FigminObject.addComponent to attach components at runtime.

Use these to extend an object’s capabilities beyond its built-in component.

Members
Name Description
PHYSICS Adds a physics body to the object; exposes the physics property (see component). Requires a compatible collider (e.g., BOX, SPHERE, APPROXIMATE); not allowed with EXACT/NONE.
PHYSICS_MATERIAL Customizes contact response (bounciness/friction); exposes physicsMaterial (see component). Often paired with PHYSICS, but can be added independently.
LIGHT Adds a light source to the object; exposes light (see component).
MOTION Animates the object along a keyframe path; exposes motion (see component).
SKETCH Adds a sketch (brush strokes) component; exposes sketch (see component). Also built-in on SKETCH objects.
Notes:
- Check each component’s addComponent parameters for defaults and constraints.
- Some components have preconditions (e.g., PHYSICS requires a compatible collider). See their component sections for details.

ObjectState

Lifecycle states reported via a FigminObject’s status component (obj.status.state).

Members
Name Description
UNINITIALIZED Object was just created; data is not yet valid. Most APIs are unavailable at this point
LOADING Object is downloading/processing required data. Some APIs may be unavailable until it becomes READY.
READY Object is ready for use. It may transition back to LOADING if an API call requests a reload or recalculation.
DESTROYED Object was destroyed and can no longer be used. Listen for this via obj.onDestroy.
ERROR Object failed to load/initialize. See status properties description and code for details.
Notes:
- Observe transitions with obj.onStatusChanged(callback) from the status component.
- DESTROYED is terminal; after destruction, the handle should not be reused.

InteractionState

This state controls whether a FigminObject allows user interaction or not.

Scripts can always interact with objects no matter the interaction state, this is a user facing setting only.

Members
Name Description
ENABLED The user can freely move/rotate/scale the object.
LOCKED The user cannot move/rotate/scale the object, but is able to manually remove the lock.
Notes:
- You can't change the interaction state on objects with a read-only transform

ColliderType

Collider shapes assignable to an object’s collider component (collider.type).

The collider is the physical shape of the model.

Members
Name Description
NONE No collider. Object cannot use the physics component while set to NONE.
BOX Axis-aligned box collider. Fast and stable; compatible with physics.
SPHERE Sphere collider. Very fast; good for round or approximate shapes; compatible with physics.
APPROXIMATE Convex mesh approximation of the object. More accurate than primitives; compatible with physics.
EXACT Concave mesh collider for highest fidelity. Not compatible with the physics component.
Notes:
- When a physics component is present, EXACT and NONE are disallowed.
- Prefer BOX/SPHERE for performance; use APPROXIMATE or EXACT only when needed.
- See the collider component for behavior and restrictions when changing types.

BodypartType

Valid player body part types used to address tracked anatomy (head and hands).

Consumed by getPlayerBodypart and exposed on bodypart components via bodypart.bodypartType.

Members
Name Description
HEAD The player’s head object (center eye).
LEFT_HAND The player’s left hand object.
RIGHT_HAND The player’s right hand object.

Layers

Raycastable layers used to filter what your ray tests can hit.

Consumed by raycast, raycastAll, raycastSphere, and raycastSphereAll.

Members
Name Description
SURFACE Environment surfaces (e.g., floor, room mesh, walls).
PHYSICS_OBJ Dynamic physics-enabled objects.
STATIC_OBJ Static/non-dynamic scene objects.
UI UI elements rendered in the scene.
Notes:
- The raycast defaults are SURFACE, PHYSICS_OBJ, and STATIC_OBJ (UI is excluded unless you request it).
- Pass an array (e.g., [figmin.Layers.UI, figmin.Layers.SURFACE]) to limit hits to specific layers.

RenderMode

Valid rendering modes used by figmin.setRenderMode.

Controls whether the app renders as standard 2D UI or in stereoscopic 3D layouts.

Members
Name Description
STANDARD Displays UI in 2D (like a normal web browser).
SBS_3D Stereoscopic 3D — Side-by-Side: left eye on the left half, right eye on the right half.
OE_3D Stereoscopic 3D — Over-Under: left eye on the upper half, right eye on the lower half.
Notes:
- Use stereoscopic modes only when your content is authored for SBS/OU layouts.

AppMode

Different modes the app can be set to via figmin.setAppMode.

Controls how the app window is presented in the scene.

Members
Name Description
DEFAULT Renders the HTML content normally in the app window.
MINIMIZED Hides the window and stops rendering; an icon is shown in its place.
OBJECT Intended for rendering 3D content using the WebView. Always faces the player (billboard) and user interaction is disabled. Configure its interaction bounds with figmin.setObjectModeBounds.
HUD Locks the window in front of the player with a capped field of view of 55°.
FULLSCREEN Fills the player’s entire field of view.
Notes:
- In HUD and OBJECT modes the window’s pose can differ from the app object’s transform.

MotionEndBehavior

Controls what happens when a motion path reaches its end, used by the motion component.

If not specified in the component’s parameters, the default is LOOP.

Members
Name Description
LOOP When the timeline reaches the end, it restarts from the beginning and repeats continuously. (Default)
PING_PONG When the timeline reaches the end, it reverses direction and plays back toward the start, then forward again, and so on.
Notes:
- endDelay (and randomizeDelay, if enabled) is applied at each loop/turnaround boundary.
- Works with keyframes defined via motion.setKeyframes(...).

InputCode

The different inputs that can be requested via figmin.enableInputConnect and queried with the getInput, getInputDown, and getInputUp APIs.

Request only the inputs you intend to read to keep processing lightweight.

Members
Name Description
A Button A on the controller.
B Button B on the controller.
X Button X on the controller.
Y Button Y on the controller.
GRIP_LEFT Left grip button on a motion controller (or bumper on a gamepad).
GRIP_RIGHT Right grip button on a motion controller (or bumper on a gamepad).
SELECT_LEFT Left trigger button.
SELECT_RIGHT Right trigger button.
AXIS_X_RIGHT X axis of the right thumbstick.
AXIS_Y_RIGHT Y axis of the right thumbstick.
AXIS_X_LEFT X axis of the left thumbstick.
AXIS_Y_LEFT Y axis of the left thumbstick.
THUMB_LEFT Left thumbstick press (button).
THUMB_RIGHT Right thumbstick press (button).
Notes:
- getInput returns a float; axes are in [0..1] and buttons are 0 or 1.
- Use getInputDown/getInputUp to detect discrete button press/release frames.

InputType

The type of input mechanism a bodypart is using.

Members
Name Description
HAND_TRACKING Hands free controls.
MOTION_CONTROLLER A motion controller.
TOUCH_SCREEN Touch screen controls are found in smartphones.

physics.CollisionDetectionMode

How the physics engine detects collisions for a body (see physics component).

Choose a mode based on speed/accuracy needs vs. performance. Default in physics params: CONTINUOUS.

Members
Name Description
DISCRETE Standard step-based collision checks. Fastest; suitable for most slow/medium-speed bodies.
CONTINUOUS Reduces tunneling for faster motion by using continuous checks against the world. (Default)
CONTINUOUS_DYNAMIC Higher accuracy continuous detection for fast-moving dynamic bodies. Higher cost.
CONTINUOUS_SPECULATIVE Speculative contacts to anticipate impacts. Good robustness at moderate cost.
Notes:
- Use more conservative/continuous modes for small, fast objects to avoid tunneling.
- Pair with an appropriate ColliderType and timestep for best results.

physics.ForceFieldType

The shape of the force field applied by the physics component.

Controls how acceleration is distributed in space.

Members
Name Description
NONE No force field is applied.
SPHERE Radial field from the object’s origin, limited by forceFieldReach.
FLAT Planar field with a single push/pull direction (see ForceFieldDirection).
Notes:
- Strength/falloff configured via forceFieldAcceleration and forceFieldForceType on the physics component.

physics.ForceFieldForceType

Force falloff model for a physics component force field.

Determines how acceleration changes with distance.

Members
Name Description
SQUARED Inverse-square style falloff; stronger near the source, weaker with distance.
CONSTANT No falloff; uniform strength within forceFieldReach.

physics.ForceFieldDirection

Direction of a planar (FLAT) force field on the physics component.

Applied in the object’s local coordinate system.

Members
Name Description
UP Positive local Y.
DOWN Negative local Y.
LEFT Negative local X.
RIGHT Positive local X.
FORWARD Positive local Z.
BACK Negative local Z.
Notes:
- Only relevant when ForceFieldType is FLAT.
- The effective world direction changes with the object’s rotation.

physics.Combine

How two physics materials combine their friction/bounce, used by the physicsMaterial component.

The effective contact uses both colliders’ materials and the selected combine modes.

Members
Name Description
AVERAGE Mean of the two values.
MULTIPLY Product of the two values.
MINIMUM Lower of the two values.
MAXIMUM Higher of the two values.
Notes:
- See physicsMaterial properties bounceCombine and frictionCombine (default: AVERAGE).

lights.LightType

Types of lights supported by the light component.

Select the light’s emission model. Default in light: POINT.

Members
Name Description
SPOT A cone-shaped light. Use with spotlightAngle; affected by range.
DIRECTIONAL Sun/sky style light with parallel rays. No attenuation with distance.
POINT Omnidirectional point source. Intensity attenuates with range. (Light default)
Notes:
- For SPOT/DIRECTIONAL, set orientation via light.rotation (Euler degrees).
- Shadows/effects are configured separately (see enums below).

lights.ShadowType

Shadow rendering modes for the light component.

Controls if/how the light casts shadows. Default in light: NONE.

Members
Name Description
NONE No shadows are cast.
HARD Enables shadow casting with hard edges.
SOFT Enables filtered, softer-edged shadows.
Notes:
- Pair with shadowNearPlane on light to tune contact shadows.
- Global toggles are available at the scene level via SceneShadowMode.

lights.LightEffect

Special visual effects for the light component.

Applies time-based or reactive behaviors. Default: NONE.

Members
Name Description
NONE No special effect; steady illumination.
FLICKER Random light intensity flicker (e.g., torch/firelight vibe).
AUDIO_REACTIVE Light reacts to audio amplitude (device/runtime dependent).
PULSE Periodic pulsing of intensity.
RAINBOW Cycles hue over time for colorful effects.

lights.LightProjection

“Cookie” projection patterns for the light component.

Projects a texture-like pattern through the light. Default: NONE.

Members
Name Description
NONE No projection pattern.
FLASHLIGHT1 Flashlight-style beam pattern.
SPOTLIGHT1 Spotlight gobo pattern #1.
SPOTLIGHT2 Spotlight gobo pattern #2.

lights.SceneShadowMode

Global shadow override for the active scene (via getScenescene.shadowMode).

Forces shadows on/off or defers to the system default. Default: DEFAULT.

Members
Name Description
DEFAULT Use the runtime’s default shadow behavior.
FORCE_ON Force-enable scene shadows (where supported).
FORCE_OFF Force-disable scene shadows.

Multiplayer

All FigminObjects are networked by default: when your script changes a property on an object or component, that change replicates to all peers automatically. Figmin XR's multiplayer is peer-to-peer.

Authority & Master Client

Each Spatial App has a master client—the peer who created it. The master executes the script without restrictions. On non-master peers the script still runs, but most write/create operations are ignored (no-ops).

If the master-client disconnects, a new master client is elected, the script will reload and the process will start again.

  • figmin.isMasterClient() → Use this to early-out on non-masters.
  • Non-masters can load the app and read state, but should avoid making changes.
  • This keeps multiplayer simple: one script instance performs authoritative work.
Authoritative Pattern (Recommended)

Write your app as if it were single-player, then gate mutations behind the master-check. This avoids wasted CPU on non-masters.

function init() {        
    // Early-out on non-masters
    if (!figmin.isMasterClient()) {
        return;
    }

    // Master-only section: create objects, perform mutations, etc
}
UI & Interaction
  • Since only the master client executes code, the UI will be inoperable on non-master peers without additional work.
Planned: A lightweight messaging channel for non-masters to signal intent to the master is planned. Until then, assume only the master operates the UI that changes shared state.
Warning: Figmin XR’s peer-to-peer networking is bandwidth-limited. Very large payloads or high-frequency updates may be automatically throttled; if the load remains excessive, the sending peer can be disconnected to protect session stability.

Brush Catalog

The Brush Catalog contains descriptors for every brush available in Figmin XR. Each entry defines the metadata and behavior of a brush, such as its category, minimum pressure, and whether it is audio-reactive.

Note: Brushes are used to create strokes with figmin.sketch.stroke() or the various sketch functions.

The API defines the figmin.brushes namespace, which exposes all brush definitions listed in the brush catalog table below (e.g., figmin.brushes.MetallicTube).

Each brush object in the catalog exposes the following properties:

Brush properties
Name Type Description
id string Unique identifier for this brush. This is what appears in stroke objects as id.
name string Human-readable name of the brush.
category string Category of this brush.
Possible values: "FLAT", "3D", "PARTICLES", "CONVEX_HULL".
minPressure number The minimum pressure the brush supports. Effective pressure in a stroke is clamped to this value.
audioReactive boolean Whether the brush responds dynamically to audio input
description string The description of this brush, as shown in the catalog section below

Brush Category

Brushes in Figmin XR fall into four distinct categories, each with very different rendering behaviors:

"FLAT" — A 2D paint-like stroke, typically used to represent a stroke of paint on a surface. The renderer will automatically segment sharp angles into multiple strokes.

"3D" — A volumetric stroke with depth. These brushes generate 3D geometry along the path of the control points, giving strokes a sculpted or extruded appearance.

"CONVEX_HULL" — A special type of stroke that produces a convex mesh enclosing all control points. This can create hull-like or solid shapes. Use a small stroke size unless you explicitly want to inflate the resulting mesh.

"PARTICLES" — A particle system brush. At each control point, particles are emitted according to the brush’s definition, resulting in effects such as sparks, smoke, or trails.

Below is the list of available brushes in the catalog. Use them in code by prefixing the name with figmin.brushes. (e.g., figmin.brushes.MetallicTube).

Note: Each catalog entry corresponds to a full brush object exposing the properties described above (id, name, category, minPressure, audioReactive, description). Audio-reactive brush names end with _AR.
Catalog
Name Category Description
OilPaint FLAT Slightly rough-textured brush strokes
Ink FLAT Smooth paint with tapered brush strokes. Good for adding detail, creating foliage, and calligraphy
ThickPaint FLAT Rough-textured brush strokes
WetPaint FLAT Shiny & thick brush strokes. Good for creating shiny surfaces and details
Gouache FLAT Matte, textured brush strokes. Good for details
DryBrush FLAT
Flat FLAT Shaded flat brush
Marker FLAT Unshaded flat brush
TaperedFlat FLAT Flat brush, tapered on one end. Use short brush strokes to create flower petals
TaperedMarker FLAT Flat brush, tapered on one end. Use short brush strokes to create flower petals
TaperedHueShift FLAT Flat brush, tapered on one end. Use short brush strokes to create flower petals
DoubleTaperedFlat FLAT Flat brush, tapered on both ends. Use short brush strokes to create individual leaves
DoubleTaperedMarker FLAT Flat brush, tapered on both ends. Use short brush strokes to create individual leaves
DoubleTaperedHue FLAT Tapered on both ends with hue shift colors
SoftHighlighter FLAT Creates transparent, glowing brush strokes. Good for light rays, clouds, and adding glow
SoftHighlighter_AR FLAT Creates transparent, glowing brush strokes. Good for light rays, clouds, and adding glow - Audio Reactive
Highlighter FLAT Creates transparent, glowing brush strokes. Good for light rays, clouds, and adding glow
VelvetInk FLAT Transparent brush strokes. Good for sketching
VelvetInk_AR FLAT Transparent brush strokes. Good for sketching - Audio Reactive
DuctTape FLAT Large, flat textured brush. Good for creating flat textured surfaces
Paper FLAT Large, flat, slightly textured brush. Good for creating flat surfaces
CoarseBristles FLAT Scattered bristle brush strokes. Good for creating grass & fur
WigglyGraphite FLAT Creates rough animated brush strokes. Good for adding subtle movement to water, landscapes, characters, etc
WigglyGraphite_AR FLAT Creates rough animated brush strokes. Good for adding subtle movement to water, landscapes, characters, etc - Audio Reactive
CelVinyl FLAT Flat, tapered brush with black outlines. Good for stylized cartoon designs
Charcoal FLAT Good for adding rough texture to surfaces
Light2 FLAT Creates bright brush strokes
Light2_AR FLAT Creates bright brush strokes - Audio Reactive
Light FLAT Creates bright brush strokes
Light_AR FLAT Creates bright brush strokes - Audio Reactive
Fire2 FLAT Creates animated fire effects
Fire2_AR FLAT Creates animated fire effects - Audio Reactive
Fire FLAT Creates animated fire effects
Fire_AR FLAT Creates animated fire effects - Audio Reactive
Embers PARTICLES Creates animated rising motes of light
Embers_AR PARTICLES Creates animated rising motes of light - Audio Reactive
Comet FLAT
Comet_AR FLAT - Audio Reactive
Smoke PARTICLES Creates floating, 3D smoke. Layer multiple colors together to create gradients
SmokeTiny PARTICLES Creates floating, 3D smoke. Layer multiple colors together to create gradients
Wind FLAT
Stars PARTICLES Creates animated stars
Stars_AR PARTICLES Creates animated stars - Audio Reactive
Waveform FLAT Creates an animated waveform. Use brighter or darker colors to change the speed of animation
Waveform_AR FLAT Creates an animated waveform. Use brighter or darker colors to change the speed of animation - Audio Reactive
WaveformFFT FLAT Creates an animated fourier transform. Use brighter or darker colors to change the speed of animation
WaveformFFT_AR FLAT Creates an animated fourier transform. Use brighter or darker colors to change the speed of animation - Audio Reactive
ChromaticWave FLAT Creates an animated, rainbow waveform. Useful for energy effects & sci-fi designs
ChromaticWave_AR FLAT Creates an animated, rainbow waveform. Useful for energy effects & sci-fi designs - Audio Reactive
Plasma FLAT Creates animated plasma
Plasma_AR FLAT Creates animated plasma - Audio Reactive
Electricity FLAT Creates animated lightning. Use brighter or darker color to change lightning intensity
Electricity_AR FLAT Creates animated lightning. Use brighter or darker color to change lightning intensity - Audio Reactive
Splatter FLAT Scattered spatter brush strokes. Good for creating moss, foliage, & fluffy textures
Streamers FLAT Creates animated trails of light. Good for creating fireworks, running water, and magic effects
Streamers_AR FLAT Creates animated trails of light. Good for creating fireworks, running water, and magic effects - Audio Reactive
Hypercolor FLAT Creates animated iridescent brush strokes.
Hypercolor_AR FLAT Creates animated iridescent brush strokes. - Audio Reactive
HypercolorTransparent FLAT Creates animated iridescent translucent brush strokes.
HypercolorTransparent_AR FLAT Creates animated iridescent translucent brush strokes. - Audio Reactive
Snow PARTICLES Creates animated falling snowflakes. Small brush sizes & other colors can be used to simulate falling particles
Snow_AR PARTICLES Creates animated falling snowflakes. Small brush sizes & other colors can be used to simulate falling particles - Audio Reactive
Bubbles PARTICLES Creates animated bubbles
RisingBubbles PARTICLES Creates animated bubbles
Hearts PARTICLES Creates animated hearts
Dots PARTICLES Creates glowing dots in a line. Useful for creating a variety of glowing light sources
Dots_AR PARTICLES Creates glowing dots in a line. Useful for creating a variety of glowing light sources - Audio Reactive
Fairy FLAT Creates an animated glitter effect. Good for creating magical effects and glittering surfaces
ShinyHull CONVEX_HULL Creates shiny 3D shapes
MatteHull CONVEX_HULL Creates matte 3D shapes
UnlitHull CONVEX_HULL Creates unshaded 3D shapes
DiamondHull CONVEX_HULL Creates transparent, shiny 3D shapes. Good for making water, ice, crystals, and glass surfaces
MetallicHull CONVEX_HULL Creates metallic 3D shapes
StainedGlassHull CONVEX_HULL Creates textured glass shapes
ToonHull CONVEX_HULL Creates cartoon style 3D shapes
SmoothHull CONVEX_HULL Creates smooth, shiny 3D shapes
SmoothMatteHull CONVEX_HULL Creates smooth, matte 3D shapes
MetallicSmoothHull CONVEX_HULL Creates smooth metallic 3D shapes
SmoothDiamondHull CONVEX_HULL Creates smooth transparent 3D shapes. Good for making water, ice, crystals, and glass surfaces
MetallicTube 3D
Icing 3D Creates textured, 3D brush strokes. Good for wood, stems, snow, and frosting
Toon 3D Creates 3D brush strokes with black outlines. Good for stylized cartoon designs
Toon_AR 3D Creates 3D brush strokes with black outlines. Good for stylized cartoon designs - Audio Reactive
MylarTube 3D Metallic, 3D brush strokes. Useful for jewelry & metal filigree. Use short brush strokes to create mushrooms
TubeAdditive 3D
MetallicWire 3D Metallic tapered tubes
DiamondWire 3D Diamond tapered tubes
ToonWire 3D Cartoon style tapered tubes
Wire 3D Unshaded 3D brush strokes. Combine with Unlit Hull to add detail to unshaded shapes
Spikes 3D Good for creating vines, stems, horns and spikes
MetallicSpikes 3D
SpikesToon 3D Good for creating vines, stems, horns and spikes
Lofted 3D Creates thick, pointed brush strokes
LoftedMetallic 3D Creates thick, pointed metallic brush strokes
LoftedToon 3D Creates cartoon style pointed brush strokes
LoftedHueShift 3D Creates thick, pointed brush strokes
BubbleWand 3D Creates iridescent, 3D bubble shapes with a floaty animation. Useful for clouds, fantasy creature parts, and bubbles
SquarePaper 3D Creates rectangular 3D brush strokes. Good for architecture and other non-organic shapes
Feather FLAT
Feather_AR FLAT - Audio Reactive
Petal 3D Creates 3D flower shapes. Use short brush strokes to create flowers & leaves, or long brush strokes to create vines
Rainbow FLAT Creates animated rainbows. Not effected by brush color
Rainbow_AR FLAT Creates animated rainbows. Not effected by brush color - Audio Reactive
Disco 3D Shiny disco tubes
Disco_AR 3D Shiny disco tubes - Audio Reactive
NeonPulse FLAT Creates transparent tubes with animated neon light pulses. Useful for neon signs, magical items, and sci-fi designs
NeonPulse_AR FLAT Creates transparent tubes with animated neon light pulses. Useful for neon signs, magical items, and sci-fi designs - Audio Reactive
Muscle 3D Tapered, muscle-textured 3D brush strokes. Good for creating creatures
Guts 3D Rounded, shiny-textured 3D brush strokes. Good for horns, coral, and, yes - guts
Rain FLAT Creates animated droplets. Good for creating running water, fireworks, and magical effects
HyperGrid FLAT Creates sci-fi grid shapes. Useful for sci-fi designs
HyperGrid_AR FLAT Creates sci-fi grid shapes. Useful for sci-fi designs - Audio Reactive
ArrowsBrush FLAT Creates animated arrows
LightWire 3D
LightWire_AR 3D - Audio Reactive
InvisibleHull CONVEX_HULL Creates invisible shapes that block out all digital content. Useful for creating occlusion and portal entrances

Development Guide

This guide covers two workflows for Figmin XR spatial apps:

  • Development: run your HTML from a local web server so you can iterate quickly and simply reload in Figmin XR to see changes.
  • Release: embed your HTML into the spatial app by offering a downloadable file in the Figmin XR browser; no server required after deployment.
Heads-up

You don’t need a web server to publish. When an HTML file is offered as a download in the Figmin XR browser, a dialog will prompt to load the spatial app and its contents are embedded directly into Figmin XR. During development, though, a local server makes iteration faster.

Development workflow (web server)

During development you’ll serve your .html from your computer and open it from the Figmin XR browser using your machine’s IP address. That way, edits are reflected immediately, just reload the web-app in Figmin XR.

1) Start a simple local server

We recommend Python’s built-in HTTP server. Open a terminal in the folder that contains your app’s HTML and run:

python -m http.server 8000

This serves the current folder at http://<your-ip>:8000.

To open a terminal in Windows search for "Command Prompt", for Mac OS simply type "Terminal"

2) Find your computer’s IP address

Use your OS network settings (Wi-Fi/Ethernet details). You’re looking for something like 192.168.0.23 or 10.0.0.10 on your local network.


You can also obtain your IP address from a terminal, in Windows (Command Prompt) type:

ipconfig

Look for the line labeled IPv4 Address.

3) Open it from Figmin XR

In Figmin XR, open the in-app browser and type <your-ip>:8000.
You’ll see the directory listing from your server. Tap your HTML (e.g., my-app.html) to load your spatial-app.

4) Edit → Reload loop

Edit your files on your computer, then in Figmin XR just reload the page to see changes. No redeploy step is needed while developing.

Warning:

Do not publish a spatial app that points to a local web server (e.g., an IP address such as 192.168.x.x)—it won’t work and it isn’t safe.

You may absolutely publish a spatial app that uses a real internet web server; this also gives you control over future app updates.

Release Workflow (embed your app)

Once your app is ready for release, you’ll offer an HTML file for download inside the Figmin XR browser. Figmin XR will prompt to deploy the spatial app; on deploy, the HTML is embedded into the app’s data, no server needed at runtime. This is the recommended way to publish single-file apps.


How do I offer the file for download?


Discord: On your computer, drag and drop your HTML into your discord server. In Figmin XR sign in to Discord and click the file to download and deploy.


AI assistant link: If you use an AI assistant that you can can log into from Figmin XR, ask it to generate a direct download link to your HTML file. Open the link in the Figmin XR browser to download and deploy.

Tip: Make sure it’s a direct file URL (ends in .html), not a preview page.

Immutability after publishing

Once deployed, the embedded HTML cannot be updated in place. Only use this workflow when your app is ready to ship

Multi-file / complex apps

If your app spans multiple files (modules, assets, etc.), you can host them on an Internet web server. Doing so gives you full control over future updates—just update your hosted files and users will pull the new version next launch.

Complete Examples

This section showcases complete, ready-to-run examples demonstrating how to build spatial apps with the Figmin XR API. Examples range from beginner to advanced and were mostly generated with AI.

Each example includes two actions: View Code and Download / Run. When you click "Download / Run" within Figmin XR, a dialog will appear asking if you’d like to load the spatial app. The contents of the file are then embedded directly into Figmin XR, so no web server is required.

Note for AI assistants: The example source code is loaded dynamically from its URL. Many AI tools may not be able to access or display this code directly. If you need the full source, please ask the user to copy it for you.

Controllable Character


This spatial app creates an animated character that the user can control. It can walk, run, jump, and emote.

Difficulty: Advanced

How it works

  1. Create a MODEL3D object for the character.
  2. Enable controller input with enableInputConnect and start the game loop via setUpdateFunction.
  3. On each update, read input (axes/buttons) with getInput, advance a small state machine (idle/walk/run/jump/emote), and apply movement.
  4. Use raycast to detect floor/steps/overhead obstacles and to keep motion grounded.

API used

onStart, setUpdateFunction, createObject(MODEL3D), getCamera, getWindowSpawnPosition, getWindow, enableInputConnect, getInput, getInputDown, InputCode, transform model3d raycastSphere, Layers

Code


RC Airplane


This example creates an interactive, physics-driven RC airplane you can fly around your room. Lift, drag, thrust, and control-surface torques are computed each frame to simulate flight.

Difficulty: Hardcore

How it works

  1. Create a MODEL3D airplane with URL, targetSize, and colliderType set in createObject params. Spawn it next to the app window using getWindowSpawnPosition.
  2. When the model starts, attach a physics component and wire up inputs: enableInputConnect.
  3. Run a per-frame flight loop with setUpdateFunction: read controls via getInput (InputCode), compute lift/drag, apply thrust, and use the physics API to apply forces/torques.
  4. For ground effect, cast near-ground probes with raycast against Layers; optionally visualize vectors with debugDraw.
  5. Gate browser usage with isSpatialApp / requireSpatialApp so users can deploy/run as a spatial app.

API used

onStart, setUpdateFunction, createObject (ObjectType.MODEL3D), ColliderType.APPROXIMATE, getWindowSpawnPosition, getWindow, enableInputConnect, getInput (InputCode.*), physics (mass/drag, collision detection mode, applyForce, applyTorque), raycast, Layers, debugDraw, isSpatialApp, requireSpatialApp, transform, ObjectState.READY

Code


Player Wisps


Glowing “wisps” flock toward players’ hands and swirl playfully around them. As hands move, nearby wisps get tugged along, creating a subtle “wind” effect. If the player grabs an object, the wisps will follow it for a short while.

Difficulty: Intermediate

How it works

  1. Wait for the FigminReady event.
  2. Query the current players with getPlayers, then subscribe to onPlayerConnected / onPlayerDisconnected to keep the set in sync.
  3. For each player, obtain hand bodyparts via getPlayerBodypart (BodypartType.LEFT_HAND / RIGHT_HAND).
  4. Spawn a flock of SKETCH dots (wisps) with createObject one of them has a POINT light for extra sparkle.
  5. Each wisp is set to interactionState = figmin.InteractionState.LOCKED to prevent the user from manipulating it.
  6. Drive updates with setUpdateFunction:
    • Compute each tracked hand’s velocity from the bodypart ray origin positions.
    • Apply a spring-like attraction toward the current target hand, add a gentle swirl, and clamp speeds.
    • When a wisp is very close to a moving hand, blend in some of the hand’s velocity to simulate “wind.”
    • Cycle the flock’s target hand every few seconds; fall back to the window position if no hands are tracked.

API used

FigminReady, getPlayers, onPlayerConnected, onPlayerDisconnected, getPlayerBodypart (BodypartType), Component: bodypart, setUpdateFunction, createObject (ObjectType.SKETCH), getWindowSpawnPosition, getWindow

Code


Object Ownership (Scene Persistent)


This example shows the difference between script-owned objects and scene-owned objects. Click buttons to create temporary (script-owned) or persistent (scene-owned) 3D text objects and see which ones survive when the script ends.

Difficulty: Simple

How it works

  1. Wait for FigminReady before creating objects.
  2. Wire two buttons: “Create Temporary” and “Create Persistent”. Compute spawn positions beside the app window with getWindowSpawnPosition and align rotation from getWindow.
  3. Create temporary objects with createObject (default ownership = script-owned).
  4. Create scene-owned objects by passing scenePersistent: true in createObject params, so they remain after the script stops.

API used

FigminReady, createObject, createObject(TEXT3D), ObjectType, getWindowSpawnPosition, getWindow, scenePersistent

Code


Object Visibility


This example demonstrates how to control a FigminObject’s visibility using its active property. Four 3D text objects are created, and their visibility is toggled through HTML checkboxes.

Difficulty: Simple

How it works

  1. Wait for the FigminReady event before creating objects.
  2. Spawn four TEXT3D objects next to the app window using getWindowSpawnPosition and align their rotation with getWindow.
  3. Add event listeners to each checkbox in the HTML interface. When a checkbox is toggled, update the object’s active property to show or hide it.

API used

FigminReady, createObject, createObject(TEXT3D), ObjectType, getWindowSpawnPosition, getWindow, active

Code


Save & Load UI state


This example shows how to persist UI state using saveState/loadState. Form controls are tagged with figmin-persist-state so their values are saved with the spatial app and restored automatically on the next run.

Difficulty: Simple

How it works

  1. Wait for the FigminReady event. If not in spatial app mode, gate with isSpatialApp / requireSpatialApp.
  2. Tag inputs you want to persist with a unique figmin-persist-state key (e.g., text, number, range, checkbox, radio, select, textarea).
  3. On “Save”, call saveState (you can also include optional custom payload).
  4. On “Load” or automatically on start, call loadState to restore all tagged fields and receive any custom data via callback.

API used

FigminReady, isSpatialApp, requireSpatialApp, saveState, loadState

Code


Dynamic Components


This example demonstrates how to dynamically attach and remove components from a Figmin object. You can add physics, lighting, and a physics material to a 3D text object and modify them in real time.

Difficulty: Medium

How it works

  1. Create a TEXT3D object near the window using getWindowSpawnPosition.
  2. Start the update loop with setUpdateFunction to keep the UI in sync with the object’s components.
  3. Use UI controls to call addComponent / removeComponent for physics, physicsMaterial, and light.
  4. Adjust component properties live: set mass/drag, apply forces and torque, choose light type and color, enable shadows, and tweak spotlight, projection pattern, and effects.

API used

FigminReady, setUpdateFunction, createObject / createObject(TEXT3D), getWindowSpawnPosition, getWindow, addComponent, removeComponent, ComponentType, transform, physics (mass, drag, angularDrag, velocity, angularVelocity, gravityStrength, kinematic, sleeping, applyForce, applyTorque), physicsMaterial (bounciness, staticFriction, dynamicFriction), light (type, range, spotlightAngle, rotation, shadowType, shadowNearPlane, projectionPattern, effect, color), lights.LightType, lights.ShadowType, lights.LightEffect, lights.LightProjection

Code


Sketch Component


This example demonstrates programmatic sketch generation. You’ll learn how to set brush strokes on a Sketch component to display a variety of AI-generated shapes, and how to clone those strokes into a new object by passing them as parameters to createObject. It also shows how to attach a Sketch component to a TEXT3D object to generate a pill-shaped background behind the text.

All of the sketch samples in this example were generated by AI, and we encourage you to do the same. While generating procedural geometry can be complex for a human, it’s a straightforward task for an AI assistant

Difficulty: Medium

How it works

  1. Create a single SKETCH object and store it in a variable for reuse, we reset it if it’s destroyed using onDestroy so a new object can be created.
  2. Each “Load Sketch” button builds a list of control points with sketch.point and emits one or more strokes with sketch.stroke (choosing brushes from the Brush catalog). The result is applied via object.sketch.setBrushStrokes.
  3. “Clone Sketch” reads the current strokes via object.sketch.getBrushStrokes and creates a new SKETCH object initialized with those strokes.
  4. “Text with Background” creates a TEXT3D object; when the transform bounds change (onBoundsChanged), it adds a Sketch component to that text and generates rounded-rectangle strokes as a backdrop. We wait for the bounds changed event because the user may later on manually update the text and this will automatically re-adjust the backdrop.

API used

FigminReady, getWindow, getWindowSpawnPosition, createObject (ObjectType.SKETCH, ObjectType.TEXT3D), onDestroy, onBoundsChanged, ObjectState, transform, sketch.setBrushStrokes / getBrushStrokes, sketch.point, sketch.stroke, sketch.boxStroke, sketch.roundedRectangleStroke, sketch.coneStroke, sketch.rotateStroke, sketch.translateStroke Brushes, showNavigationArrow

Code