Scene Management
YAGE uses a scene stack to manage game states. This page covers common patterns for pause menus, time control, transitions, and cross-scene communication.
For the foundational API, see Scenes.
Scene Stack Recap
Section titled “Scene Stack Recap”The SceneManager maintains a stack of active scenes:
engine.scenes.push(new GameScene()); // add on topengine.scenes.pop(); // remove top sceneengine.scenes.replace(new MenuScene()); // swap top sceneOnly the topmost scene receives input and updates by default. Scenes below continue rendering unless occluded.
Pause Menu Pattern
Section titled “Pause Menu Pattern”The most common pattern is a pause overlay that freezes the game scene below:
class PauseScene extends Scene { readonly name = "pause-menu"; override readonly pauseBelow = true; // freeze scene below override readonly transparentBelow = true; // keep rendering scene below
onEnter(): void { const entity = this.spawn("pause-ui"); const panel = entity.add(new UIPanel({ anchor: Anchor.Center, direction: "column", gap: 12, padding: 32, background: { color: 0x000000, alpha: 0.8, radius: 12 }, }));
panel.text("PAUSED", { fontSize: 28, fill: 0xffffff });
panel.button("Resume", { width: 200, height: 40, onClick: () => engine.scenes.pop(), }); }}Push the pause scene from the game scene:
class GameController extends Component { update(): void { if (this.input.isJustPressed("pause")) { engine.scenes.push(new PauseScene()); } }}Key properties:
pauseBelow = true— the game scene’supdate()andfixedUpdate()stop running. Physics freezes. Entities stop moving.transparentBelow = true— the game scene still renders behind the pause menu, so the player sees the frozen game state.
Time Scale
Section titled “Time Scale”Each scene has a timeScale property that scales the delta time passed to
update() and fixedUpdate():
scene.timeScale = 0.25; // quarter speed (slow-mo)scene.timeScale = 1; // normal speedscene.timeScale = 2; // double speedUse it for slow-motion effects, speed-up power-ups, or post-goal replays.
Time scale affects the scene’s physics, processes, and tweens — everything that
reads dt from the game loop.
// Toggle slow-moif (keys.has("1")) scene.timeScale = 0.25;if (keys.has("2")) scene.timeScale = 1;if (keys.has("3")) scene.timeScale = 2;HUD Across Pause
Section titled “HUD Across Pause”If your HUD lives in the game scene, it continues rendering while paused
(rendering is not affected by pauseBelow). However, HUD updater components
will stop receiving update() calls.
To update HUD text when pausing, modify it directly from the pause scene:
class PauseScene extends Scene { onEnter(): void { const game = engine.scenes.all.find(s => s.name === "game") as GameScene; game.statusText.setText("PAUSED"); }
onExit(): void { const game = engine.scenes.all.find(s => s.name === "game") as GameScene; game.statusText.setText("Running"); }}Scene Transitions
Section titled “Scene Transitions”Level Progression
Section titled “Level Progression”Use replace to swap the current scene for the next level:
// Transition to next level (old scene is destroyed)engine.scenes.replace(new Level2Scene());Dialog / Overlay
Section titled “Dialog / Overlay”Use push for overlays that should dismiss back to the previous scene:
// Show inventory overlayengine.scenes.push(new InventoryScene());
// Dismiss it (returns to game)engine.scenes.pop();Full Navigation Reset
Section titled “Full Navigation Reset”Replace all scenes to return to the main menu:
// Pop everything and push the menuwhile (engine.scenes.all.length > 0) { engine.scenes.pop();}engine.scenes.push(new MainMenuScene());Cross-Scene Communication
Section titled “Cross-Scene Communication”Access other scenes on the stack via engine.scenes.all:
const gameScene = engine.scenes.all.find( (s) => s.name === "game") as GameScene | undefined;
if (gameScene) { gameScene.timeScale = 0.25;}For loose coupling, use the engine-level EventBus instead of direct
references:
import { EventBusKey, defineEvent } from "@yagejs/core";
const GamePaused = defineEvent("game:paused");
// Emit from pause scenethis.context.resolve(EventBusKey).emit(GamePaused);
// Listen from game scenethis.context.resolve(EventBusKey).on(GamePaused, () => { this.statusText.setText("PAUSED");});