# scene-stack-demo-mode-coordination > 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: Jason Cochran - Repository: strataga/claude-setup - Version: 20260124101132 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/strataga/claude-setup - Web: https://mule.run/skillshub/@@strataga/claude-setup~scene-stack-demo-mode-coordination:20260124101132 --- --- 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-24 --- # 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: 1. Maintains the current phase/step 2. Pushes child scenes one at a time 3. 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):** ```rust 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; // Wait for rendering to settle, then push current phase's scene 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) { // Called when pushed scene pops - advance to next phase self.phase = self.phase.next(); self.frames_in_phase = 0; self.transition_requested = false; } } ``` **Child Scene (CORRECT - pops back):** ```rust impl Scene for ChildScene { fn update(&mut self, ctx: &mut SceneContext) -> SceneTransition { // Demo mode: auto-exit after delay 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; // ← CORRECT: Returns to orchestrator } } // ... normal logic ... } } ``` **Child Scene (WRONG - causes infinite loop):** ```rust 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 { // WRONG: Bypasses orchestrator, creates unbounded stack 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 1. Log shows each scene's `on_resume` being called on the orchestrator 2. Scene stack depth stays bounded (typically max 2: orchestrator + child) 3. All phases/scenes are visited in order 4. Demo completes and either exits or loops to beginning ## Example From the rpg-game project, the fix was changing: ```rust // BEFORE (wrong): MainMenuScene pushing directly if self.demo_mode && self.demo_timer > 2.0 { return SceneTransition::Push(Box::new(WorldMapScene::new())); } // AFTER (correct): MainMenuScene popping to DemoScene 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