Skip to content

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. 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.

Shared UI is a component in the game’s folder, included in every scene that needs it, not lifted to Game.

src/scenes/Lobby.tsx
import {
World,
Entity,
Camera,
Hud,
Panel,
Slot,
Button,
useScenes,
} from "@daniel-zarinski/engine";
export function Lobby() {
const scenes = useScenes();
return (
<World map="hilltop">
<Entity model="sled" />
<Camera follow={null} />
<Hud>
<Panel slot={Slot.Bottom}>
<Button onPress={() => scenes.go("run")}>Play</Button>
</Panel>
</Hud>
</World>
);
}

The Play button is scene UI: it unmounts with the lobby when the run starts.

A scene holds no state of its own.