Shared action reactions
Use react when an accepted action should produce a short-lived effect for nearby participants. It runs after the reducer and returns bounded feedback, optional area-removal intent, or null.
Input is separate from reaction
An interaction declares tap or bump actions. The action still passes normal permission and payload checks. react(state, previous, action, context) then describes the outcome.
ts
react: () => ({
feedback: {
durationMs: 600,
burst: { color: '#a9e8ff', radiusCells: 1.5, particles: 0 },
audio: [{ kind: 'play', voice: 'bell', sound: 'bell', delayMs: 0,
gain: 1, rate: 1, loop: false, rangeCells: [1, 8], stereo: 0.7 }],
},
}),1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Declare the referenced sound in sounds or soundBank. Chime is a complete example.
Delivery
Scape validates feedback before committing state, then emits a transient event after the scene transaction succeeds. The host supplies position, floor, time, instance and operation identity.
Retries, repeated snapshots and late joins do not replay feedback. Delivery is best effort; it is not a durable message queue. Stale events, mismatched builds, floor changes and inactive gameplay cancel or suppress output.
Effects last 1–2,000 ms. Audio must be non-looping and start before expiry. Optional burst, lighting, sprite impulse, camera shake and haptic feedback are bounded. Reduced motion suppresses moving particles, impulses and camera shake.
Removal is a separate capability
areaRemoval: { radiusCells } declares a maximum from 0 to 3. A reaction may request removeArea within that maximum. The host anchors the square at the source on its current floor.
The actor must be allowed to remove the source, and every candidate is checked separately. Entry protection, ownership and world rules still apply. State and permitted removals commit atomically. Authors cannot choose arbitrary coordinates, another floor, or item IDs.
Use permission: 'remover' when invoking the action itself requires source-removal rights. This is the composition used by the built-in Bomb.
Local tests
Use ObjectRegistry.execute to get both the new instance and reaction. act returns only the new instance. Supplying permission in a test fixture simulates authority; it does not authenticate a player.
See reaction declarations and the host/test runtime.
