Composite events
Why you’d want this
Section titled “Why you’d want this”Some of the best chaos comes from surprise. Instead of a viewer paying for a known effect, they pay to spin a wheel, and nobody, not even the streamer, knows which of several outcomes they’ll get until it lands. A horde of monsters? Low gravity? Every monster turned fast? Items raining from the sky?
A composite event is exactly that: one Reward whose redeem resolves to one of several of your existing events, chosen by a trusted weighted roll on the bridge, with a built-in reveal animation. You don’t write any new effect code: the winning event runs through the normal pipeline like any other. You just mark an event as composite and (optionally) curate which events are choosable. The broadcaster composes the actual wheel (which events, what parameters, what odds) in the Dashboard.
It is the platform’s generic “mystery box” primitive. One pack might flip a card, another might roll a random hazard, a shooter spins a wheel of mayhem: same mechanism, your presentation.
Declaring a composite event
Section titled “Declaring a composite event”A composite event is declared like any other event, with two additions:
kind = "composite" and an optional members whitelist.
[events.mystery_box]title = "Mystery Box"summary = "Roll the wheel to resolve one of several configured events."queue = "effects"kind = "composite"members = [ "spawn_horde", "fast_monsters", "gravity", "add_bot",]kind = "composite"marks the event. (The default,"standard", is an ordinary event.)membersis an optional curation list: the events a broadcaster is allowed to put on this wheel. Omit it to allow any declared event. Listing an unknown event, or puttingmemberson a non-composite event, is a manifest error.
Every member must be a standard event you’ve already declared, and it must
not declare Viewer Input. Composite faces are always filled by the
broadcaster, so a member event can’t ask the viewer for free text (an event that
declares Viewer Input is rejected as a member). Composites can’t contain
composites (no recursion). The kind marker and the members
list are part of the manifest hash, so changing
them re-pins the Pack.
Who configures what
Section titled “Who configures what”The split is deliberate:
| You (the Pack author) | The broadcaster (in the Dashboard) |
|---|---|
| Declare the composite event + the member events | Composes the wheel: which members, with what params and weight |
Optionally curate the choosable set (members) | Sets the reveal duration (revealMs) |
The broadcaster’s wheel lives on the Reward as a set of faces:
{ "revealMs": 3000, "faces": [ { "member": "spawn_horde", "params": { "count": 6 }, "weight": 3 }, { "member": "fast_monsters", "params": { "seconds": 30 }, "weight": 1 }] }This is validated when the Reward is saved: each face’s member must be a
declared, non-composite event (and in your members whitelist if you set one),
and its params must satisfy that member’s
params_schema. A face pointing at a disabled event
is rejected at config time.
What happens on a redeem
Section titled “What happens on a redeem”- The bridge rolls a winning face in its trusted process, weighted, uniform by default. Selection is bridge-side and authoritative, so a paid outcome is auditable and defensible under a refund dispute.
- It holds for
revealMswhile the overlay animates the reel toward the already-decided result (see Reveal). - The winning member is dispatched as a fresh invocation on its own queue:
same
ready_after, sameack/applied/done, same telemetry as if it had been redeemed directly. It is front-inserted so the rolled effect lands promptly.
Your Adapter never sees “mystery_box”. It sees the winning member event
(spawn_horde, fast_monsters, …) and handles it exactly as it already does.
No new Adapter code.
Rendering the reveal
Section titled “Rendering the reveal”The roll result is published to the read-only target_reveal pack-state key,
which a single pack-agnostic overlay renders. You get the spinning reel for free;
to style or replace it, see Reveal
and Overlays.
See also
Section titled “See also”- Reveal: the primitive behind the reel; also rolls over live game state.
- Defining Events: declaring the member events.
- Manifest reference: where
kindandmemberssit in the TOML tree.