raea/remote
A headless Bevy App you open, step and query from TypeScript, through Bevy's remote protocol.
BevyApp.open starts a headless Bevy App with the plugins you name and hands back an object that speaks Bevy's
remote protocol (BRP): spawn entities, insert and query components, set resources, trigger events and step frames.
TypeScript systems run inside its schedules. It's how a test or a raea run script drives the
engine without a composition.
import { BevyApp } from "raea/remote";
const app = BevyApp.open({ plugins: [] });
const e = app.spawn();
app.step(3);
console.log(app.methods.length, e);import { BevyApp } from "raea/remote"raea/remote exports 1 class, 1 type. Bevy's counterpart: bevy_remote. Source: sdk/raea/src/remote.ts.
Classes
BevyApp
A headless Bevy App driven from TypeScript through Bevy's remote protocol: open it with its plugins, then spawn, insert, query and step it, and add TypeScript systems to its schedules.
| Member | What it does |
|---|---|
BevyApp.open(o: OpenOptions): BevyApp | A headless App with these plugins; Startup has run, no frame has stepped. TypeScript plugins are built in order once the App is open, then finished and cleaned up; their Startup systems run before the first frame. |
BevyApp.stepTogether(apps: BevyApp[], frames?: number): number[] | Apps stepped together, a frame at a time: a network's peers. Returns each one's frame. |
.methods: string[] | the methods this App answers (BRP's, raea's and its plugins') |
.id: number | the App's handle in the engine |
.isPluginAdded(name: string): boolean | Whether a plugin of this name is in the App (Bevy's is_plugin_added), Rust or TypeScript. |
.addPlugins(...refs: PluginRef[]): BevyApp | Adds TypeScript plugins and groups (Bevy's add_plugins): each built in order, then each finished, then each cleaned up. A Rust plugin is compiled in and must be named when the App opens; naming a new one here throws. |
.addSystems(schedule: string, systems: ((app: BevyApp, frame: number) => void) | ((app: BevyApp, frame: number) => void)[], o?: SystemOptions): BevyApp | Systems in a schedule (Bevy's add_systems), each as system adds one; one of the startup schedules (PreStartup, Startup, PostStartup) runs them once, before the App's next frame. Returns the App, to chain. |
.insertResource<T>(r: Resource<T>, value: T): BevyApp | Bevy's insert_resource: the resource's value set (setResource). |
.addObserver<T>(e: string | Event<T>, o?: { entity?: number | undefined; then?: Then[] | undefined; }): Observing<T> | Bevy's add_observer: an observer of an event inside the App (observer). |
.step(frames?: number): number | frames frames on. Returns the frame it's on. With TypeScript systems (system), each frame is run schedule by schedule and they run in theirs. |
.system(schedule: string, run: (app: BevyApp, frame: number) => void, o?: SystemOptions): () => void | A system written in TypeScript: run is called every frame right after Bevy's own systems of schedule (one of the frame's: "First", "PreUpdate", "StateTransition", "RunFixedMainLoop", the fixed step's "FixedFirst", "FixedPreUpdate", "FixedUpdate", "FixedPostUpdate", "FixedLast" (one fixed step a frame: the clock's step is the timestep), "Update", "SpawnScene", "PostUpdate", "Last"), on that frame's World, before the next schedule's; it queries, changes and observes through the App's methods (query, get, insert, call("world.mutate_components"), observe...). Returns a function that removes it. o places it as Bevy's add_systems(...).run_if().before().after().in_set() would: when is its run condition (asked every frame before it runs; see conditions), before/after name other systems or sets of the same schedule it runs before or after (a cycle is refused), set puts it in a set that configureSet gives a condition and an order. Without an order, systems run in the order they were added. |
.configureSet(name: string, o: { when?: Condition | undefined; before?: string | string[] | undefined; after?: string | string[] | undefined; }): void | A set of TypeScript systems (Bevy's SystemSet with configure_sets): when is asked once per schedule run, before its first member, and a false skips them all; before/after order the whole set against systems or sets. |
.oneShot<R = void>(fn: (app: BevyApp, frame: number) => R): OneShot<R> | A one-shot system (Bevy's register_system + run_system): run() runs it now, on the World as it is; queue() runs it once the current TypeScript system returns (as Commands::run_system applies at the next sync point), or at the end of the frame if called outside a step. remove() unregisters it. |
.frameSchedules(): string[] | The schedules a frame runs, in order (Bevy's MainScheduleOrder). |
.call<A = unknown>(method: string, params?: unknown): A | Any method of the App's table, run now: its answer, or a throw with the method's message. |
.spawn(...components: With[]): number | A new entity with these components. |
.insert(entity: number, ...components: With[]): void | Adds these components to an entity, replacing any it has of the same type. |
.get<T>(entity: number, c: Component<T>): T | undefined | One component of an entity, or undefined when it hasn't got one. |
.query(o: { data?: Component<unknown>[] | undefined; has?: Component<unknown>[] | undefined; without?: Component<unknown>[] | undefined; }): { entity: number… | Entities with every component in has (and none in without), with the data components' values. |
.resource<T>(r: Resource<T>): T | A resource's value. |
.setResource<T>(r: Resource<T>, value: T): void | Sets a resource's value, adding it if the app hasn't got one. |
.trigger<T>(e: Event<T>, value: T): void | Triggers an event: its observers run now. |
.write<T>(m: Message<T>, value: T): void | Writes a message, for its readers' next run. |
.observe<T>(e: Event<T>, entity?: number | undefined): () => T[] | Starts observing an event (BRP's world.observe+watch). Each call of the returned function gives the events triggered since the last call, in order. entity limits it to events aimed at that entity. |
.hook(on: "Add" | "Insert" | "Discard" | "Remove" | "Despawn", component: string | Component<unknown>, then?: Then[]): Observing<unknown> | A component hook as an observer inside the App: when component is added, inserted, discarded, removed or its entity despawned, then's calls (BRP methods, "$entity" in their params standing for the entity) run right there, in the same flush, before anything else sees the World. seen() gives the entities it fired for since the last call; stop() removes it. |
.observer<T>(e: string | Event<T>, o?: { entity?: number | undefined; then?: Then[] | undefined; }): Observing<T> | An observer inside the App for a reflected event: on each trigger (or each aimed at entity), then's calls run in the same flush, "$event" standing for the event's value and "$entity" for its target. |
.state<T>(s: State<T>): T | null | A state's value (null before it exists). |
.setState<T>(s: State<T>, value: T): void | A state's next value: it changes at the next frame's StateTransition. |
.schema(crates?: string[] | undefined): Record<string, unknown> | The App's registered types as JSON schema (BRP's registry.schema), filtered by crate. |
.close(): void | Shuts the app down; its methods fail after. |
Types
OpenOptions
| Field | Type | What it is |
|---|---|---|
plugins (required) | PluginRef[] | the App's plugins, in order: Rust ones by the name this build registered them under (a declaration's name, or its halves: lightyear_server), compiled in and added before Startup; TypeScript ones (definePlugin) built after |
fps | number | frames a second: one step is 1/fps of Time (default 60) |
serve | number | serve BRP over HTTP on this port (a dev tool, a BRP client, curl) |