Events and player messages
Neutral event payload
type StudioEvent = {
type: string;
subject: string | null;
target: string | null;
time: number; // runtime seconds, finite
};StudioEventBus supplies subscribe(listener), emit(event), events snapshots, reset and dispose. Unsubscribe using the returned function. History is bounded to 256 events; queue/delivery to 128. Listener failures and reentrant cycles produce diagnostics. This is transient observation, not durable event sourcing or an authoring mutation API.
Produced and accepted events
| Name | Producer / consumer | Subject → target and lifecycle |
|---|---|---|
| qway.object.enter / qway.object.leave | Host/QWAY observation → director/experience filters | Object UUID → target UUID/null; explicit observed enter/leave, not synthetic teleport proof |
| qway.relation.changed | Host relation observation → directing filters | Object UUID → related target/null; does not rewrite authored relation |
| qway.interaction | Host interaction → experience/trigger filters | Acting object UUID → target/null |
| qway.trigger | Proximity/runtime or host → experience/trigger filters | Actor UUID → trigger target/null; once policy is explicit |
| wright.room.enter / wright.room.leave | World transition observer → experience | Actor UUID → room UUID, derived from resolved feet position after baseline |
| wright.portal.crossed | World transition observer → experience | Actor UUID → portal UUID; continuous crossing within aperture, not teleport |
| ridley.complete / ridley.stop | Cinematic director → experience/host | Cinematic completion/stop; adapter emits neutral subject/target and current time |
| ridley.play | Cinematic director → experience/host | Sequence started; director PlayerEvent also carries cinematic name |
| ridley.state.enter | ExperienceDirector → host/subscribers | State entry notification; inspect target state in actual payload |
| ridley.conversation.finished | ExperienceDirector → transitions | Conversation actor and state context; explicit end releases control |
| Custom emit event | Authored RIDLEY emit cue or explicit host → bus filters | Optional target; lower-case bounded event name, not executable code |
Commands sent to the player
CinematicDirector subscriptions receive PlayerEvent, which adds cinematic: string|null to the neutral event fields. The experience bridge emits the neutral form; read director state for the active sequence. ridley.state.enter has null subject and target state ID; ridley.conversation.finished has actor subject and null target.
| Message | Payload | Effect |
|---|---|---|
| ridley.play / ridley.goto | cinematic: sequence name | Start/go to an existing compiled cinematic, not seek to arbitrary source text |
| ridley.pause / ridley.resume | type only | Pause/resume cinematic clock |
| ridley.stop / qway.interactive | type only | Stop direction / return to interactive ownership |
| ridley.state.goto | state: compiled state ID | Experience state transition; distinct from cinematic goto |
| qway.object.enter / leave / relation.changed / interaction / trigger | subject UUID, target UUID|null | Deliver explicit host observation through the directing bridge |
WRIGHT events are emitted through the neutral event bus/experience emit API, not invented PlayerMessage variants. Unknown sequences/states or unavailable playback are errors. User control changes are state policy; there is no general “set any transform” player message.
Host subscription and dispatch
const stopListening = preview.experience.bus.subscribe(event => {
console.log(event.type, event.subject, event.target, event.time);
});
preview.dispatch({ type: "ridley.play", cinematic: "intro" });
preview.dispatch({ type: "ridley.pause" });
preview.dispatch({ type: "ridley.resume" });
// Teardown:
stopListening();
preview.dispose();Fragment: await preview.ready and verify preview.experience exists first. The complete downloadable host handles load/errors and lifecycle. Do not inject room-enter events to pretend a blocked actor navigated successfully.