Built-in component reference
Component IDs are stable across scenes and blueprints — the engine persists them by ID, so existing scenes keep working as fields evolve.
This page is the inspector and Flow catalog: fields, actions, conditions, and events. Native components also have an OpalScript class — Health, RigidBody2D, Motion, and the rest — listed in the Scripting API.
Each component below lists its fields, actions (callable from Flow), conditions (checkable from Flow), events (Flow graph triggers), lifecycle hooks, and any cross-component dependencies. Fields marked hidden are internal and don't show in the inspector or Flow; fields marked output are read-only at runtime (engine-set state).
Legacy components: stats, combatAction, turnQueue, and networkHit are deprecated for new attachments. Existing scenes, prefabs, scripts, Flow nodes, and exports keep their IDs and behavior. Their Inspector cards explain the replacement path. New RPG stats, damage formulas, turn eligibility and victory rules belong in project Behavior Components. Use Network Input for new authorized tap/key commands. Deprecation does not automatically convert saved content or remove runtime support.
Browsing components in the editor
The Object Flow node picker lists every registered component — built-ins plus your script-authored Behavior Components — grouped and sorted so attached ones float to the top.
Project-specific possession, victory, death and cover-timing recipes are documented in Project gameplay policies.
Core
These components are on almost every object: rendering an image, moving it, and catching taps and drags.
Motion (motion)
Category: Core Description: Moves, tweens, springs, bounces, and smooths a Thing's transform.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
springStiffness | number | 0.18 | 0–1; spring follow stiffness |
springDamping | number | 0.68 | 0–1; spring follow damping |
dragStiffness | number | 0.52 | 0–1; stiffness while being dragged |
dragDamping | number | 0.58 | 0–1; damping while being dragged |
scaleSmoothing | number | 10 | 0 disables smoothing |
rotationSmoothing | number | 8 | 0 disables smoothing |
Actions
| Action | Params | Behavior |
|---|---|---|
Move To | x, y, durationMs, easing | Tween position to (x, y) over durationMs. |
Snap To | x, y | Instantly set position; cancels any move tween. |
Scale To | value, durationMs, easing | Tween scale to value. |
Rotate To | value, durationMs, easing | Tween rotation to value. |
Cancel Tweens | — | Stop all tweens; snap targets to current. |
Reset Home | — | Return position/scale/rotation to home. |
Bounce | amount | Scale-bounce effect sized by amount. |
Shake | durationMs, intensity | Shake by oscillating scale/rotation with decay. |
Easing values: easeOutQuad (default), easeInQuad, easeInOutQuad, easeOutBack, easeOutBounce, linear.
Conditions
| Condition | True when |
|---|---|
isMoving | A move tween is active. |
isAnimating | Any tween or bounce is active. |
Events
| Event | Payload |
|---|---|
Move Complete | x, y |
Scale Complete | value |
Rotation Complete | value |
Shake Complete | durationMs, intensity |
Lifecycle
- onTick: Steps tweens, applies springs in fixed 1/60-second substeps (up to 60 per tick), runs shake/bounce, emits completion events. Authored stiffness/damping retain their 60 Hz meaning; frames above 60 Hz may wait one substep.
- onPlayStart / onPlayEnd / onDetach: Reset motion runtime state.
::: note When something is being dragged While thing.dragging is true, move tweens cancel and Motion swaps to dragStiffness/dragDamping. The Draggable component (and engine) sets that flag — you don't wire it. :::
Sprite Renderer (spriteRenderer)
Category: Core Description: Draws an image-backed sprite and controls render order, tint, source, flip, and opacity.
The Sprite field selects an image asset from the library. Most source metadata fields are kind: internal — they persist and serialize but are managed by the engine and the Studio actions below, so they're hidden from the inspector and Flow.
Fields (selected)
| Field | Type | Default | Notes |
|---|---|---|---|
renderOrder | int | 0 | Position inside the nearest Sorting Group. |
tint | color | #ffffff | Flat overlay color. |
tintAmount | number | 0 | Overlay strength (0 = off, 1 = solid). |
assetSrc | string | "" | hidden; resolved image source. |
assetLibraryId | assetRef | "" | Sprite image selected from the asset library. |
Actions
| Action | Params | Behavior |
|---|---|---|
Appear | style (fade/pop/scale), durationMs, delayMs | Show sprite with an entrance animation. |
Vanish | style (fade/shrink), durationMs, delayMs, hide, markDone | Fade/shrink out; optionally hide and/or mark done. |
Collect | durationMs | Shrink + fade out, hide, mark done. |
Set Sprite | assetId, preserveSize | Swap sprite image to a library asset. |
Set Flip | flipped (Flip X), flipY | Mirror the sprite horizontally and/or vertically. |
Set Alpha | value (0–1) | Set sprite opacity. |
Set Tint | color, amount (0–1) | Overlay a flat tint color on the sprite. |
Conditions
| Condition | True when |
|---|---|
Has Sprite | assetSrc or assetLibraryId is set. |
Sprite Is | current sprite matches a given asset. |
Is Animating | An appear/vanish tween is active. |
Events
| Event | Payload |
|---|---|
Appear Complete | style |
Vanish Complete | style, hidden |
Lifecycle
- onAttach: Reloads with asset resolution.
- onPlayStart: Initialises anim state, records home alpha/scale.
- onTick: Steps appear/vanish tweens.
Sprite Animator (spriteAnimator)
Category: Core Description: Controls named animation states, sprite sequences, and automatic locomotion animation. Requires Sprite Renderer.
Fields (selected)
| Field | Type | Default | Notes |
|---|---|---|---|
activeState | string | "idle" | hidden; current Animation State. |
stateSprites | object | {} | hidden; Animation State name → sprite source. |
stateSequences | object | {} | hidden; Animation State name → sprite frames. |
autoLocomotionStates | boolean | false | Automatically select locomotion states from a character controller. |
idleState/walkState/runState/jumpState/fallState/landingState | string | "idle"… | hidden; locomotion role → Animation State name. |
landingStateDurationMs | number | 150 | How long the Landing State is held after touching down. |
Actions
| Action | Params | Behavior |
|---|---|---|
Configure Locomotion States | idle/walk/jump/fall/landing/run sprites and sequences | Assign locomotion sprites and looping sequences. |
Play Animation | sequence, loop, restore | Play a sprite animation; a one-shot may restore the prior state frame. |
Set Idle/Walk/Run/Jump/Fall/Landing State | sprite, sequence, autoApply | Bind a locomotion state's sprite or animation. |
Set Locomotion State | role | Switch to an authored locomotion state. |
Set Automatic Locomotion States | enabled | Toggle controller-driven locomotion states. |
Set Animation State | state | Switch to a named Animation State. |
Conditions
Animation State Is, Locomotion State Is.
Events
| Event | Payload |
|---|---|
State Changed | oldValue, newValue |
Locomotion States Ready | count, role |
Animation Complete | name |
::: note Automatic locomotion states When enabled, Sprite Animator reads an attached character controller to select Idle, Walk, Run, Jump, Fall, and Landing states without extra Flow wiring. :::
Shape 2D (shape2d)
Category: Rendering Description: Editable geometry for floors, walls and ramps. Its visible outline, selection and automatic collision use the same shape, including after resizing or flipping. Create these objects with Arrange → Shapes and adjust them with Edit points on stage in the inspector.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
shape | enum | rectangle | Rectangle, Ramp, or convex Polygon |
fillColor | color | #718096 | Visible fill color |
collisionEnabled | boolean | true | Solid geometry; disable for decoration |
friction | number | 0.7 | Surface grip; zero is slippery |
restitution | number | 0 | Bounce, from zero to one |
Without Rigid Body 2D the shape is fixed, suitable for level geometry. Add Rigid Body 2D for dynamic geometry. An enabled Collider 2D overrides automatic shape collision; an enabled Soft Body 2D owns collision. The inspector explains these overrides. Shape 2D exposes Collision Start and Collision End events.
Polygon points are saved with the component. Polygons support up to 64 points and must be convex, with no crossing edges or duplicate points. Use multiple shapes for inward corners. Shape geometry exports directly; no image asset is required. Extremely thin outlines stay visible but have no automatic collision; the inspector identifies these outlines so you can widen them for stable physics.
Sorting Group (sortingGroup)
Category: Core Description: Keeps this object and its visual descendants together in paint order so a character or prop doesn't interleave with unrelated sprites.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
renderOrder | int | 0 | Positions the whole group relative to neighboring renderers and groups |
Sprite Renderer renderOrder is relative to the nearest Sorting Group ancestor.
Interactable (interactable)
Category: Core Description: Lets an object receive taps/clicks: its hit region, built-in tap action, and whether it blocks taps to objects behind it. This is the modern tap component — it's auto-added when you wire an "On Tap" graph.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Off = ignores taps |
hitArea | enum | "sprite" | sprite (opaque pixels), bounds (full rectangle), collider (collider shape) |
blocksBehind | boolean | true | Off lets taps pass through to objects behind |
tapAction | enum | "none" | none, bounce, sparkle, sound, spin, collect, toggle |
tapOnly | boolean | false | On draggable objects, register a quick tap instead of a drag |
longPress | boolean | true | Emit Long Pressed |
doubleTap | boolean | true | Emit Double Tapped |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Tap Action | action (enum) | Set the built-in tap reaction. |
Clear Tap Action | — | Set tapAction to none. |
Set Tappable | enabled | Enable/disable tap reception. |
Conditions
| Condition | True when |
|---|---|
Is Tappable | enabled is not false. |
hasAction | tapAction is not none. |
Action Is | tapAction matches a given value. |
Events
| Event | Payload |
|---|---|
Tapped | pointer |
Double Tapped | pointer |
Long Pressed | pointer |
Draggable (draggable)
Category: Core Description: Lets an object be dragged, axis-constrained, and dropped onto Drop Zones.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
axis | enum | "free" | free, x, y |
bounds | enum | "none" | none, stage |
moveThreshold | number | 6 | Pixels the pointer must travel before a drag starts |
pickUpScale | number | 1.12 | Scale while held |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Drag Axis | axis (free/x/y) | Constrain dragging axis. |
Set Drag Bounds | bounds (none/stage) | Set stage bounds. |
Set Pick-up Scale | value | Set scale while held. |
Conditions
| Condition | True when |
|---|---|
isDragging | thing.dragging is truthy. |
constrainedToStage | bounds is stage. |
Axis Is | axis matches. |
Events
| Event | Payload |
|---|---|
Drag Started | pointer |
Drag Moved | pointer, deltaX, deltaY |
Drag Ended | pointer |
Dropped | otherId, targetId, dropX, dropY |
::: note Drop Zones resolve targets The Dropped event carries otherId/targetId resolved from nearby Drop Zones. The engine sets thing.dragging, which Motion reads to switch to drag tuning — no wiring required. :::
Drop Zone (dropZone)
Category: Core Description: Marks an object as a target area for drops and proximity checks.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
radius | number | 110 | Proximity threshold in pixels |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Radius | value | Set the zone radius. |
Conditions
| Condition | True when |
|---|---|
hasRadius | radius > 0 |
Radius At Least | radius ≥ value |
Events
| Event | Payload |
|---|---|
Entered | otherId, pointer |
Exited | otherId, pointer |
Dropped On | otherId, droppedId, dropX, dropY |
Rendering
These components expose the modern Render2D lighting path without putting GPU, Canvas, texture, or render-target handles into a project. Add a Light 2D to any object and a Sprite Material 2D to the sprites that should receive it.
Scene Render (sceneRender)
Category: Rendering Description: Opts the scene camera into HDR lighting. Bright sprite, mesh and particle values remain above white until bloom is combined and the scene is tone mapped. Ordinary Canvas hooks are composited in order. The game HUD and speech render afterward.
Fields
| Field | Type | Default | Purpose |
|---|---|---|---|
enabled | boolean | true | Enable the scene rendering settings. |
hdr | boolean | true | Preserve bright scene values on supported WebGL2 devices, including when bloom intensity is zero. |
exposure | number | 0 | Final scene exposure in stops, −8–8, while HDR is active. |
toneMapping | enum | "aces" | Map combined HDR scene light and bloom to the display: none, reinhard, or aces. |
The active camera takes priority. Games without this component keep their previous rendering. Canvas2D, unsupported devices, and unsafe Canvas operations (including destination-dependent blends, readbacks, self-copy, clips and unknown raw draw callbacks) use standard rendering; fallback counters explain why. Disabling HDR or taking this fallback skips the camera's exposure and tone mapping. Leave per-sprite tone mapping at none when the camera owns the final tone map.
Play controls and exported player controls offer Auto, High, Balanced and Low quality. These change backing resolution, light-field density, bloom processing resolution and shadow-mask size without changing any saved component settings. Auto responds to sustained timing pressure with hysteresis.
Scene Bloom (sceneBloom)
Category: Rendering
Description: Adds soft glow around bright scene pixels during Play. Attach to the scene camera. Sprites, deforming meshes, and particles contribute; native HUD elements and speech stay sharp. The effect also ships in exported players. With Scene Render it extracts glow from the retained HDR scene. Otherwise it uses a bounded copy of the displayed scene. Both paths include mixed Canvas and WebGL content.
Fields
| Field | Type | Default | Purpose |
|---|---|---|---|
intensity | number | 0.65 | Glow strength, 0–3. Zero skips capture and bloom passes. |
threshold | number | 0.78 | Brightness cutoff, 0–16. Values above 1 isolate HDR lighting and emission; lower values make more of the scene glow. |
radius | number | 1.5 | Halo softness at the processing resolution, 0–8. |
downsample | number | 4 | Resolution divisor, 1–8. Larger values spread glow and reduce cost. Standard scene captures cap the longer dimension at 512 pixels; HDR processing accounts for display scale. |
Disable the component to retain its settings without drawing bloom. If several objects have enabled bloom components, the active camera takes priority and otherwise the first enabled component with positive intensity is used.
Light 2D (light2d)
Category: Rendering Description: Emits a colored, range-limited local light to Sprite Material 2D receivers on the same lighting layer.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Whether this component emits light. |
layer | string | "default" | Matches any comma-separated receiver layer case-insensitively; * matches all. |
color | color | #ffffff | Color encoded in the light contribution texture. |
intensity | number | 1 | Diffuse energy, 0–8. Values above 1 are preserved in HDR light targets. |
range | number | 320 | World-space radius in pixels. |
height | number | 180 | Virtual distance above the 2D surface; larger values make lighting more frontal. |
falloff | number | 2 | Radial attenuation exponent, 0.25–8. |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Light Enabled | enabled | Start or stop emitting without losing tuning. |
Set Light Intensity | value | Set diffuse energy from 0–8. |
Set Light Color | color | Change color and rebuild the shared procedural light texture. |
Conditions
Light Is Enabled is true when the authored switch is on and intensity is greater than zero.
Lifecycle
- onAttach / onFieldsChanged: Lazily builds or refreshes a small procedural attenuation texture in runtime state.
- onEditorDraw: Shows the light center and world-space range as an editor-only gizmo.
Light Occluder 2D (lightOccluder2d)
Category: Rendering Description: Blocks local lights using this object's rectangular bounds. Resize, rotate, parent or move the object to shape its hard shadow. Each light keeps an independent mask, so an unblocked lamp still illuminates the shadow.
Fields
| Field | Type | Default | Purpose |
|---|---|---|---|
enabled | boolean | true | Whether this rectangle blocks light. |
layer | string | "default" | Blocks lights sharing any comma-separated layer; * matches all lights. |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Occluder Enabled | enabled | Enable or disable blocking. |
Conditions
Blocks Light reports the authored switch. Hidden or disabled objects do not block light. A lamp ignores its own rectangle; a lamp inside another blocker is fully blocked. Masks are shared across receivers and released when unused, with bounded light and occluder counts.
Sprite Material 2D (spriteMaterial2d)
Category: Rendering Description: Adds portable normal-mapped lighting, emission and color grading to an image-backed Sprite Renderer, including deforming soft-body meshes. Requires Sprite Renderer.
Flat receivers automatically use the scalable shared-field path. WebGL2 shades them directly in the normal sprite draw. Directional materials shade directly on WebGL2 with a bounded Canvas2D reference path. This runtime optimization does not change serialized component data.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Receive matching lights; off restores the ordinary sprite fast path. |
normalMap | assetRef | "" | Optional tangent-space image. Empty uses a generated flat normal. |
layer | string | "default" | Receives Light 2D components sharing any comma-separated, case-insensitive layer; * matches all. |
ambient | number | 0.22 | Baseline light contribution, 0–4. |
emissionColor | color | #ffffff | Glow color, masked by the artwork's alpha. |
emissionIntensity | number | 0 | Emitted light, 0–16, including without lamps. Values above 1 contribute strong HDR bloom. |
normalStrength | number | 1 | Scales normal-map detail, 0–4. |
maxLights | int | 4 | Highest-impact intersecting lights sampled by the directional per-sprite path, 1–4. Shared fields accumulate all matching lights. |
lightingScope | enum | "auto" | auto shares flat surfaces and keeps normal maps directional; layer forces the shared field; sprite forces per-sprite lighting. |
smoothing | boolean | true | Use linear sampling for the final lit target. |
exposure | number | 0 | Color-grading exposure in stops, −8–8. |
contrast | number | 1 | Post-lighting contrast, 0–4. |
saturation | number | 1 | Post-lighting saturation, 0–4. |
vignette | number | 0 | Edge darkening, 0–1. |
toneMapping | enum | "none" | none, reinhard, or aces. |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Normal Map | assetId | Swap or clear the stable normal-map asset reference. |
Set Receiving Lighting | enabled | Enter or leave the authored material path. |
Conditions
Receives Lighting reports the authored receive switch. Has Normal Map reports whether an asset or inline source is configured; a flat normal remains available when it is false.
Lifecycle
- onAttach / onRuntimeContextChanged: Resolves the stable normal-map asset id into runtime-only decoded image state.
- onFieldsChanged: Invalidates and reloads the decoded normal when the asset changes.
On WebGL2, flat surfaces automatically share one stage-space HDR field per receiver-layer mask. Every matching light is accumulated once, and each sprite samples its transformed world region without a per-sprite light ceiling. Normal-mapped or explicitly sprite-scoped materials select up to maxLights by layer, range, and impact for directional lighting. If no matching light is active, no targets are submitted and the existing one-command sprite path is retained. Canvas2D keeps the bounded per-sprite path as its reference fallback.
Particle Emitter (particleEmitter)
Category: Rendering Description: Plays a looping particle effect on this object. Use Flow Spawn VFX for one-shot bursts. The Particle Canvas (FX workspace) bakes .pfx assets this component can play.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
effect | assetRef | "" | Baked .pfx or a builtin name (sparkle, smoke, fire, …). assetKind: particle. |
autoPlay | boolean | true | Start the effect when play begins. |
loop | boolean | true | Keep emitting. Off plays one burst then stops. |
offsetX | number | 0 | Horizontal offset from this object. |
offsetY | number | 0 | Vertical offset from this object. |
seed | int | 1 | Seeded RNG for this instance. |
playing | boolean | false | output — true while an effect instance is live. |
Actions
| Action | Params | Behavior |
|---|---|---|
Play | — | Start (or restart) the effect. |
Stop | — | Stop the effect. |
Restart | — | Stop and play again from this object's position. |
Conditions
Is Playing is true while an effect instance is live.
Events
| Event | Payload |
|---|---|
Started | effect |
Stopped | effect |
Lifecycle
- onPlayStart: Starts the effect when
autoPlayis on. - onRuntimeContextChanged: Retries start if
vfxwas missing at attach (session-scoped, not ambient). - onTick: Follows the host via
vfx.setOrigin. - onPlayEnd / onDetach: Stops the instance.
Control
Character controllers drive locomotion. The engine is shared (character-controller-core.js); three flavors expose it with different movement models. Set controlledBy to player, flow, ai, or network to choose who drives it.
Joint Motor Controller (jointMotorController)
Category: Control · Requires: Joint 2D
Drives the same object's revolute hinge using player input or game logic. Add it from Joint 2D → Add drive controls; Physics Cart includes it on Rear Wheel.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
controlledBy | enum | player | Player or Flow / Script |
speed | number | -5 | Forward angular speed in rad/s; flip sign to change direction |
force | number | 100000 | Motor strength; tune for body size and density |
idle | enum | coast | Release the motor or brake at zero input |
reverseInput | binding | ArrowLeft | Remappable reverse input |
forwardInput | binding | ArrowRight | Remappable forward input |
brakeInput | binding | Space | Hold to brake; overrides driving |
adKeys | boolean | true | Also accept A/D |
gamepad | boolean | true | Also accept analog left-stick X with the shared deadzone |
Actions and lifecycle
Set Drive (value) accepts -1 to 1 while Controlled By is Flow / Script; the value stays active until changed and resets on Play. OpalScript: GetComponent<JointMotorController>().SetDrive(0.5). Disabling or removing the controller restores the joint's previous motor settings. Disabling or breaking its Joint 2D stops control. This controller does not move transforms directly; the connected bodies remain part of the ordinary physics world.
Platformer Controller (platformerController)
Category: Control Description: Side-view locomotion with gravity, jumping, coyote time, jump buffering, and ground-aware foot probes.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
controlledBy | enum | "player" | player, flow, ai, network |
maxSpeed | number | 220 | px/s |
acceleration | number | 900 | px/s² |
friction | number | 1200 | px/s² |
airAcceleration | number | 700 | px/s² |
airFriction | number | 160 | px/s² |
gravity | number | 1800 | px/s² |
terminalVelocity | number | 1400 | px/s |
jumpSpeed | number | 620 | px/s |
maxJumps | int | 1 | 2 = double jump |
variableJumpHeight | boolean | true | Cut upward velocity when jump released early |
variableJumpMinPercent | number | 0.4 | Fraction of full jump retained |
coyoteTime | number | 0.08 | Seconds after leaving ground a jump still works |
jumpBufferTime | number | 0.08 | Seconds a queued jump waits before landing |
useStageFloor | boolean | true | Land on the bottom of the stage |
floorY | number | 0 | Custom floor Y when useStageFloor is off |
collideWithWorld | boolean | false | Use physics colliders |
clampToStage | boolean | false | Keep inside the stage |
arrivalRadius | number | 8 | px to count as "arrived" for Move Toward |
footProbe* | — | — | Foot probing: showFootProbes, footProbeSpread, footProbeInset, footProbeLeftX/RightX, footProbeDepth, footProbeLift, footProbeYOffset, footProbeMode (leading/…), footProbeSpeed |
rotateSprite | boolean | false | Flip sprite horizontally to face movement |
jumpKey | binding | "Space" | Click the field and press any key, mouse button, or gamepad button. |
leftKey/rightKey/upKey/downKey | binding | Arrow keys | Click the field and press any key, mouse button, or gamepad button. |
wasd | boolean | true | Also accept WASD |
moving | boolean | false | output |
facing | enum | "right" | output; 8-directional |
grounded / jumping / falling | boolean | false | output |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Move Input | x, y | Set persistent movement intent. |
Move Direction | x, y | Set movement direction intent. |
Move Toward | x, y, stopWithin | Move toward a point; emits Arrived on arrival. |
Clear Move Target | — | Clear the move-to target. |
Stop | haltVelocity | Stop; optionally halt velocity. |
Set Speed | value | Set maxSpeed. |
Set Controller Enabled | enabled | Enable/disable. |
Set Facing / Face Direction | direction / x, y | Set facing. |
Jump | strength | Queue a jump. |
Conditions
| Condition | True when |
|---|---|
Can Move | enabled is true. |
Is Moving / Is Idle | moving is true / false. |
Has Move Target | A move-to target exists. |
Facing Is | facing matches. |
Is Grounded / Is Airborne | grounded is true / false. |
Is Falling | falling is true. |
Can Jump | Enabled and has a ground jump or remaining jumps. |
Events
| Event | Payload |
|---|---|
Move Started / Move Stopped | x, y, vx, vy, speed |
Direction Changed / Facing Changed | direction, x, y |
Arrived | x, y |
Jumped | x, y, vx, vy, jumpsUsed |
Landed / Left Ground | x, y, vx, vy |
Top-Down Controller (topDownController)
Category: Control Description: Free-plane movement in all directions, with optional diagonal movement and turn-to-face.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
controlledBy | enum | "player" | player, flow, ai, network |
maxSpeed | number | 220 | px/s |
acceleration | number | 900 | px/s² |
friction | number | 1200 | px/s² |
allowDiagonal | boolean | true | Off = 4-way cardinal only |
turning | enum | "none" | none, instant, smooth |
rotateSprite | boolean | false | Orient the sprite toward the direction it is moving. Rotation also needs turning set; flipping does not. |
spriteFacing | enum | "rotate" | rotate, flipX. How it orients. Rotate suits top-down art; flip suits side-view art, which rotation would turn upside down. |
collideWithWorld / clampToStage | boolean | false | |
arrivalRadius | number | 8 | |
left/right/up/downKey, wasd | — | — | Same input fields as Platformer |
moving | boolean | false | output |
facing | enum | "right" | output |
Actions & Conditions
Same shared action/condition set as Platformer (Set Move Input, Move Direction, Move Toward, Clear Move Target, Stop, Set Speed, Set Controller Enabled, Set Facing, Face Direction; conditions Can Move, Is Moving, Is Idle, Has Move Target, Facing Is). No jump, ground, or air actions.
Events
Move Started, Move Stopped, Direction Changed, Facing Changed, Arrived.
Side-Scroller Controller (sideScrollerController)
Category: Control Description: Horizontal-focused movement (no gravity), with an optional vertical axis. Flips the sprite to face travel.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
controlledBy | enum | "player" | player, flow, ai, network |
maxSpeed | number | 220 | px/s |
acceleration | number | 900 | px/s² |
friction | number | 1200 | px/s² |
sideScrollerVertical | boolean | false | Also allow up/down movement |
rotateSprite | boolean | false | Flip sprite horizontally to face movement |
collideWithWorld / clampToStage | boolean | false | |
arrivalRadius | number | 8 | |
left/right/up/downKey, wasd | — | — | Same input fields as Platformer |
moving | boolean | false | output |
facing | enum | "right" | output |
Actions, Conditions & Events
Same shared action/condition/event set as Top-Down. No jump.
Driving a controller with AI
Set the controller's controlledBy to ai and add AI Mover — it drives moveDirection/moveToward/stop for you. For Flow-driven control, set controlledBy to flow and call Move Direction/Move Toward from graphs.
AI Brain (aiBrain)
Category: Control Description: Runs reusable .opbrain state machines and behavior trees with per-NPC memory and cancellable tasks.
Choose a blank state machine, blank behavior tree, or Guard template in the Inspector, then New behavior. Edit behavior opens the graph; the Library also opens saved behavior assets. See NPC state machines for the authoring workflow, transition ordering, movement ownership, and Guard setup. See NPC behavior trees for ordered priorities, reusable subtrees, cooldowns, and interruption rules.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Run the state machine during Play. |
behavior | assetRef | "" | Reusable .opbrain asset. |
overrides | object | {} | Initial per-NPC memory values; edited with typed controls. |
overrideTypes | object | {} | hidden; type metadata preserves object-reference remapping. |
currentState | string | "" | output; active leaf state's name. |
currentStateId | string | "" | output; active leaf state's stable ID. |
status | string | "idle" | output; loading, running, idle, or error status. |
error | string | "" | output; latest loading or execution diagnostic. |
blackboard | object | {} | output; current per-instance variables. |
Actions
Send Behavior Event queues an event for the next decision. Set Behavior Number, Set Behavior Boolean, Set Behavior Text, Set Behavior Vector, and Set Behavior Object write a declared variable. Restart Behavior restarts from the initial state with authored initial values.
Conditions
Is in State checks a state ID against the active path, including parents.
Events
| Event | Payload |
|---|---|
State Entered | stateId, name |
State Exited | stateId, name |
AI Mover (aiMover)
Category: Control Description: Drives a character controller (set to Controlled By: AI) to patrol, follow, or flee — no Flow wiring needed.
AI Mover decides where to go; the character controller on the same object does the moving. All speed and acceleration tuning lives on the controller.
Beyond the basic behaviors it can acquire targets by team, path around scenery, report whether it has a clear shot, and break off to hide when hurt. Each of those is opt-in — an AI Mover with default settings costs nothing more than a straight-line chase.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Turn AI movement on or off. |
behavior | enum | "patrol" | patrol, follow, flee, idle |
detectRange | number | 0 | px within which the target is noticed. 0 = always active. |
patrolDistance | number | 96 | px from the spawn point before turning back (Patrol). |
patrolAxis | enum | "horizontal" | horizontal, vertical (Patrol). |
stopWithin | number | 8 | How close to get before stopping (Follow). |
seesTarget | boolean | false | output; target is within Detect Range. |
Targeting
| Field | Type | Default | Notes |
|---|---|---|---|
targetMode | enum | "object" | object, nearestEnemy, nearestAlly. The auto modes resolve against the Team tag. |
target | objectRef | "" | The chased object in object mode. |
retargetInterval | number | 0.25 | Seconds between re-checks for a closer target. |
currentTargetId | string | "" | output; id of the object currently chased. |
Pathfinding
| Field | Type | Default | Notes |
|---|---|---|---|
avoidObstacles | boolean | false | Walk around scenery instead of pressing into it. |
obstacleGroup | string | "" | Only this group blocks. Empty = anything with a Collider 2D. |
agentRadius | number | 0 | Body width for pathing. 0 = derive from object size. |
navCellSize | number | 24 | Nav grid cell size in px. Smaller = tighter routes, costlier search. |
repathInterval | number | 0.5 | Seconds before the route is recalculated while still blocked. |
waypointReach | number | 16 | How close counts as reaching a waypoint. |
repathTolerance | number | 48 | Recalculate early once the target moves this far from the planned goal. |
isPathing | boolean | false | output; following a route rather than moving straight. |
Line of sight
| Field | Type | Default | Notes |
|---|---|---|---|
checkLineOfSight | boolean | false | Keep hasLineOfSight current even when not pathing. Implied by avoidObstacles. |
hasLineOfSight | boolean | false | output; nothing blocks the line to the target. |
Cover requests
Use Set Cover Seeking to request or release cover. Health thresholds, hold times, and cooldowns belong in project behavior. Existing projects receive an editable Cover Tactics script when migrated.
| Field | Type | Default | Notes |
|---|---|---|---|
coverSearchRadius | number | 260 | How far it will run to reach cover. |
useUnmarkedCover | boolean | true | Hide behind ANY blocking scenery when no object with a Cover component is in reach. Off restricts this unit to authored cover only. |
coverSeeking | boolean | false | output; an explicit cover request is active. |
isInCover | boolean | false | output; currently hidden from its target. |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Behavior | behavior | Set patrol/follow/flee/idle. |
Set Target | target | Chase a specific object. Also switches targetMode to object — otherwise auto-retargeting would overwrite the pick on its next pass. |
Set Target Mode | mode | Switch between the specific-object and auto modes; clears the held target. |
Set Enabled | enabled | Enable/disable AI movement. |
| Set Cover Seeking | seeking | Request cover, or release the current request and reservation. |
Conditions
| Condition | True when |
|---|---|
Has Target | A target is resolved — the acquired one in auto modes, not just the authored field. |
Sees Target | seesTarget is true. |
Has Clear Shot | hasLineOfSight is true. Needs checkLineOfSight or avoidObstacles on. |
Events
Target Spotted, Target Lost (no payload).
::: note Requires a character controller AI Mover locates any character controller on the same object each tick and drives it. The controller must be set to Controlled By: AI. :::
Acquisition is deliberately sticky
In the auto modes the current target is held until it dies, leaves Detect Range, or retargetInterval elapses. Re-running acquisition every tick makes a squad jitter between two near-equidistant enemies and costs a full scene scan per unit per frame.
Pathing needs a stage
The nav grid is confined to the scene's stage bounds. Without them the grid only spans the obstacles, and an agent blocked by a wall will route around the outside of the level.
Selectable (selectable)
Category: Input Description: Lets the player select this object (click or drag a selection box). Pair with Selection Box on a manager object.
The unit half of RTS selection. It owns no gesture — only the fact "am I selected", the events that fire when that changes, and a highlight ring so the state is visible with no authoring.
Selection is per-object state rather than a list on a manager, so a unit that dies or despawns takes its flag with it. Nothing has to prune a stale id.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Off makes the object unselectable without removing the component. |
selected | boolean | false | Whether it is selected right now. Read it in rules; Selection Box writes it. |
showHighlight | boolean | true | Draw a ring under the object while selected. |
highlightColor | color | "#5fe0cf" | |
highlightScale | number | 1.15 | Ring size relative to the object. |
Actions
| Action | Params | Behavior |
|---|---|---|
Select | — | Mark selected and fire Selected. |
Deselect | — | Clear it and fire Deselected. |
Toggle Selected | — | Flip the current state. |
Conditions
| Condition | True when |
|---|---|
Is Selected | This object is currently selected. |
Events
| Event | Payload | Fires when |
|---|---|---|
Selected | — | The object became selected. |
Deselected | — | It stopped being selected. |
::: note Selection is session state It clears when play stops, so a stopped session never leaves units marked selected back in the editor. :::
Selection Box (selectionBox)
Category: Input Description: Click or drag a box to select units (RTS-style), and right-click to issue a move order. Put this on one manager object; put Selectable on the units.
The gesture half. One per scene, on a manager object. It reads the pointer and mouse buttons directly each frame — it is already drawing the marquee per frame, so keeping the gesture and its rendering together avoids splitting one interaction across two places.
For a no-code move order without this component, the On Stage Tap event carries the stage position, the button, and the object under the pointer.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
selectGroup | string | "" | Only units in this group can be selected. Blank means any. |
selectTeam | string | "" | Only units on this team can be selected. Blank means any. |
selectBinding | binding | Left Mouse | Input that selects and drags the box. |
addBinding | binding | (unbound) | Held to ADD to the selection instead of replacing it (Shift is the convention). |
commandBinding | binding | Right Mouse | Input that issues an order at the pointer. |
dragThreshold | number | 6 | Stage units before a click becomes a box drag. |
clickRadius | number | 12 | How close a click must be to a unit's centre to pick it. |
clearOnMiss | boolean | true | Clicking empty ground deselects everything. |
boxColor | color | "#5fe0cf" |
Actions
| Action | Params | Behavior |
|---|---|---|
Clear Selection | — | Deselect every unit this box manages. |
Select All | — | Select every eligible unit. |
Conditions
| Condition | True when |
|---|---|
Has Selection | At least one managed unit is selected. |
Events
| Event | Payload | Fires when |
|---|---|---|
Selection Changed | count, ids | The selected set changed. |
Command Issued | x, y, targetId, count, ids | The command input fired with units selected. |
One event for move and attack
Command Issued carries targetId — empty when the order landed on empty ground (a move), set when it landed on another unit (an attack or follow). One event, one branch, instead of two gestures to wire.
Combat
Health (health)
Category: Combat Description: Tracks HP, applies damage and healing, emits lifecycle events.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
hp | number | 30 | Current HP (min 0) |
maxHp | number | 30 | Maximum HP (min 1) |
invulnerable | boolean | false | Blocks damage |
resetOnPlay | boolean | true | Refill to maxHp on play start |
Events
| Event | Payload |
|---|---|
damaged | amount, remainingHp |
healed | amount, remainingHp |
died | remainingHp (0) |
Actions
| Action | Params | Behavior |
|---|---|---|
damage | amount | Subtract HP; emit damaged; emit died at 0. |
heal | amount | Add HP up to maxHp; emit healed. |
setHp | value | Clamp and emit damaged/healed/died as needed. |
setMaxHp | value, adjustCurrent | Raise/lower max HP; optionally clamp current. |
refill | — | Set HP to maxHp. |
kill | — | Force HP to 0; emit died. |
Conditions
| Condition | Params | True when |
|---|---|---|
isDead | — | HP ≤ 0 |
isAlive | — | HP > 0 |
isAtFull | — | HP ≥ maxHp |
hpAtLeast | value | HP ≥ value |
hpBelow | value | HP < value |
Lifecycle
- onAttach: Clamps HP to maxHp if needed.
- onPlayStart: Refills HP when
resetOnPlayis true.
Stats (stats)
Status: Deprecated for new attachments. This fixed Attack/Defense/Speed schema is an RPG recipe. Define your game's stats in a project Behavior Component; existing Stats fields, modifiers, Flow and native script calls remain supported.
Category: Combat Description: Attack, defense, and speed with temporary bonuses.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
atk | number | 5 | Base attack |
def | number | 1 | Base defense |
spd | number | 5 | Base speed (used by Turn Queue) |
atkBonus / defBonus / spdBonus | number | 0 | Hidden modifiers |
Effective values in logic: base + bonus.
Events
| Event | Payload |
|---|---|
statChanged | stat, oldValue, newValue |
Actions
| Action | Params |
|---|---|
addModifier | stat (atk/def/spd), amount |
setBase | stat, value |
clearModifiers | — |
Conditions
| Condition | Params |
|---|---|
fasterThan | other (objectRef) — compares effective speed to another object's Stats; falls back to otherSpd when empty |
Ability Cooldown (abilityCooldown)
Category: Combat Description: Timed gate for abilities; counts down each frame.
Fields
| Field | Type | Default |
|---|---|---|
duration | number | 1.5 (seconds) |
remaining | number | 0 (read-only) |
autoStart | boolean | false |
Events
used, ready.
Actions
| Action | Returns |
|---|---|
use | false if still cooling; otherwise starts timer and emits used |
forceReady | Clears remaining; emits ready |
setDuration | value — updates duration |
Conditions
canUse (remaining ≤ 0), isCoolingDown.
Lifecycle
- onPlayStart: Sets
remainingfromautoStart. - onTick: Decrements
remaining; emitsreadywhen it hits zero.
Combat Action (combatAction)
Status: Deprecated for new attachments. Author your game's damage formula and turn advancement in a project Behavior Component. Use Health's accepted command results to distinguish refused damage from applied damage. Existing Combat Action attachments retain their behavior.
Category: Combat Requires: statsDescription: Applies stat-based attacks to another object's Health.
Damage formula: attacker atk + atkBonus + power + bonusPower − target def/defBonus, clamped to minimum damage. Friendly fire is blocked unless enabled.
Fields
| Field | Type | Default |
|---|---|---|
power | number | 0 |
minDamage | number | 1 |
variance | number | 0 |
useDefense | boolean | true |
allowFriendlyFire | boolean | false |
Events
attacked (attackerId, targetId, amount), blocked (attackerId, targetId, reason).
Actions
| Action | Params |
|---|---|
attack | targetId, power, minDamage, optional endTurn + turnQueueId |
Conditions
canAttack — target exists, has Health above 0, and is not an ally unless friendly fire is enabled.
Ranged Weapon (rangedWeapon)
Category: Combat Description: Fires at an enemy on a cooldown when it is in range and the shot is clear. Hitscan damage or a spawned projectile.
The other combat components each cover one piece: Combat Action applies a melee-range hit now, Hazard damages on contact, Projectile handles flight. Ranged Weapon is the one that decides when to shoot, at what, and whether the shot is worth taking.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
autoFire | boolean | true | Shoot on its own whenever a target is in range. Off = only on an explicit Fire. |
fireMode | enum | "hitscan" | hitscan (instant damage) or projectile (spawn a prefab). |
range | number | 260 | Max firing distance in px. 0 = unlimited. |
cooldown | number | 0.8 | Seconds between shots. |
aimFacing | enum | "none" | none, rotate, flipX. How the object turns toward what it shoots. |
canFire | boolean | false | output; cooled down, with a valid target in range and in sight. |
currentTargetId | string | "" | output; what it is aiming at. |
Damage (hitscan mode)
| Field | Type | Default | Notes |
|---|---|---|---|
damage | number | 2 | HP removed per shot. |
damageVariance | number | 0 | Random ± swing per shot. A hit never lands for 0. |
Targeting
| Field | Type | Default | Notes |
|---|---|---|---|
targetMode | enum | "auto" | auto (nearest enemy), mover (AI Mover target, then nearest enemy), or object. |
target | objectRef | "" | The target in object mode. |
Line of sight
| Field | Type | Default | Notes |
|---|---|---|---|
requireLineOfSight | boolean | true | Hold fire when scenery blocks the line. Off = arcing weapons that shoot over cover. |
obstacleGroup | string | "" | Only this group blocks shots. Empty = anything with a Collider 2D. |
Muzzle and projectiles
| Field | Type | Default | Notes |
|---|---|---|---|
muzzleX / muzzleY | number | 0 | Where shots leave from, in the object's own space. |
projectilePrefab | prefab | "" | Prefab spawned per shot (projectile mode). |
projectileSpeed | number | 600 | px/s (projectile mode). |
Actions
| Action | Params | Behavior |
|---|---|---|
Fire | — | Shoot now. Still respects enabled, cooldown, range, and line of sight. |
Set Enabled | enabled | Enable/disable the weapon. |
Conditions
| Condition | True when |
|---|---|
Can Fire | canFire is true. |
Has Target | A target is resolved. |
Events
| Event | Payload | Fires when |
|---|---|---|
Fired | targetId, angle | A shot leaves the muzzle (both fire modes). |
Hit | targetId, amount | Hitscan damage was applied. |
It shares AI Mover's target on purpose
New weapons use independent nearest-enemy targeting in auto mode. Choose mover to share an eligible AI Mover target, falling back to the nearest enemy when necessary. Version-one attachments migrate to mover to preserve their behavior.
Zero variance makes evenly-matched fights end in draws
With damageVariance: 0 every duel between identical units resolves on the same frame, so symmetric battles reliably end in mutual annihilation. A small variance desynchronizes them.
::: note Friendly fire is never possible Targets are filtered by the Team tag. A unit with no Team is neither ally nor enemy, so it is never shot — and never shoots. :::
Area Damage (areaDamage)
Category: Combat Description: Damages everything within a radius once, with distance falloff. The blast for rockets, grenades, mines, and exploding barrels.
Hazard damages what touches it and Combat Action damages one target; neither can express "everything near this point takes a hit". Attach this to a shell, a mine, a barrel, or a bare marker.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
radius | number | 90 | How far the blast reaches, in px. |
damage | number | 12 | HP removed at the center of the blast. |
falloff | boolean | true | Scale damage down toward the rim. Off makes the blast a flat disc, so where you stand inside it stops mattering. |
minDamage | number | 1 | Damage floor at the very edge when Falloff is on. |
detonateOnStart | boolean | true | Go off as soon as it spawns — right for a shell that has already landed. Off waits for a Detonate call, which is how a mine or a timed charge works. |
destroySelf | boolean | true | Retire this object once it has gone off. |
targetGroup | string | "" | Only objects in this group or team can be hurt. Empty = anything with Health. |
allowFriendlyFire | boolean | true | Let the blast hurt the shooter's own team. On by default — an explosion that spares your squad reads as fake. |
blockedByCover | boolean | false | Require a clear line from the blast to each victim, so scenery shields people behind it. |
obstacleGroup | string | "" | Which group shields the blast. Empty = anything with a Collider 2D. |
Actions
| Action | Params | Behavior |
|---|---|---|
Detonate | — | Go off now. Only ever fires once. |
Conditions
| Condition | True when |
|---|---|
Has Detonated | It has already gone off. |
Events
| Event | Payload | Fires when |
|---|---|---|
Detonated | hitCount, radius, x, y | The blast went off. |
Friendly fire is ON by default
An explosion that politely spares your own squad reads as fake, and blowing up your own soldier is a defining moment of the genre. The shell carries no Team of its own — the blast resolves sides through the object it was spawned from, so a projectile must be fired with spawn provenance for allowFriendlyFire: false to mean anything.
It detonates on the first TICK, not at play start
Play start walks objects in scene order and Health refills to maxHp in its own start hook, so a blast that fired during that sweep would have its damage silently undone on every victim that happened to start after it.
Ballistic (ballistic)
Category: Combat Description: Flies a shot from where it spawned to where it was aimed — straight and blockable, or arcing over cover. Pairs with Area Damage for explosive rounds.
Opal's other projectile, Projectile, is a physics arrow: it needs a Rigid Body, a Collider and a live physics world, and its purpose is welding into what it hits. A bullet or grenade wants none of that. Ballistic is kinematic — it moves itself and finds its own impact — so a firefight can put dozens of shots in the air without a physics body each.
Travel time is the point. A hitscan shot cannot be dodged, cannot miss a moving target, and cannot land behind someone.
Flight modes
| Mode | Behaviour |
|---|---|
direct | Flies along its heading and stops at the first obstacle. Cover blocks it. This is a bullet. |
lobbed | Arcs to the point it was aimed at, passing over everything. Cover does not protect you. This is a grenade. |
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
flightMode | enum | "direct" | direct, lobbed. Direct shots stop at the first obstacle. Lobbed shots arc over everything and land where they were aimed. |
speed | number | 420 | Travel speed in px/s. Slower shots can be dodged, which is what makes positioning matter. |
maxRange | number | 0 | Distance before it gives out. 0 = until it hits something or Lifetime expires. |
lifetime | number | 4 | Seconds before a shot that hit nothing expires. Stops strays living forever. |
damage | number | 0 | HP removed by a clean hit. Leave at 0 when an Area Damage blast is the whole weapon. |
hitRadius | number | 14 | How near a target counts as a hit. Too small and fast shots tunnel straight through people. |
targetGroup | string | "" | Only objects in this group or team can be hit. Empty = anything with Health. |
hitOwnTeam | boolean | true | Let the shot hit the shooter's own side. The shooter itself is always immune. |
obstacleGroup | string | "" | Which group stops a direct shot. Lobbed shots ignore this entirely — they go over. Empty = anything with a Collider 2D. |
arcHeight | number | 48 | How high a lobbed shot rises at the peak of its arc, in px. Purely visual lift — the shot is untouchable while airborne. |
spin | number | 0 | Degrees per second the shot tumbles in flight. Grenades read better with a little. |
flying | boolean | false | output; |
traveled | number | 0 | output; |
Actions
| Action | Params | Behavior |
|---|---|---|
Detonate Now | — | End the flight immediately where it is. |
Conditions
| Condition | True when |
|---|---|
Is Flying | The shot is still in the air. |
Events
| Event | Payload | Fires when |
|---|---|---|
Impact | targetId, reason, x, y | The shot hit something, landed, or expired. |
reason on impact is one of hit (struck a target), cover (stopped by scenery), landed (reached its aim point or max range), expired (lifetime ran out), or manual.
Aim points arrive through the spawn
Ranged Weapon in projectile mode passes the point it was aiming at as spawn launch data. A lobbed shot needs it — position and rotation alone cannot say "land here". A shell spawned without it simply flies its configured maxRange.
Collision is swept, not sampled
Impact is tested against the whole step, not just the endpoint. At 4000 px/s a frame is a 66px jump — endpoint-only checks would sail straight through a target.
The arc is visual lift only
A lobbed shot's height is cosmetic; the ground track still ends exactly on the aim point. Making the height real would move where it lands.
Cover (cover)
Category: Combat Description: Marks this object as a place units can take cover behind. Hands out standing spots on the side away from the shooter, and limits how many can shelter at once.
Put this on a sandbag, wall, crate or rock. It gives two things that inferring cover from raw geometry cannot:
- Authored intent. The designer decides what counts as cover. A decorative crate is not automatically a firing position just because it happens to block a sightline.
- Occupancy. Spots are claimed, so a squad spreads across the map instead of three soldiers piling onto one sandbag.
AI Mover prefers marked cover, and falls back to unmarked scenery only when nothing authored is in reach (see its useUnmarkedCover).
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Turn this cover off without deleting it — useful once it is destroyed. |
capacity | number | 1 | How many units can shelter here at once. More than one and they fan out along the face. |
standoff | number | 26 | How far clear of this object's edge a unit stands, in px. |
slotSpacing | number | 30 | Gap between units sharing this cover. |
releaseDistance | number | 260 | Once a claimant has ARRIVED, moving further than this frees its spot automatically. It never applies while a unit is still on its way. 0 = never auto-release. |
claimTimeout | number | 8 | Seconds a unit may reserve this without arriving before the spot is freed. Stops a reservation from leaking when the claimant never makes it. |
quality | number | 1 | Preference weight when a unit is choosing between cover. Higher wins ties; a sandbag nest can outrank a thin post. |
occupants | number | 0 | output; |
isFull | boolean | false | output; |
Actions
| Action | Params | Behavior |
|---|---|---|
Claim | claimantId, threatX, threatY | Reserve a spot and get the world position to stand at. Returns null when full or disabled. |
Release | claimantId | Give up a claimed spot. |
Release All | — |
Conditions
| Condition | True when |
|---|---|
Is Full | Every slot is claimed. |
Has Room | At least one slot is free. |
Events
| Event | Payload | Fires when |
|---|---|---|
Claimed | claimantId, occupants | A unit took this cover. |
Released | claimantId, occupants | A unit gave this cover up. |
Claims are validated, never trusted
Every tick this drops claimants that died, left the scene, arrived and then wandered past Release Distance, or reserved a spot and never showed up (Claim Timeout). A unit killed on its way to cover cannot call Release, so without this the map slowly fills with reservations held by corpses.
The distance check only applies after arrival
A unit claims from wherever it is standing, which is usually further away than Release Distance. Releasing on distance while it is still travelling would revoke the spot on the very next tick and loop forever — so a claim is only distance-released once the claimant has reached the cover at least once.
Turn Queue (turnQueue)
Status: Deprecated for new attachments. This component combines sequencing with defeated-unit eligibility, Speed initiative, battle victory and indicator placement. Author those rules in a project Behavior Component. Existing queues and their events remain supported.
Category: Combat Description: Cycles turns across objects in a named Group. Attach to a controller object; fighters share the same group string on their Thing.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
group | string | "" | Scene group name (e.g. Combatants) |
order | enum | "registered" | registered, speedDesc, random |
skipDefeated | boolean | true | Ignore visible members whose Health is 0 |
stopWhenOneTeam | boolean | true | End a multi-team battle once one team remains |
activeId | string | — | hidden; current actor object id |
queue | string | — | hidden; comma-separated id queue |
indicatorId | objectRef | "" | Optional arrow/marker snapped above the active combatant |
indicatorOffsetY | number | -48 | Gap used for automatic indicator placement |
Events
turnStart (actorId), turnEnd (actorId), roundStart, queueEmpty, battleEnd (winningTeam).
Actions
| Action | Description |
|---|---|
rebuild | Collect visible group members and rebuild queue. |
next | End current turn, advance; auto-rebuild if empty; may emit roundStart; moves indicatorId when set. |
positionIndicator | Snap marker above the active combatant (marker, offsetY). |
Conditions
isActive — compares activeId to a given object ref.
Ordering
- speedDesc: Sort by Stats
spd(higher first). - random: Shuffle member ids.
- registered: Scene order of members.
Team (team)
Category: Combat Description: Faction tag for ally/enemy checks in graphs.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | "neutral" | e.g. player, enemy |
Actions
setTeam — value (string).
Conditions
| Condition | Params |
|---|---|
isAlly | other (objectRef) — same team name |
isEnemy | other — different non-empty team |
Network Hit (networkHit)
Status: Deprecated for new attachments. Use Network Input targeting an explicitly authorized [NetworkAction] for new bindings. Existing Network Hit attachments keep their bounded host-authorized Health damage and cooldowns; ordinary guest scripts remain disabled.
Category: Combat Description: Explicitly permits a configured Health hit from a key or tap. Local games apply it locally; in a multiplayer room only the host applies the canonical damage.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
amount | number | 1 | Exact permitted damage, greater than zero and at most 1,000,000. |
cooldownMs | number | 150 | Per-player cooldown, 100–60,000 milliseconds. |
key | string | "" | Optional shortcut key, such as 1. Repeats, modifier chords and typing are ignored. |
tap | boolean | true | Allow a press/release over the same object's bounds, without dragging away. |
Behavior and dependencies
Configure these permission fields in the inspector; they do not generate Flow getter/setter nodes. Requires enabled Health on the same object. The shared editor/player input spine handles this declarative input before the guest gameplay guard and after UI consumption. The host checks room membership, the enabled component, exact damage, living Health and cooldown using its own world. Requests cannot install or expand the policy. Disabling the component, hiding the object or turning network sync off removes the grant. No additional actions, conditions, events or component lifecycle callbacks are declared; ordinary Health events drive authored reactions. The host's OpalScripts and Flow produce the replicated consequences. Guests never run those callbacks.
An injected embedding authorization policy takes precedence, including refusals. This is a shared target interaction, not general player input forwarding. Host departure freezes guest gameplay. See Multiplayer and sharing and the Crystal Crew example, which now uses general OpalScript network actions.
Health Bar (healthBar)
Category: UI Requires: healthDescription: Draws an HP bar above the object.
Fields
| Field | Type | Notes |
|---|---|---|
width, height | number | Bar size |
offsetY | number | Vertical offset above sprite |
showWhenFull | boolean | Hide bar at full HP |
showOnHover | boolean | Show on pointer hover or after damage |
fillColor, bgColor, lowColor | color | Bar colors |
lowThreshold | number | 0–1 fraction for "low HP" color |
flashOnHit | boolean | Brief flash on damage |
visible | boolean | hidden; runtime visibility |
Events
barShown, barHidden.
Actions
show, hide, flash.
Conditions
isVisible.
Sibling handlers
Reacts to Health on the same object without extra graph wiring:
| Handler key | Behavior |
|---|---|
health.damaged | Flash bar; show if showOnHover. |
health.died | Hide bar. |
Hazard (hazard)
Category: Combat Requires: collider2d (auto-attached) Description: Damages objects that touch it (targets need Health). Auto-adds a sensor Collider 2D.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
damage | number | 1 | HP removed per hit |
targetGroup | string | "" | Only objects in this group/team take damage; empty = anyone with Health |
continuous | boolean | false | Keep damaging on interval while in contact |
interval | number | 0.5 | Seconds between hits when continuous |
destroySelf | boolean | false | Vanish after dealing damage (projectiles) |
Events
| Event | Payload |
|---|---|
Hurt Something | targetId, targetName, amount |
::: note How it hurts Hazard runs the target's health.damage action on each qualifying contact. With continuous off, it damages a given target once per contact; with it on, every interval seconds while still touching. :::
Items
Inventory (inventory)
Category: Items Description: Named item stacks (serialized as an internal string map).
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
capacity | number | 99 | Max distinct item types |
items | string | "" | Read-only encoded stacks |
Events
itemAdded, itemRemoved, full.
Actions
| Action | Params |
|---|---|
add | item, count |
remove | item, count |
clear | — |
Conditions
has (item), hasAtLeast (item, count).
Pickup (pickup)
Category: Items Requires: collider2d (auto-attached) Description: Collectible: when a qualifying object overlaps it, fires Collected and vanishes. Auto-adds a sensor Collider 2D.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
collectorGroup | string | "" | Only objects in this group/team can collect; empty = anyone |
points | number | 1 | Score value in the Collected payload |
vanish | boolean | true | Hide on collect (uses Sprite Renderer's collect animation if present) |
collected | boolean | false | output; true once picked up |
Actions
| Action | Behavior |
|---|---|
Reset | Make the pickup collectible again and show it. |
Conditions
Is Collected — collected is true.
Events
| Event | Payload |
|---|---|
Collected | byId, byName, points |
::: note Vanish animation On collect, Pickup runs the Sprite Renderer collect action if one is present on the same object; otherwise it hides and marks done directly. :::
Logic
Timer (timer)
Category: Logic Description: Counts down and fires Completed when it elapses. Loops on demand. Drive it from Flow or auto-start on play.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
duration | number | 1 | seconds |
autoStart | boolean | true | Start counting when play starts |
loop | boolean | false | Restart automatically on completion |
running | boolean | false | output |
elapsed | number | 0 | output; seconds counted |
remaining | number | 0 | output; seconds left |
Actions
| Action | Behavior |
|---|---|
Start | Start or resume. |
Restart | Reset to zero and start. |
Stop | Pause where it is. |
Reset | Stop and clear elapsed to zero. |
Set Duration | Set duration in seconds. |
Conditions
Is Running, Is Done (not running, elapsed ≥ duration, duration > 0).
Events
| Event | Payload |
|---|---|
Started | duration |
Completed | duration |
Looped | count |
Spawner (spawner)
Category: Control Description: Spawns a prefab on an interval at this object's position. Great for enemy waves, obstacles, and pickups.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
prefab | assetRef | "" | Prefab asset to spawn (assetKind: blueprint) |
interval | number | 1.5 | seconds between spawns |
autoStart | boolean | true | Begin spawning on play start |
spawnOnStart | boolean | false | Emit first spawn immediately |
limit | int | 0 | Max spawns; 0 = unlimited |
offsetX / offsetY | number | 0 | Spawn offset from this object |
running | boolean | false | output |
spawnCount | number | 0 | output; total spawned this play |
Actions
| Action | Behavior |
|---|---|
Start | Start the spawner. |
Stop | Stop the spawner. |
Reset | Clear spawn count for a fresh limit. |
Spawn Now | Spawn one prefab immediately, ignoring interval. |
Conditions
Is Spawning — running is true.
Events
| Event | Payload |
|---|---|
Spawned | prefab, x, y, count |
Finished | count |
Prefabs are assets
Spawner spawns a prefab — a reusable object blueprint. Author the object once, save it as a prefab, then point prefab at it.
Physics (2D)
See the Physics guide for setup, coordinates, and troubleshooting.
Rigid Body 2D (rigidBody2d)
Category: Physics Description: Simulates mass and velocity. Requires Collider 2D to collide with other objects.
Fields (selected)
| Field | Type | Default | Notes |
|---|---|---|---|
bodyType | enum | "dynamic" | dynamic, fixed, kinematicPosition, kinematicVelocity |
gravityScale | number | 1 | 0 disables gravity for this body |
linearDamping | number | 0 | Slows linear motion |
lockRotation / lockX / lockY | boolean | false | Axis locks |
vx, vy, speed, sleeping | — | — | Read-only at runtime |
Events
collisionStart, collisionEnd — payload: otherId, otherName, started, sensor.
Actions
setVelocity, addVelocity, applyImpulse, setAngularVelocity, teleport, setBodyType, setEnabled, wake, sleep. Teleport coordinates are the world-space visual origin, including under transformed parents.
Conditions
isDynamic, isKinematic, isMoving, isSleeping.
Collider 2D (collider2d)
Category: Physics Description: Collision shape for Rapier. Collider-only attachments become implicit fixed bodies (floors, walls).
Fields (selected)
| Field | Type | Default | Notes |
|---|---|---|---|
shape | enum | "box" | box, circle, capsule |
useObjectSize | boolean | true | Match sprite bounds |
sensor | boolean | false | Trigger only — no physical push |
friction | number | 0.7 | Surface friction |
restitution | number | 0 | Bounce (0–1) |
colliding, contactCount | — | — | Read-only at runtime |
Events
Same collision events as Rigid Body 2D.
Actions
setSensor, setEnabled.
Conditions
isSensor, isColliding, hasContacts.
Joint 2D (joint2d)
Category: Physics Description: Connects this object's rigid body to another with a hinge, weld, or distance joint. Both objects need Rigid Body 2D (and usually Collider 2D).
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
target | objectRef | "" | Other object this joint connects to |
type | enum | "revolute" | revolute (hinge), fixed (weld), distance (rope/spring) |
anchorX / anchorY | number | 0 | Body-local pixels (0,0 = centre) |
targetAnchorX / targetAnchorY | number | 0 | Target body-local |
limitMin / limitMax | number | -180 / 180 | Degrees; revolute only |
motorSpeed | number | 0 | rad/s; revolute only |
motorForce | number | 0 | revolute only |
restLength | number | 0 | distance joint natural length; 0 = capture current separation |
stiffness | number | 0 | 0 = rope (max length only), >0 = spring |
collideConnected | boolean | false | Allow connected bodies to collide |
breakForce | number | 0 | Max anchor separation (px) before break; 0 = unbreakable |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Enabled | enabled | Enable/disable; releases physics on disable. |
Break Joint | — | Disable and release the joint. |
Set Limits | min, max | Set hinge angle limits (revolute). |
Set Motor | speed, force | Set motor speed/force (revolute). |
Events
Broke — otherId, force.
Soft Body 2D (softBody2d)
Category: Physics Description: Deformable jelly and cloth made from a spring-connected particle mesh. Sprite artwork deforms with the mesh; objects without artwork use Fill Color. Add it directly to a sprite or shape. The inspector provides Jelly, Cushion, Flag, and Curtain presets, each applied as one undo step. Resize the object to change its rest dimensions.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Owns the object's physics while enabled; ordinary rigid body/collider settings on the same object are unused |
mode | enum | jelly | Jelly preserves area; cloth folds freely |
shape | enum | box | Box or ellipse; jelly only. Cloth uses a rectangular mesh |
columns / rows | number | 7 / 7 | Particle counts per axis, 3–12; at most 144 particles per object |
pinning | enum | none | none, topCorners, topEdge, leftEdge, or corners; holds those particles at their authored world positions |
stiffness | number | 0.65 | Stretch resistance, 0–1; controls spring frequency |
areaStiffness | number | 0.8 | Area preservation, 0–1; jelly only |
bendStiffness | number | 0.2 | Resistance to folding across neighboring mesh cells, 0–1 |
damping | number | 0.65 | Spring damping ratio, 0–2; around 1 settles quickly |
linearDamping | number | 0.5 | Air resistance, 0–20 |
mass | number | 1 | Total mass shared among movable particles, 0.01–1000 |
gravityScale | number | 1 | Gravity multiplier, −10–10 |
initialVx / initialVy | number | 0 / 0 | Initial world velocity in pixels/second; positive Y points down |
particleRadius | number | 0 | Particle collision radius in local pixels; 0 fits mesh spacing automatically; positive values are capped by spacing |
friction | number | 0.5 | Sliding resistance, 0–4 |
restitution | number | 0.1 | Contact bounce, 0–1 |
ccd | boolean | true | Continuous collision for fast-moving particles |
color | color | #8b9dff | Fill when the object has no sprite artwork |
showMesh | boolean | false | Draw wireframe during Play and in exported games |
particleCount | number | 0 | read-only; live particle count |
speed | number | 0 | read-only; center-of-mass speed in pixels/second |
deformation | number | 0 | read-only; mean relative stretch/compression of mesh edges; 0.1 is about ten percent |
contactCount | number | 0 | read-only; number of other scene objects in contact |
Actions
| Action | Params | Behavior |
|---|---|---|
Apply Impulse | x, y | Distribute a total world-space impulse across movable particles |
Set Velocity | x, y | Set all movable particles' velocity in pixels/second |
Reset Shape | — | Restore the creation pose, rest shape, and initial velocities |
Set Enabled | enabled | Enable or release the soft body; ordinary rigid physics can resume when disabled |
Events
Collision Start and Collision End carry otherId, otherName, started, and sensor. Contacts are grouped by the other scene object, so several touching particles do not create duplicate object-level events.
Boundaries
Collision uses particle circles, not a continuous deformable surface: small objects can pass through gaps. A body's own particles do not collide with each other, so cloth can fold through itself. This is a spring mesh with area correction, not a fluid or finite-element material model. There is no tearing or remeshing. Higher resolution costs more rigid bodies, springs, and rendering work; start at 7 × 7 and measure the target device.
Soft bodies do not support skeletons, Tile Map 2D, or an enabled character controller on the same object. Sprite Material 2D lighting, emission and normals follow the deformed mesh, including rotated and mirrored artwork. Joint 2D cannot attach to soft-body particles or target a soft body. Pins attach to the authored pose; attaching arbitrary particles to moving objects is not exposed in this release. Saved scenes and exported packages store only authored fields, never simulated particle positions or live outputs.
Fluid 2D (fluid2d)
Category: Physics Description: Experimental particle liquid with shared-domain emitters, solid boundary coupling, and smooth surface rendering. The object's rectangle defines the initial fill, not the container. Use separate solid colliders for walls. Open Help → Fluid Playground… for a working example; see Experimental liquid for setup and limits.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Enable the domain; disabling releases its live particles |
initialFill | boolean | true | Fill the object's rotated/scaled rectangle on start or reset |
restDensity | number | 1 | Mass per square pixel, 0.01–100; matches collider density units |
viscosity | number | 0.02 | Velocity Smoothing, 0–0.2; numerical damping, not calibrated viscosity |
spacing | number | 8 | Sample spacing in world pixels, 4–32; changing it resets the running domain |
maxParticles | int | 2000 | Budget, 32–8000; emission pauses when full; high values need measurement |
iterations | int | 5 | Maximum compression correction passes per microstep, 1–12 |
compressionTolerance | number | 0.000001 | Early-exit target, 0–0.05; raising it can destabilize light props; not a guaranteed error bound |
vorticity | number | 0 | Swirl Preservation, 0–1; optionally restore a bounded share of smoothing energy loss; not surface tension |
color | color | #428de8 | Liquid tint |
renderMode | enum | surface | surface or particles |
surfaceOpacity | number | 0.94 | Smooth surface opacity, 0.1–1 |
foamIntensity | number | 0.45 | Visual foam where exposed water is disturbed (impacts, shear, breakup), 0–1; uniform flow stays clear; no added physics particles |
highlightIntensity | number | 0.55 | Surface rim highlight strength, 0–1 |
showParticles | boolean | false | Overlay particle samples on the surface |
showVelocity | boolean | false | Overlay live velocity arrows |
particleCount | number | 0 | read-only; current number of live particles |
densityError | number | 0 | read-only; mean positive relative compression, excluding free-surface deficits |
renderMs | number | 0 | read-only; CPU surface work including Canvas raster/draw or WebGL submission; excludes asynchronous GPU completion |
maxDensityError | number | 0 | read-only; maximum positive density error in the latest microstep |
solverIterations | number | 0 | read-only; latest microstep correction count |
runtimeMs | number | 0 | read-only; fluid CPU per fixed tick, excluding Rapier solve, sync, publication and rendering |
emittedRate / drainedRate | number | 0 | read-only; actual births/removals per latest tick divided by tick duration |
blockedCount | number | 0 | read-only; occupied or solid-blocked birth attempts in the latest tick |
capacityCount | number | 0 | read-only; birth attempts rejected by capacity in the latest tick |
Actions
| Action | Params | Behavior |
|---|---|---|
Sample Water | x, y | Detached point occupancy and weighted flow from committed liquid; see typed Fluid2D.SamplePoint |
Clear Liquid | — | Remove all live particles |
Reset Liquid | — | Clear and recreate the initial fill; separate props retain their poses |
Set Enabled | enabled | Enable or release the live domain |
Authored settings and object references save normally. Live particles and output values do not persist. The experimental PBF solver supports solid rigid colliders; separate domains, soft bodies, skeleton bones, and network peers do not exchange fluid state.
Fluid Emitter 2D (fluidEmitter2d)
Category: Physics Description: Pour particles into a selected Fluid 2D domain. Multiple emitters feeding the same domain interact. Object width sets the nozzle width and rotation turns its local velocity.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Continuous emission enabled |
domain | objectRef | "" | Fluid 2D object to receive particles |
rate | number | 100 | Requested particles per second, 0–2000 |
velocityX / velocityY | number | 0 / 100 | Local pixels per second, −4000–4000; rotated with nozzle |
emittedRate | number | 0 | read-only; actual births per latest tick divided by tick duration |
blockedCount / capacityCount | number | 0 | read-only; occupied/solid-blocked or budget-rejected attempts in the latest tick |
domainAvailable | boolean | false | read-only; a live domain is available |
Actions
| Action | Params | Behavior |
|---|---|---|
Emit Burst | count | Request 1–2000 particles in a compact block at the nozzle; respects occupied slots and budget |
Set Emitting | enabled | Start/stop continuous emission; explicit bursts remain available |
Fluid Drain 2D (fluidDrain2d)
Category: Physics Description: Remove particles from the selected domain inside this object's rotated/scaled rectangle. No sensor collider is required.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Drain enabled |
domain | objectRef | "" | Fluid 2D object to drain |
drainedRate | number | 0 | read-only; removals per latest tick divided by tick duration |
domainAvailable | boolean | false | read-only; a live domain is available |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Draining | enabled | Enable/disable removal |
Fluid Probe 2D (fluidProbe2d)
Category: Physics Description: Observe approximate liquid occupancy at this object's center plus a local offset. Latest committed physics positions supply flow and relative movement. A point probe is not an exact volume/depth measurement or a swept contact detector.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Enable observations; disabling clears live state |
domain | objectRef | "" | Fluid 2D domain to sample |
offsetX / offsetY | number | 0 | Local point offset, rotated and scaled with the object |
enterCoverage | number | 0.4 | Entry occupancy threshold, 0.001–1 |
exitCoverage | number | 0.25 | Exit threshold, 0–1, capped at entry threshold to prevent chatter |
splashSpeed | number | 120 | Minimum relative entry speed in pixels/second for a splash event |
wet | boolean | false | read-only; point occupancy after hysteresis |
coverage | number | 0 | read-only; kernel occupancy estimate, 0–1 |
velocityX / velocityY | number | 0 | read-only; weighted local water flow, world pixels/second |
speed | number | 0 | read-only; water speed in pixels/second |
relativeSpeed | number | 0 | read-only; probe speed relative to water |
domainAvailable | boolean | false | read-only; exact referenced domain belongs to the current simulation |
Events and conditions
Entered Water, Exited Water and Splash publish a FluidContact snapshot to Flow and OpalScript. Splash requires a prior available-domain observation and sufficient relative speed; spawning or first binding inside water does not splash. In Water reads the current wet state. See FluidProbe2D and FluidContact for typed signatures and examples.
Ragdoll (ragdoll)
Category: Physics Description: Makes a skinned skeleton go limp using physics bones authored in Skeleton Studio. Activate on death or via action.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
activateOnDeath | boolean | true | Activate ragdoll when Health dies |
active | boolean | false | output; currently limp; version 2 drops saved activity |
blendBack | number | 0 | hidden; reserved, retained for stored-data compatibility; does not blend |
Actions
| Action | Params | Behavior |
|---|---|---|
Activate | — | Spawn bone bodies at the current animated pose and go limp; stops skeleton clips. |
Deactivate | — | Free bone bodies; bones keep last limp pose. |
Impulse Bone | boneId, x, y | Apply a linear impulse to one physics bone. |
Events
| Event | Payload |
|---|---|
Activated | — |
Bone Hit | boneId, otherId, otherBoneId |
::: note Activates on death With activateOnDeath on, Ragdoll listens for the Health died sibling event and activates automatically. :::
Projectile (projectile)
Category: Physics Description: Arrow / bolt / dart flight: points along velocity while flying and can weld into what it hits. Requires dynamic Rigid Body 2D + Collider 2D. Enable Continuous Collision on the rigid body so fast shots don't tunnel.
Fields (selected)
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | |
alignToVelocity | boolean | true | Face direction of travel each tick |
minAlignSpeed | number | 30 | px/s; skip alignment when slower |
turnSpeed | number | 0 | deg/s; 0 = snap instantly |
angleOffset | number | 0 | Degrees if art doesn't point +X at rotation 0 |
stickOnHit | boolean | true | Weld into first solid hit (sensors never stick) |
ignoreOwner | boolean | true | Never stick to the spawner / owner hierarchy |
stickGroup / ignoreGroup | string | "" | Optional group filters |
armDelay | number | 80 | ms before sticking arms (avoids welding to shooter on spawn) |
breakForce | number | 0 | Max anchor separation (px) before tear-free; 0 = stuck for good |
stuck / stuckToId | — | — | output |
Actions
| Action | Params | Behavior |
|---|---|---|
Launch | speed, angle | Fire along facing (or explicit angle); unsticks first and re-arms stick delay |
Unstick | — | Release the weld |
Set Owner | targetId | Assign who fired this (spawned projectiles get owner automatically) |
Conditions
Is Stuck
Events
| Event | Payload |
|---|---|
Stuck | otherId, otherName |
Unstuck | otherId, reason |
Scene
Scene Camera (scene_camera)
Category: Scene Description: Named camera shots with tracking, bounds and optional simultaneous screen views. Camera controls use world positions and game time; their Play state is separate from saved authorship.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
playerFit | enum | "cover" | cover fills this output; contain fits the stage with margins. Shared by editor Play and the exported player. |
zoom | number | 1 | 0.35–4; the same range for authoring and live controls. |
followInPlay | boolean | false | Track the configured target in Play. |
previewFrame | boolean | true | Draw this camera's frame guide in Arrange. |
followTargetId | objectRef | "" | Initial framing target; continuously tracked when follow is enabled. |
followSmoothingMs | number | 450 | Damping time in game milliseconds; 0 snaps. |
followOffsetX | number | 0 | World-unit horizontal offset. |
followOffsetY | number | 0 | World-unit vertical offset. |
deadZoneWidth | number | 0 | Visible-frame fraction (0–1) within which the target can move without horizontal tracking. |
deadZoneHeight | number | 0 | Visible-frame fraction (0–1) for vertical tracking. |
boundsMode | enum | "none" | none, stage, or custom; constrains the visible world rectangle. |
boundsX | number | 0 | Custom bounds left edge. |
boundsY | number | 0 | Custom bounds top edge. |
boundsWidth | number | 1024 | Custom bounds width. A smaller area than the visible frame is centered. |
boundsHeight | number | 720 | Custom bounds height. |
outputMode | enum | "primary" | primary draws when this camera is active; viewport draws an additional view; disabled produces no output. |
outputX | number | 0 | Fraction of the canvas from its left edge. |
outputY | number | 0 | Fraction of the canvas from its top edge. |
outputWidth | number | 1 | Canvas width fraction, clipped at the right edge. |
outputHeight | number | 1 | Canvas height fraction, clipped at the bottom edge. |
outputOrder | number | 0 | Higher values draw above lower ones; ties draw the primary first, then use stable camera-ID order. |
inputEnabled | boolean | true | Pointer input uses the foremost eligible view. Disabled input lets gestures reach a view behind it. |
isDefault | boolean | false | Read-only startup status; choose Use at scene start in the camera inspector. |
Actions
| Action | Params | Behavior |
|---|---|---|
Set Zoom | value | Immediately change this camera's zoom. |
Follow Object | targetId, followInPlay | Set or release this camera's continuous tracking. |
Clear Follow | — | Release tracking and the current move. |
Reset camera | — | Reset framing and clear motion. |
Zoom To | value, duration | Ease to a zoom while continuing any active follow. |
Focus | targetId, zoom, duration | Frame a target's world position without enabling follow. |
Move To | x, y, zoom, duration | Move to a world position. |
Activate Camera | — | Use this camera as the primary output for this Play session. |
Shake | intensity, duration | Shake this view, respecting reduced motion. |
Stop Motion | — | Stop movement, follow and shake at the current pose. |
World To Screen | x, y | Project a world point through this camera's current resolved view into canvas CSS pixels. |
Screen To World | x, y | Inverse projection through this camera's current resolved view. |
Component action durations are game milliseconds; typed OpalScript ZoomTo, Focus, MoveTo and Shake take seconds. New moves interrupt older ones. A missing target refuses Focus/Follow; deleting a followed target releases tracking.
Events and conditions
moveCompleted, moveCancelled, and shakeCompleted carry camera/target IDs, resulting center and zoom, duration and reason. Conditions: isDefault, hasFollowTarget.
Use Create → Camera for another named shot. The camera inspector offers full-screen, split-left, split-right and inset presets. Existing cameras receive additive version-2 defaults; the persisted scene setting activeCameraId chooses the startup camera. Runtime activation does not change saved startup settings.
Screen-space HUDs and the global Camera.WorldToScreen / Camera.ScreenToWorld API use the primary view. Use the SceneCamera component's conversions for a particular output. Each view renders the same world; physics, scripts and animation still update once per frame. Bloom and Scene Render settings on a camera affect its own view.
Combining components (patterns)
| Goal | Components |
|---|---|
| Damageable enemy | Health, Stats, Combat Action, Team, Health Bar |
| Player character | Health, Stats, Combat Action, Team, Health Bar, Inventory |
| Animated platformer hero | Platformer Controller + Sprite Renderer + Sprite Animator (autoLocomotionStates on) |
| AI guard | Top-Down/Side-Scroller Controller (controlledBy: ai) + AI Mover |
| Skill button | Ability Cooldown + Object Flow on use / canUse |
| Battle loop | Turn Queue on a controller + group-tagged fighters |
| Collectible coin | Pickup (auto-adds sensor Collider 2D) |
| Spikes / damage zones | Hazard (auto-adds sensor Collider 2D) |
| Sticky arrow / bolt | Projectile + dynamic Rigid Body 2D (CCD on) + Collider 2D |
| Enemy waves | Spawner pointing at an enemy prefab |
| Physics prop | Rigid Body 2D + Collider 2D |
| Static platform / floor | Collider 2D only |
| Hinged door / lever | Joint 2D (revolute) between two Rigid Body 2D objects |
| Death flop | Health + Ragdoll (activateOnDeath on) |
| Countdown / spawn cadence | Timer driving other actions, or Spawner's own interval |
| Paint-order group | Sorting Group on a parent + Sprite Renderers on children |
For custom types authored in the editor, see Behavior Components.
Network Owner (networkOwner)
Category: Network
Assigns a Play object to one room player. LocalInput runs only for the client whose player id matches this component's runtime owner, and owner-only network actions are refused before OpalScript executes. Host OpalScript assigns ownership through Network.SetOwner(entity, playerId); room identities are never authored into a project.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
ownerOnly | boolean | true | Require the requesting player to own this object before any [NetworkAction] executes. |
The internal replicated ownerId is intentionally absent from the Inspector. It is cleared when its player leaves or the Play world changes. See Multiplayer and sharing.
Network Input (networkInput)
Category: Input
Routes a tap, key or Flow request to an OpalScript [NetworkAction] on this object. The host checks the active method signature and runs its gameplay permission rules. Works in local Play, the editor and exported players; guest scripts remain disabled.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
component | string | empty | Script component ID, such as crewCrystal. |
action | string | empty | Exposed method name, such as Hit. |
arguments | string | [] | JSON array of scalar values in parameter order. |
key | string | empty | Optional shortcut key. |
tap | boolean | true | Request when a tap ends over the object's bounds without dragging. |
These fields are inspector configuration and do not generate Flow field accessors. The request action requests the configured method and values through the same host authorization path. There are no additional events or conditions. Network Input grants no native damage, inventory or other gameplay policy itself. See Multiplayer and sharing for script syntax and limits.
General capabilities and tile rendering
Proximity Sensor (proximitySensor)
Detects nearby objects in a radius or facing cone, with optional group, component and line-of-sight filters. Does not move or attack.
Membership is a snapshot of live object IDs in world space; invisible objects and objects with zero Health can still be sensed. Radius 0 detects coincident origins. The cone faces local +X. Group filters use the canonical group/team query; line of sight uses other Collider 2D footprints. Disable, removal and Stop release membership. It never moves, attacks or initializes physics.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Enabled |
radius | number | 128 | World-space distance from this object's visual origin. 0 detects only coincident origins. |
angle | number | 360 | Cone width in degrees, facing this object's local +X axis. 360 detects all directions. |
group | string | "" | Optional group or team name to detect. |
component | string | "" | Optional enabled component that a detected object must have. |
lineOfSight | boolean | false | Exclude targets blocked by other Collider 2D footprints. |
nearestId | objectRef | "" | output; Nearest Object |
count | int | 0 | output; Detected Count |
Actions
setEnabled: Enables sensing, or disables it and clears detected IDs and count immediately..
Conditions
hasTargets: Returns true when the latest scan detected at least one object..
Events
entered: Emits an object's ID when it first satisfies this sensor's range and filters..exited: Emits an object's ID when it leaves the range or no longer satisfies the filters..nearestChanged: Emits the previous and current nearest object IDs; an empty ID means no detected object..
Resource Meter (resourceMeter)
A named bounded numeric resource with exact spending and committed change results.
initialValue is saved configuration; value and fraction are live outputs reset on each Play. Set/Add refuse changes outside the bounds; Spend accepts only finite nonnegative costs and commits exactly or refuses. Commands return immutable ResourceChange records with a signed actual delta and identity. Changed/Empty/Full carry that committed result. Equal minimum and maximum is valid with fraction 0; invalid ranges produce a setup notice and refuse commands.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | "resource" | Name |
min | number | 0 | Minimum |
max | number | 100 | Maximum |
initialValue | number | 100 | Initial Value |
value | number | 100 | output; Value |
fraction | number | 1 | output; Fraction |
Actions
set: Set an exact value within the authored range, or return a refusal without changing it..add: Apply an exact signed amount, refusing changes outside the authored range..spend: Subtract a finite nonnegative cost only when the entire cost is available..refill: Set the resource to its authored maximum and return the committed change..
Conditions
isEmpty: True when the current value equals a valid authored minimum..isFull: True when the current value equals a valid authored maximum..canSpend: True when a finite nonnegative cost can be spent in full without crossing the minimum..
Events
changed: Emitted after an accepted command commits a new value..empty: Emitted when an accepted change reaches the minimum from above..full: Emitted when an accepted change reaches the maximum from below..
Transform Constraint (transformConstraint)
Copies selected parts of another object's world pose with offsets and optional smoothing, without changing hierarchy. Refuses pose-owner conflicts and dependency cycles.
Targets are stored as IDs and resolved in the current world. World offsets use world units; local offsets follow the target axes and scale. Rotation offsets are radians. Smoothing 0 snaps; positive values are an exponential response rate per second. Cycles and enabled physics/controllers or overlapping Motion operations refuse pose writes with a diagnostic. Stop restores the starting local pose. Use parenting when every channel should inherit together.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Enabled |
target | objectRef | "" | Target |
copyPosition | boolean | true | Copy Position |
copyRotation | boolean | false | Copy Rotation |
copyScale | boolean | false | Copy Scale |
offsetX | number | 0 | Offset X |
offsetY | number | 0 | Offset Y |
offsetSpace | enum | "world" | World units, or target-local units rotated and scaled with the target. |
rotationOffset | number | 0 | Additional world rotation in radians. |
scaleMultiplier | number | 1 | Scale Multiplier |
smoothing | number | 0 | Exponential response rate per second. 0 snaps to the target; positive values approach it smoothly. |
active | boolean | false | output; Active |
diagnostic | string | "" | output; Diagnostic |
Actions
setTarget: Sets the object whose world pose will be copied on the next update..clearTarget: Clears the target and stops copying its pose without moving this object..setEnabled: Enables or disables pose copying without changing this object's current pose..
Conditions
isActive: Returns true when the latest update copied the target pose without a conflict or invalid reference..
Audio Emitter (audioEmitter)
Owns one sound voice. Play, loop and stop it with volume, pitch and stereo pan.
One emitter owns one voice from the canonical audio service. Repeated Play replaces it. Stop, disable, removal and world retirement abort delayed asset/decode work and release playback. Loop uses the same voice; volume (0–2), pitch (0.01–4) and stereo pan (−1–1) are live controls. Playing/Status are outputs. Missing/unavailable sounds fail without starting a voice; the next Play uses current asset bytes after a rebake. There is no automatic distance attenuation.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
sound | assetRef | "" | Sound |
autoPlay | boolean | false | Play on start |
loop | boolean | false | Loop |
volume | number | 1 | Volume |
pitch | number | 1 | Pitch |
pan | number | 0 | Stereo pan |
playing | boolean | false | output; Playing |
diagnostic | string | "" | output; Status |
Actions
play: Replace this emitter's voice with the configured sound; playback status updates after loading..stop: Cancel pending loading and stop this emitter's voice..
Conditions
isPlaying: Whether the owned sound voice is playing..
Events
started: A sound voice was admitted and started..stopped: The owned voice was stopped explicitly, disabled or released..finished: The owned voice ended naturally..
Value Bar (valueBar)
Draws a world-space bar for any numeric field or computed getter, or a directly supplied value.
Empty Source Component uses the direct Value, which Flow or SetValue can update. Otherwise choose an object ID (empty means this object), component ID and declared numeric field or computed getter, such as resourceMeter.value or health.hp. Minimum/Maximum are explicit display bounds. Missing, dead, disabled or mistyped sources hide the bar and expose a diagnostic; valid sources recover automatically. Fractions clamp without rewriting the source. The bar follows pivot-aware world transforms and uses Render2D track/fill commands with a Canvas compatibility fallback. Vertical fill grows upward.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
value | number | 0 | Used when Source Component is empty; writable from Flow. |
min | number | 0 | Minimum |
max | number | 100 | Maximum |
sourceObject | objectRef | "" | Empty reads this object. |
sourceComponent | string | "" | Source component |
sourceField | string | "value" | Source field |
width | number | 80 | Width |
height | number | 8 | Height |
offsetX | number | 0 | Offset X |
offsetY | number | -24 | Offset Y |
direction | enum | "horizontal" | Fill direction |
fillColor | color | "#5dd17a" | Fill |
bgColor | color | "#1a1f29" | Background |
visible | boolean | true | Visible |
showWhenFull | boolean | true | Show when full |
fraction | number | 0 | output; Fraction |
available | boolean | false | output; Source available |
diagnostic | string | "" | output; Status |
Actions
setValue: Set the direct value used when Source Component is empty..show: Show the bar when its numeric source is available..hide: Hide the bar..
Conditions
isAvailable: Whether the current declared numeric source and display range are valid..
Sequence Queue (sequenceQueue)
Sequences object IDs without eligibility or victory rules. Duplicate IDs are distinct occurrences; Remove ends the active matching occurrence first, then removes the first pending occurrence.
Authored Items seed a private runtime queue on Play; commands do not rewrite that list. At most 256 active plus pending occurrences are admitted. Duplicated IDs are valid occurrences. Remove removes the active occurrence first, otherwise the first pending occurrence; removal does not advance automatically. Next ends the active occurrence and starts the next; Repeat requeues the ended occurrence. Clear resets position to −1. Destruction does not silently skip a job. Immutable command results and item events report the committed snapshot; eligibility and victory stay in project logic.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
items | list | [] | Initial Items |
repeat | boolean | false | Requeue each ended item at the tail when Next is called. |
autoStart | boolean | false | Start on play |
activeId | string | "" | output; Active Item |
position | int | -1 | output; Zero-based number of items started since Play/reset. -1 before the first item. |
queuedCount | int | 0 | output; Active plus pending occurrences. |
Actions
enqueue: Append one ID occurrence, refusing empty IDs or a queue of 256 occurrences..remove: End the active matching occurrence first, otherwise remove the first matching pending occurrence..next: End the active occurrence and start the next, optionally requeuing the ended occurrence at the tail..clear: End the active occurrence, discard pending occurrences, and reset the started-item position..
Conditions
isEmpty: True when no active or pending occurrence remains..hasActive: True when a sequence occurrence is currently active..
Events
itemStart: Emitted after Next commits a new active occurrence..itemEnd: Emitted when Next, Remove, or Clear ends an active occurrence..empty: Emitted after the queue becomes empty, or Next finds no remaining occurrence..
TileMap 2D (tileMap2d)
Paints a camera-culled 2D grid from a tile atlas or fitted standalone image. Includes runtime cell editing for procedural levels.
Cells and palette are authored tile data; the renderer visits only the visible cell window. Changes are normalized at the field-change boundary, rather than rescanning the whole map on every render. Render cost still depends on visible commands, material and backend; this is not a total frame-time guarantee.
Fields
| Field | Type | Default | Notes |
|---|---|---|---|
tileset | assetRef | "" | Tile atlas or standalone image painted by this map. |
tilesetSource | enum | "atlas" | Slice a tile atlas into cells, or fit the entire image into each painted tile. |
tileWidth | int | 32 | Tile Width |
tileHeight | int | 32 | Tile Height |
margin | int | 0 | Atlas Margin |
spacing | int | 0 | Tile Spacing |
imageFit | enum | "contain" | Contain preserves the whole image; Cover fills the tile; Stretch fills without preserving aspect; Crop keeps original pixel size. |
smoothing | boolean | false | Enable bilinear sampling. Leave off for crisp pixel art. |
opacity | number | 1 | Opacity |
collisionEnabled | boolean | true | Build efficient merged physics colliders from cells whose source tile is marked Solid. |
collisionFriction | number | 0.7 | Friction |
collisionRestitution | number | 0 | Bounce |
collisionContactSkin | number | 0 | Contact Skin |
mapWidth | int | 16 | Columns |
mapHeight | int | 10 | Rows |
Actions
setCell.eraseCell.fillRect.floodFill.setTileSolid.clear.
Conditions
cellIs.cellIsEmpty.cellIsSolid.worldPointIsSolid.
Events
cellChanged.mapCleared.tileCollisionChanged.collisionStart.collisionEnd.
Runtime admission details: Spawner consumes its count/limit only for admitted creation. Projectile-mode Ranged Weapon consumes its cooldown only for admitted creation. Both require a prepared prefab plan; spawnRefused / fireRefused report unavailable or refused requests. Hitscan still emits Fired for a valid shot; Hit reports only an accepted Health change. Timer delivers at most 128 elapsed looping cycles per tick, carrying any backlog; reentrant Stop, Restart or duration changes interrupt the current catch-up pass.