Skip to content
Work in progress. These docs describe Spawnite at launch, and some parts are still being built.

Scene

<Scene name component> inside Game registers a scene by name, and Game’s start names the first one. useScenes().go(name) switches, and useScenes().reload() starts the active scene again from the beginning. Code outside a component, such as a store’s action, calls the same functions on what useScenes() returned to the component that calls it. In a room, a system starts the room’s scene again with reloadScene(step) from @spawnite/engine/core: once the step ends, every entity the scene spawned spawns anew on the room and on every page, and the players keep their characters. It returns false, and changes nothing, in a game played alone, which starts its scene again with useScenes().reload() from a component, and on a room whose scene is a spawn function rather than a component. Each Game keeps its own scenes, so two Games on one page never draw each other’s. Only the active scene is mounted, so leaving one unmounts its world and everything in it. An entity that holds something beyond the frame, a GPU asset or a subscription, tracks it on itself with trackResource; destroying the entity runs what it tracked, so a switch leaves nothing behind.

sequenceDiagram
    participant UI as scene UI
    participant Game
    participant Lobby as Scene lobby
    participant Run as Scene run
    UI->>Game: useScenes().go("run")
    Game->>Lobby: unmount
    Note over Lobby: world, entities and scene UI go with it
    Game->>Run: mount
    Note over Run: world loads, entities spawn

A scene renders a World and any UI that belongs to that scene alone. UI inside a Scene reads the scene’s state and lives as long as the scene is active.

UI that every scene shows can sit inside Game, beside the scenes, where it lives as long as the game, as the example game’s wallet readout does. UI that only some scenes show is a component in the game’s folder, included in each scene that needs it.

The example game’s lobby, which its test/scenes/Lobby.test.tsx mounts:

games/example/src/scenes/Lobby.tsx
import {
Button,
Camera,
CameraPreset,
Hud,
Panel,
PanelVariant,
Slot,
useScenes,
World,
} from "@spawnite/engine";
import { noon } from "@spawnite/engine/looks/noon";
import "../items";
import { Robot } from "../components/Robot";
// A room and `spawnite simulate` load this file alone, so it exports the
// game's plugins and its save.
export { plugins } from "../game";
export { save } from "../save";
/** Metres the lobby's camera opens behind the robot. */
const lobbyCameraDistance = 4;
/** Degrees the lobby's camera opens looking down. */
const lobbyCameraPitch = 10;
/** The visor robot standing on the engine's plain grid under the noon
* look, a camera behind it, and the buttons to the run and the platforms. The
* grid loads no texture and no model, so the first screen opens fast. */
export function Lobby() {
const scenes = useScenes();
return (
<World map="grid" look={noon}>
<Robot />
{/* Behind the robot and low, so the whole floor and the sky
show; the left button's drag orbits it, and no
click-to-walk. */}
<Camera
preset={CameraPreset.Classic}
distance={lobbyCameraDistance}
pitch={lobbyCameraPitch}
clickToWalk={false}
/>
<Hud>
<Panel slot={Slot.Bottom} variant={PanelVariant.Bare}>
<Button onPress={() => scenes.go("run")}>Play</Button>
<Button onPress={() => scenes.go("platforms")}>
Platforms
</Button>
</Panel>
</Hud>
</World>
);
}

The Play and Platforms buttons are scene UI: they unmount with the lobby when the run starts. The scene’s file also exports the game’s plugins and save, because a room and spawnite simulate load that file alone.

<Scene> itself only registers a component under a name and keeps no state. The scene’s component may keep state as any React component does, and that state, like its world, goes when the scene unmounts.