Object types
These docs are made to be read by both humans and AI. They are the same docs given to your AI when it runs!
Core Objects
Ball
A ball in the world.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'ball' | |
| name | string | |
| material | BallMaterialSettings | null | Visual Material texture settings. |
| opacity | number | 0-1. |
| color | ||
| isAlwaysOnTop | boolean | Whether to render in front even if visually blocked. |
| radius | number | |
| location | ||
| movement | ||
| isWalkthrough | boolean | Whether this object can pass through other objects. |
| isAnchored | boolean | Whether this object is totally unmovable. |
| density | number |
Brick
A brick in the world.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'brick' | |
| name | string | |
| material | BrickMaterialSettings | null | Visual Material texture settings. |
| opacity | number | 0-1. |
| color | ||
| isAlwaysOnTop | boolean | Whether to render in front even if visually blocked. |
| size | ||
| location | ||
| movement | ||
| isWalkthrough | boolean | Whether this object can pass through other objects. |
| isAnchored | boolean | Whether this object is totally unmovable. |
| density | number |
Cylinder
A cylinder in the world. Its symmetry axis is local Z.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'cylinder' | |
| name | string | |
| material | CylinderMaterialSettings | null | Visual Material texture settings. |
| opacity | number | 0-1. |
| color | ||
| isAlwaysOnTop | boolean | Whether to render in front even if visually blocked. |
| radius | number | |
| length | number | |
| location | ||
| movement | ||
| isWalkthrough | boolean | Whether this object can pass through other objects. |
| isAnchored | boolean | Whether this object is totally unmovable. |
| density | number |
RigidGroup
A RigidGroup is a bunch of objects that move together. All Ball, Brick, and Cylinder child descendants are glued together and will move as one rigid body.
If you want to add animations, you must set followSkeletonId, use a SkAnimator to animate it, and add SkAttachment objects to glue objects to the SkJoints. There are some AI tools to automate this.
Group
Use this as a Folder. There is no special behavior, it is simply for organization.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'group' | |
| name | string |
Mesh
A mesh in the world.
To animate this mesh visually, you must set followSkeletonId and use a SkAnimator to animate it.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'mesh' | |
| name | string | |
| scale | ||
| meshDataId | ||
| followSkeletonId | ObjectId | null | The objectId of the Skeleton that this mesh will visually follow. |
| physicalObjectId | ObjectId | null | The objectId of the Ball, Brick, Cylinder, or RigidGroup that the mesh will use as a collider and visually follow. |
| material | MeshMaterialSettings | null | Visual Material texture settings. |
| opacity | number | 0-1. |
| color | ||
| isAlwaysOnTop | boolean | Whether to render in front even if visually blocked. |
Animation Objects
SkAnimator
This is the simplest way to animate characters and complex objects.
It animates a Skeleton. You can have many animators on the same skeleton. Animations will be blended in order of decreasing priority until each item's weight reaches a total of 100. See also: AnimationService.
Start and stop an animation with ClockService.play(clockId, animationTimeSecs) and ClockService.pause(clockId) on this animator's clock, and fade it in and out with AnimationService.smoothlyChangeWeight(animatorId, targetWeight, durationMs).
| Field | Type | |
|---|---|---|
| id | ||
| type | 'skAnimator' | |
| name | string | |
| skeletonId | ObjectId | null | The Skeleton to animate. |
| skAnimationId | ObjectId | null | Using this SkAnimation. |
| clockId | ObjectId | null | The Clock that lets you pause/play it. |
| priority | number | 0-10. |
| weight | number | 0-100. |
| weightTransition | WeightTransition | null |
Skeleton
The root of a skeleton.
It should contain a SkJoint child for each joint in the skeleton. Hierarchies are allowed.
You can (1) animate it and (2) glue objects to it. SkAnimation lets you define animations, and SkAttachment lets you glue objects. Play the animation using a SkAnimator.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'skeleton' | |
| name | string |
SkAnimation
This is how you define an animation.
It should contain a keyframe SkKeyframe child for each timestep in your animation.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'skAnimation' | |
| name | string | |
| duration | number | |
| interpolationStyle | The interpolation style of the animation. Use Step for a stop-motion effect. |
SkAttachment
Use this to glue an object in a RigidGroup to an SkJoint.
SkJoint
A child of Skeleton or SkJoint.
Note: the bindPose is the reference location that SkAnimation movements are relative to.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'skJoint' | |
| name | string | |
| bindPose | Relative to the parent. |
SkKeyframe
A child of SkAnimation.
For each desired joint in this keyframe, it should contain a SkKeyframePose child.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'skKeyframe' | |
| name | string | |
| time | number | Time in seconds in the animation. |
SkKeyframePose
A child of SkKeyframe.
The pose of an individual joint.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'skKeyframePose' | |
| name | string | |
| jointName | string | |
| relativePose |
PropertyAnimator
Use this to smoothly animate one property on any object.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'propertyAnimator' | |
| name | string | |
| targetObjectId | ObjectId | null | |
| propertyPath | string[] | Path to the continuous field to animate, for example ["color", "r"], ["opacity"], or ["location", "position", "x"]. |
| animation | ||
| clockId | ObjectId | null | The Clock that lets you pause/play it. |
| priority | number | 0-10. |
| weight | number | 0-100. |
| weightTransition | WeightTransition | null |
Other Objects
Clock
A clock is just an internal helper object that tells us how far along we are in a SkAnimator, PropertyAnimator, or SoundPlayer. Clock state can be changed by server or client scripts. Client-side changes stay local and may intentionally desync.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'clock' | |
| name | string | |
| clockState | Whether the clock is paused or playing. | |
| shouldLoop | boolean | Whether it should loop when done. |
| speed | number | A multiplier onto the normal speed. |
Material
An image or "texture" that is shown on an object. Albedo is the main texture. The other fields are optional PBR properties.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'material' | |
| name | string | |
| albedoTextureDataId | DataId | null | This is the main texture to place on the object. Four values (RGBA) per pixel. |
| metallicTextureDataId | DataId | null | Optional metallic information. One value per pixel. |
| roughnessTextureDataId | DataId | null | Optional roughness information. One value per pixel. |
| normalTextureDataId | DataId | null | Optional normal information. Three values (XYZ) per pixel. |
| alphaMode | Says how to handle the underlying object's transparency. Only relevant when albedoTextureDataId has transparency in it. |
Player
You can never create a Player object yourself. It is automatically created and deleted when a player joins and leaves. It is important for you to set the head and controls, or the player won't be able to see or move.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'player' | |
| name | string | |
| username | string | |
| userid | string | |
| headObjectId | ObjectId | null | The objectId of the Ball, Brick, Cylinder, or RigidGroup the player's camera will follow. |
| characterObjectId | ObjectId | null | The objectId of the Ball, Brick, Cylinder, or RigidGroup this player controls. |
| physicsControls | Physics constants used when the player moves. |
Script
Every Script is either a Server or Client script.
- Client scripts run on every client.
- Server scripts run on the server.
- Some APIs are only exposed to one or the other; read the docs.
Import/Export:
- It is valid to write
import { functionName } from './scriptName'. - Scripts and their path names are set once, when the script is created.
Server/Client communication:
- You should communicate between the server and client as follows:
- Write
'use server'at the top of a Server script to make all exports accessible to Client scripts. - Write
'use client'at the top of a Client script to make all exports accessible to Server scripts. - The first argument to client functions must be the player's user id.
- Exports in these files must be async functions.
- You should validate server function inputs and client function returns, as these are untrusted.
- Make sure you don't over-expose functions: all exports from a 'use server' or 'use client' script must be validly callable by the other side.
UI:
- We expose React-like syntax to draw UI on the screen.
- Use
<div>for layout and text. Divs do not block game pointer input and do not run hover effects unless you add pointer-events-auto. - Use
<button>with onClick for clickable UI and hover effects. Nested buttons are allowed, and the innermost button under the pointer handles the click. - You may only use
<div>,<button>, text, arrays, null, className, onClick, and onHover primitive props. - You can use common Tailwind class names. Do not use style props or unsupported HTML tags.
useState()works like usual.createState()works for state that comes from outside react, eg for 'use client' functions. This is similar to useSyncExternalStore.- Write
createState(initialValue). The.get()function automatically subscribes the relevant React components to re-render when.set()is called.
Libraries:
- You can use
setTimeout()andsetInterval(). Scripts expose all web APIs except fetch.
Managing Objects:
- Only the server can create and modify objects.
- All objects in the world are replicated to all users. You cannot create an object on just one client.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'script' | |
| name | string | |
| objectLocation |
SoundPlayer
WorldLighting
Controls the sun location and sky settings.
| Field | Type | |
|---|---|---|
| id | ||
| type | 'worldLighting' | |
| name | string | |
| sunOrientation | ||
| sunColor | ||
| sunIntensity | number | |
| ambientTopColor | ||
| ambientBottomColor | ||
| ambientIntensity | number | |
| skyColor | The background sky color behind the world. | |
| skyboxTextureDataId | DataId | null | An equirectangular skybox TextureData id. Transparent pixels reveal skyColor. |
| skyboxTextureOpacity | number | 0 means the skybox texture is hidden. 1 means the skybox texture is fully visible. |
Scripting
stopScript
Use await stopScript() to stop all further execution of a script.
()
Promise
tick
Use await tick() to await the next physics step. Always use this in places like infinite while loops, otherwise the script will stall and be killed.
()
Promise
FullLiveObjectJS
Scripts usually deal with this object type.
It contains all the fields of either a Ball, Brick, Clock, Cylinder, Group, SkJoint, SkAnimation, SkAnimator, SkAttachment, SkKeyframe, SkKeyframePose, Material, Mesh, Player, RigidGroup, Script, Skeleton, or SoundPlayer.
And it contains the following additional fields:
| Field | Type | |
|---|---|---|
| getChild | ||
| getChildren | ||
| parent | FullLiveObjectJS | null |
ObjectInfo
This is a helper type. It contains all the fields of either a Ball, Brick, Clock, Cylinder, Group, SkJoint, SkAnimation, SkAnimator, SkAttachment, SkKeyframe, SkKeyframePose, Material, Mesh, Player, PropertyAnimator, RigidGroup, Script, Skeleton, SoundPlayer, or WorldLighting, excluding their id and name fields.
PlayerService
This service exposes methods for managing players in the game.
To react to players joining or leaving, use the object listeners with the "player" type filter:
- join:
game.objectService.addObjectCreatedListener((player) => { ... }, "player") - leave:
game.objectService.addObjectDeletedListener((playerObjectId) => { ... }, "player"). The player object is already gone when the deleted listener fires, so if you need its userid, record it in the created listener first.
Example usage: game.playerService.getAllPlayers().
| Field | Type | |
|---|---|---|
| getAllPlayers | Only callable by a Server Script. |
ObjectService
This service exposes methods for reading and modifying objects.
If you only want to operate on one object and not its children, simply write object.propery = value, and don't use the modifiers here.
| Field | Type | |
|---|---|---|
| getObjectById | Returns the object with this ObjectId. | |
| getObjectByName | Returns any object with this name. | |
| getObjectsByName | Returns all the objects with this name. | |
| getObjectsByType | Returns all the objects with this type. | |
| createObject | Creates an object. Only callable by a Server Script. | |
| deleteObject | ||
| cloneObject | Clones the object and all its children, returning the clone. Remember to move the clone afterwards so it doesn't overlap. Only callable by a Server Script. | |
| createSkAttachmentsInRigidGroup | Only callable by a Server Script. | |
| scaleObject | This scales the object and all children by the multiplier with respect to the center point. Note that repeatedly calling this will grow/shrink the object multiple times. Only callable by a Server Script. | |
| rotateObject | Rotates the object by this offset in degrees around each axis, bringing children with it. Only callable by a Server Script. | |
| moveObjectBy | Moves the object by this offset, bringing children with it. Only callable by a Server Script. | |
| moveObjectTo | Moves the object to this exact position, bringing children with it. Only callable by a Server Script. | |
| setObjectWalkthrough | Gives the object and all children the given isWalkthrough value. Only callable by a Server Script. | |
| setObjectAnchored | Gives the object and all children the given isAnchored value. Only callable by a Server Script. | |
| setObjectDensity | Gives the object and all children the given density value. Only callable by a Server Script. | |
| castRay | Casts a ray through the physics world and returns the closest hit, or null.
The direction does not need to be normalized.
For aiming from the player's point of view, pair this with | |
| isGrounded | Whether the object is standing on walkable ground right now — the same support test the engine uses to decide if a player can jump: a live walkable contact, or walkable ground a hair's width below the object. Steep faces don't count as ground. Useful for gating airborne effects like a falling animation. | |
| addObjectCreatedListener | Fires when an object is created. On a Client Script this means the object was replicated into the local world.
Pass objectType to only hear about that type — it also narrows the callback's object, e.g. a "player" filter receives | |
| removeObjectCreatedListener | ||
| addObjectDeletedListener | Fires when an object is deleted. On a Client Script this means the object was removed from the local world. Pass objectType to only hear about that type, e.g. "player" to react to players leaving; if you need more than the id (like a player's userid), record it in an object-created listener first. Deleting an object fires this for it and every descendant. | |
| removeObjectDeletedListener |
ObjectCreatedCallback
ObjectDeletedCallback
RaycastHit
| Field | Type | |
|---|---|---|
| object | The Ball, Brick, or Cylinder the ray hit. For a RigidGroup, this is the subitem that was hit. | |
| distance | number | World-space distance from the ray origin to the hit. |
| position | World-space point where the ray hit. |
RaycastOptions
| Field | Type | |
|---|---|---|
| maxDistance | number | Stop looking past this distance. Defaults to unlimited. |
| includeWalkthrough | boolean | Whether isWalkthrough objects can be hit. Defaults to false. |
| excludeObjectIds | ObjectId[] | Objects the ray should pass through. Excluding a RigidGroup excludes all of its subitems, so pass a character's RigidGroup id here to not hit yourself. |
AnimationService
This service exposes methods for smoothly transitioning animation values.
| Field | Type | |
|---|---|---|
| smoothlyChangeWeight | animatorId: ObjectId, targetWeight: number, durationMs: number, interpolationStyle?: InterpolationStyle → void | Use this to smoothly change the weight of a SkAnimator or PropertyAnimator. |
ClockService
This service exposes methods for controlling Clock objects on SkAnimator, PropertyAnimator, and SoundPlayer.
CollisionService
- collisionService fires even when isWalkthrough=true.
- For RigidGroups, collisionService fires using the subitem(s) involved in the collision.
| Field | Type | |
|---|---|---|
| addCollisionListener | Only fires once, when the collision starts. It does not keep firing while the objects stay in contact. | |
| removeCollisionListener | ||
| addCollisionStopListener | ||
| removeCollisionStopListener |
CollisionCallback
GuiService
The guiKey can be anything; it is a string you pick to identify the GUI root.
| Field | Type | |
|---|---|---|
| show | Example: | |
| hide | guiKey: string → void | Example: |
useState
Only callable by a Client Script.
initialState: T | (() => T)
[T, (nextState: T | ((prevState: T) => T)) => void]
createState
Only callable by a Client Script.
initialState: T
{ get: () => T; set: (nextState: T | ((prevState: T) => T)) => void; }
GuiAnchor
| "topLeft" | "top" | "topRight" | "left" | "center" | "right" | "bottomLeft" | "bottom" | "bottomRight"
GuiRootRenderable
GuiRenderable | (() => GuiRenderable)
GuiRenderable
This is the equivalent to a React Node.
The typical usage is <MyComponent />.
You can also use strings, numbers, booleans, null, and undefined.
Reference
ObjectLocation
"Server" | "Client"
ClockState
| { Paused: { animationTimeSecs: number } } | { Playing: { localStartMs: number, timeLocation: ObjectLocation } }
InterpolationStyle
"Step" | "Linear" | "EaseInOut" | "EaseIn" | "EaseOut"
WeightTransition
| Field | Type | |
|---|---|---|
| startedAtMs | number | The wall-clock ms at which the weight transition started in timeLocation. |
| timeLocation | Whether startedAtMs is client time or estimated server time. | |
| initValue | number | |
| finalValue | number | |
| durationMs | number | |
| easing |
BallPrimitiveSettings
| Field | Type | |
|---|---|---|
| radius | number |
CylinderPrimitiveSettings
| Field | Type | |
|---|---|---|
| radius | number | |
| length | number |
BrickPrimitiveSettings
| Field | Type | |
|---|---|---|
| size |
BallMaterialSettings
CylinderMaterialSettings
BrickMaterialSettings
MeshMaterialSettings
AlphaMode
This only applies to Material objects whose albedoTextureDataId have transparency. Default is Opaque.
- Opaque means to render the underlying object as solid, meaning show the base color in the transparent areas.
- Mask makes the underlying object either opaque or invisible in areas, based on the transparency cutoff.
"Opaque" | { Mask: { cutoff: number } }
PlayerPhysicsControls
| Field | Type | |
|---|---|---|
| jumpHeight | number | Target number of blocks to which the player will jump. Internally we use this to figure out what impulse to apply. |
| stepHeight | number | The max obstacle height that the player will be teleported vertically onto, instead of getting stuck on. |
| speed | number | Movement speed. |
| acceleration | number | Movement acceleration. |
PropertyAnimationKeyframe
| Field | Type | |
|---|---|---|
| time | number | |
| value | number |
PropertyAnimationInfo
| Field | Type | |
|---|---|---|
| duration | number | |
| interpolationStyle | ||
| keyframes |
Vec3
| Field | Type | |
|---|---|---|
| x | number | |
| y | number | |
| z | number |
ObjectId
Every object in the world gets a unique id that you can use to reference it. It's just a number. These object ids may change between compile time and runtime. We automatically convert most object ids, but you should not hard-code object ids into scripts as we can't parse those until runtime.
number
DataId
"Data" generally means large assets that are uploaded and given an id, like mesh data and texture data. Objects reference them using their data id.
number
UserId
The unique id of the user. This will never change, so you should use it when tracking players. It is preferred over the player's username or the Player object's id.
string
Location3D
This is called "location", but really means both position and rotation. In other words, the full information needed to place the object in 3D at snapshot in time. Can be global or local depending on context.
Movement3D
Speed information of an object. The derivative of Location3D.
PhysicsToggles3D
A helper type.
| Field | Type | |
|---|---|---|
| isWalkthrough | boolean | Whether this object can pass through other objects. |
| isAnchored | boolean | Whether this object is totally unmovable. |
| density | number |
Color3
RGB color.
| Field | Type | |
|---|---|---|
| r | number | Red on a scale of 0-1. |
| g | number | Green on a scale of 0-1. |
| b | number | Blue on a scale of 0-1. |
VisualSettings
A helper type.
| Field | Type | |
|---|---|---|
| opacity | number | 0-1. |
| color | ||
| isAlwaysOnTop | boolean | Whether to render in front even if visually blocked. |
PhysicsInfo3D
A helper type.
| Field | Type | |
|---|---|---|
| location | ||
| movement |
Orientation3D
A helper type.
| Field | Type | |
|---|---|---|
| theta | number | Degrees around the vertical direction. Starts at Z and goes clockwise around Y. This is what changes when you look left or right. |
| phi | number | Degrees with respect to the horizon (XZ plane). Upwards is positive. This is what changes when you look up or down. |
CameraLocation
A helper type.
| Field | Type | |
|---|---|---|
| position | ||
| orientation |