Behavior Components
A Behavior Component is a reusable custom component authored as a project script. It uses the same registry, Inspector fields, Object Flow nodes, lifecycle, and runtime host as Opal's built-ins.
The workflow stays close to the object:
- Create or edit the definition in Scripts.
- Select an object in Arrange.
- Attach the component from the Inspector's Components card.
- Configure that object's field values.
- Use Edit Source on the attached component when you need to change its shared definition.
Components are not a separate workspace. The Inspector owns attachments and per-object settings; Script Studio owns reusable source.
Create a Behavior Component
Open Scripts, choose New → Behavior Component, and edit the generated opal.component(...) source:
export default opal.component("RageMeter", {
label: "Rage Meter",
category: "Combat",
description: "Builds rage on hit and fires when full.",
fields: {
rage: { type: "number", default: 0 },
max: { type: "number", default: 100 },
},
events: {
full: {},
},
actions: {
charge: {
label: "Charge",
params: {
amount: { type: "number", default: 1 },
},
body: "self.rage = Math.min(self.max, self.rage + params.amount); if (self.rage >= self.max) emit('full');",
},
},
conditions: {
isFull: {
label: "Is Full",
body: "self.rage >= self.max",
},
},
});Script Studio validates the source and keeps the last successfully compiled definition active when a new edit has an error. Once the script compiles, Rage Meter appears in the Inspector's Add Component menu.
Definition options
| Option | Purpose |
|---|---|
label, category, icon, description | Identity and authoring UI |
fields | Typed, per-attachment values shown in the Inspector |
events | Signals the component can emit to Flow |
actions | Named operations exposed as Component Action nodes |
conditions | Named checks exposed as Component Condition nodes |
requires | Component IDs that should be attached first |
onStart, onTick, onEnd | Play lifecycle behavior |
Field specs use the same types as built-ins, including number, boolean, string, enum, vector, color, objectRef, componentRef, assetRef, and eventKey. See Authoring components in code for the common field options.
Action and condition bodies
An action body can mutate fields, call sibling components, or emit declared events. Its available names include:
| Name | Meaning |
|---|---|
self | This attachment's field values |
params | Values passed by the caller or Flow node |
state | Private runtime scratch for this attachment |
thing | The object that owns the component |
get, run, check | Read, call, or query sibling components |
emit | Fire a declared component event |
source, target, event | Current event context when available |
Condition bodies evaluate to a boolean. Keep action and condition bodies small; use Object Flow to orchestrate waits, scene transitions, and multi-step event logic.
Lifecycle behavior
Use lifecycle hooks when an object should run code without a Flow graph:
export default opal.component("Spinner", {
label: "Spinner",
category: "Behaviors",
fields: {
speed: { type: "number", default: 90, label: "Speed (deg/sec)" },
},
onStart: "state.elapsed = 0;",
onTick: { spin: "self.speed" },
});| Hook | Runs |
|---|---|
onStart | Once when Play begins |
onTick | Every frame during Play; dt is available |
onEnd | Once when Play stops |
Lifecycle string bodies can use state for per-instance scratch during the current Play session. Common onTick object forms such as { spin: "self.speed" } and { drift: { x: "60", y: "0" } } expand to Opal's motion-safe helpers. String bodies can also use helpers.spin, helpers.moveBy, and angle conversion helpers.
Attach and edit instances
- Select an object in Arrange.
- Open the Inspector's Components card.
- Choose Add Component and search by label, category, or component ID.
- Edit the generated field controls on the attached card.
Those values belong to that object. Attaching the same Behavior Component to two objects gives each its own field values and runtime scratch state.
Use Edit Source on a script-authored component card to open its project script. Definition edits apply to every attachment after a successful compile; instance field values remain object-owned.
Use from Object Flow
Behavior Components extend the selected object's Flow catalog exactly like built-ins:
- Actions become Component Action nodes.
- Conditions become Component Condition nodes.
- Declared events can start or feed rules.
- Fields can be exposed to component value nodes and expressions according to their field spec.
Attach the component before authoring its object graph so its entries appear near the top of the catalog.
Persistence and identity
The source definition is stored once in the project's script records. Scenes do not store a separate custom-component definition list. Each object serializes only its attachment:
{
"type": "rageMeter",
"version": 1,
"fields": {
"rage": 0,
"max": 100
}
}Component IDs are the link between definitions and attachments. Renaming an ID changes that identity, so update or reattach existing instances deliberately. Removing the source removes the registered custom type; clean up attachments that still reference it.
Choosing the right tool
| Need | Use |
|---|---|
| Reusable state and behavior attached to objects | Behavior Component |
| Event wiring, waits, and readable scene orchestration | Object Flow or Scene Flow |
| One reusable calculation or custom graph operation | Script-authored Flow node |
| Engine-level capability shipped with Opal | Built-in component in code |