| name | scene-stack-demo-mode-coordination |
| description | Fix infinite loops in demo/showcase modes for scene stack architectures. Use when:
(1) Demo mode gets stuck repeating the same scene, (2) scene cycling doesn't progress
through all scenes, (3) orchestrator scene's on_resume isn't being called, (4) pushed
scenes bypass the demo controller. Applies to game engines, UI frameworks, and any
stack-based state machine with automated testing or demo modes.
|
| author | Claude Code |
| version | 1.0.0 |
| date | "2026-01-24T00:00:00.000Z" |
Scene Stack Demo Mode Coordination
Problem
When implementing a demo/showcase mode that cycles through multiple scenes in a
stack-based scene manager, child scenes that directly push their successor (instead
of popping back to the orchestrator) cause infinite loops or scene repetition.
Context / Trigger Conditions
- Demo mode gets stuck on one scene, repeatedly showing/screenshotting it
- Orchestrator scene's
on_resume() never gets called
- Scene progression works manually but fails in automated demo mode
- Log shows scenes being pushed but orchestrator never advances
- Stack grows unboundedly:
Orchestrator → Scene1 → Scene2 → Scene3...
Solution
Architecture Pattern
Use a central orchestrator scene that:
- Maintains the current phase/step
- Pushes child scenes one at a time
- Advances to next phase in
on_resume() when child pops
Key Rule
Child scenes MUST pop in demo mode, never push the next scene directly.
Implementation
Orchestrator Scene (controls progression):
pub struct DemoScene {
phase: DemoPhase,
frames_in_phase: u32,
transition_requested: bool,
}
impl Scene for DemoScene {
fn update(&mut self, ctx: &mut SceneContext) -> SceneTransition {
self.frames_in_phase += 1;
if self.frames_in_phase >= 30 && !self.transition_requested {
self.transition_requested = true;
if let Some(scene) = self.create_scene_for_phase(self.phase) {
return SceneTransition::Push(scene);
}
}
SceneTransition::None
}
fn on_resume(&mut self, _world: &mut World) {
self.phase = self.phase.next();
self.frames_in_phase = 0;
self.transition_requested = false;
}
}
Child Scene (CORRECT - pops back):
impl Scene for ChildScene {
fn update(&mut self, ctx: &mut SceneContext) -> SceneTransition {
if self.demo_mode {
self.demo_timer += ctx.dt.as_secs();
if self.demo_timer > 2.0 {
log::info!("Demo mode: auto-exiting ChildScene");
return SceneTransition::Pop;
}
}
}
}
Child Scene (WRONG - causes infinite loop):
impl Scene for ChildScene {
fn update(&mut self, ctx: &mut SceneContext) -> SceneTransition {
if self.demo_mode {
self.demo_timer += ctx.dt.as_secs();
if self.demo_timer > 2.0 {
return SceneTransition::Push(Box::new(NextScene::new()));
}
}
}
}
Stack Visualization
Correct flow:
1. [DemoScene] pushes MainMenu
2. [DemoScene, MainMenu] - MainMenu shows, then pops
3. [DemoScene] on_resume called, advances to WorldMap phase
4. [DemoScene] pushes WorldMap
5. [DemoScene, WorldMap] - WorldMap shows, then pops
6. ... continues correctly ...
Incorrect flow (infinite loop):
1. [DemoScene] pushes MainMenu
2. [DemoScene, MainMenu] - MainMenu pushes WorldMap directly
3. [DemoScene, MainMenu, WorldMap] - WorldMap pushes Town
4. [DemoScene, MainMenu, WorldMap, Town] - Town pops
5. [DemoScene, MainMenu, WorldMap] - WorldMap pushes Town again!
6. ... infinite loop on Town ...
Verification
- Log shows each scene's
on_resume being called on the orchestrator
- Scene stack depth stays bounded (typically max 2: orchestrator + child)
- All phases/scenes are visited in order
- Demo completes and either exits or loops to beginning
Example
From the rpg-game project, the fix was changing:
if self.demo_mode && self.demo_timer > 2.0 {
return SceneTransition::Push(Box::new(WorldMapScene::new()));
}
if self.demo_mode && self.demo_timer > 2.0 {
return SceneTransition::Pop;
}
Notes
- This pattern applies to any pushdown automaton / stack-based state machine
- Also relevant for: game scene managers, wizard/multi-step forms, navigation stacks
- The same issue can occur in mobile app navigation (React Navigation, UIKit)
- For screenshot/testing modes, ensure sufficient delay before capturing (let animations settle)
- Consider adding phase/state logging to debug stack issues
Related Patterns
- State Machine with history
- Wizard/multi-step form controllers
- Mobile navigation coordinators
- Undo/redo stack managers