Scene Internals¶
Purpose¶
This page explains how scenes are registered, discovered, stacked, ticked, and rendered internally.
Registration and discovery¶
Registration decorator:
packages/mini-arcade-core/src/mini_arcade_core/scenes/autoreg.py
Usage:
from mini_arcade_core.scenes.autoreg import register_scene
@register_scene("minimal_scene")
class MinimalScene(...):
...
Discovery:
packages/mini-arcade-core/src/mini_arcade_core/scenes/registry.pySceneRegistry.discover(*packages)imports all modules in each packageimported modules execute decorators and populate autoreg catalog
If a scene id is missing at runtime, it is usually a discovery/import issue.
Scene stack and policies¶
Stack manager:
packages/mini-arcade-core/src/mini_arcade_core/engine/scenes/scene_manager.py
Policy model:
packages/mini-arcade-core/src/mini_arcade_core/engine/scenes/models.py
ScenePolicy fields:
blocks_updateblocks_inputis_opaquereceives_input
This controls pause overlays, modal menus, and render visibility.
Overlay policy deep dive:
docs/source/concepts/overlay_policies.mddocs/source/tutorials/scene/pause_overlay_policy.md
Built-in debug overlay internals¶
Engine files involved:
packages/mini-arcade-core/src/mini_arcade_core/engine/loop/hooks.pypackages/mini-arcade-core/src/mini_arcade_core/engine/commands.pypackages/mini-arcade-core/src/mini_arcade_core/scenes/debug_overlay.py
Flow:
DefaultGameHooks.on_events(...)mapsKEYDOWN(F1)toToggleDebugOverlayCommand.EngineRunner._execute_commands(...)executes queued commands each frame.ToggleDebugOverlayCommandtoggles scene iddebug_overlay:remove if already present
otherwise push as overlay with policy:
blocks_update=Falseblocks_input=Falseis_opaque=Falsereceives_input=False
DebugOverlayScene.tick(...)renders telemetry and stack lines.
Important implications:
overlay visibility is scene-stack based, not a hardcoded renderer mode
gameplay scene keeps ticking while debug overlay is visible
input remains owned by underlying scene because overlay does not receive input
discovery must include
mini_arcade_core.scenes, otherwise the toggle command cannot instantiatedebug_overlay
Tutorial reference:
docs/source/tutorials/scene/debug_overlay_builtin.md
Scene transition semantics¶
The most important stack mutations are:
change(scene_id): full stack replacement (clean()+push())push(scene_id, as_overlay=...): keep current stack and append one scenepop()/remove_scene(scene_id): unwind temporary scenes
Detailed transition behavior and when to use each command:
docs/source/concepts/scene_transitions.mddocs/source/tutorials/scene/change_scene.md
Scene lifecycle¶
Base class:
packages/mini-arcade-core/src/mini_arcade_core/scenes/sim_scene.py
Lifecycle methods:
__init__(RuntimeContext)on_enter()tick(input_frame, dt) -> RenderPacketon_exit()
Typical patterns:
minimal scene: override
tick(...)directly and returnRenderPacketgameplay scene: set
tick_context_typeinitializeworldinon_enter()register systems in pipeline
Current gameplay-scene structure in the reference games:
scene.py: scene registration plus high-level orchestrationbootstrap.py: asset resolution, template loading, and world constructionpipeline.py: ordered system/bundle list buildersspawn.py: typed spawn specs and spawn policiessystems/: atomic processors and feature bundles
Tick context and system pipeline¶
Core types (same module):
BaseWorldBaseIntentBaseTickContextSystemPipelineEntityIdDomain
Gameplay scene shell:
packages/mini-arcade-core/src/mini_arcade_core/scenes/game_scene.pyGameSceneSystemsConfigdeclaratively installs common gameplay systems for:action-to-intent input
pause intent handling
one-shot intent-to-command bindings
extra scene-specific systems
render system wiring
Terminology:
a system is one phase-ordered processor with a single
step(ctx)joba system bundle is just a composition helper that expands into multiple systems before pipeline ordering
Use bundles when a gameplay feature is made from several atomic processors
(input-to-velocity, motion integration, viewport constraints), instead of
packing those concerns into one large step(...) method.
For discrete grid games, prefer the built-in grid toolkit instead of re-implementing timing and free-cell queries in each scene:
CadenceSystemfor logical movement ticksGridBounds/GridLayoutfor grid-space ownership and renderingGridCellSpawnSystemfor cell-based item spawning
For falling-block scenes, prefer the dedicated board helpers instead of embedding board collapse and piece layout logic inside scene classes:
BlockBoardfor settled-cell stateFallingBlockPieceSpec/FallingBlockPiecefor active piecesBoardRowClearSystemfor filled-row collapseBagRandomizerfor deterministic piece bags
For brick-breaker scenes, prefer the reusable bounce/brick helpers instead of repeating ball-vs-paddle and ball-vs-brick logic in each game:
ViewportBounceSystemfor wall reflectionBounceCollisionSystemfor ball-vs-rect reflectionPaddleBouncePolicyfor paddle contact shapingBrickFieldCollisionSystemfor brick damage and removal
For maze arcade scenes, prefer the dedicated maze helpers instead of embedding turn buffering, tunnel wrap, and pellet collection inside one large rules system:
TileMapfor maze cellsGridNavigationSystemfor lane movement and pending turnsTunnelWrapSystemfor side tunnelsCollectibleCollisionSystemfor pellet/power pickupModeTimerSystemfor timed behavior phases
For bomb-and-arena scenes, prefer the dedicated bomb helpers instead of embedding placement limits, fuse countdowns, and blast propagation in a single rules system:
ArenaTileandarena_tile_map_from_strings(...)for arena dataBombPlacementSystemfor placement and active-bomb limitsBombFuseSystemfor timed detonationChainReactionSystemfor early trigger cascadesDestructibleTileSystemandHazardCollisionSystemfor blast effectsExplosionLifetimeSystemfor cleanup of active flame cells
Builder pattern used by the reference games:
world construction usually lives in a local
build_<scene>_world(...)helper inbootstrap.pygameplay system registration usually lives in a local
build_<scene>_systems(...)helper inpipeline.pyscene
on_enter()should mostly compose those helpers rather than inline entity creation and long system lists
World query model:
gameplay code should prefer semantic helpers like
world.ship()orworld.aliens()those helpers are usually backed by
BaseWorld.find_entity(...),get_entities_by_tag(...), and scene-specific convenience methodsnamed
entity_id_domainsexist for constrained spawn allocation and tracked cleanup, not as the primary gameplay query API
Each frame:
scene builds typed tick context
pipeline runs systems in order
one render system must assign
ctx.packetscene returns
ctx.packet
If no render packet is produced, engine raises runtime error.
Frame loop interaction¶
Main loop:
packages/mini-arcade-core/src/mini_arcade_core/engine/loop/runner.py
Per frame (simplified):
poll backend events
build
InputFramepick input-focused scene from stack
tick update scenes based on scene policy
process cheats and command queue
collect visible scene packets
run render pipeline
Window/viewport details used by scenes and render passes:
docs/source/concepts/window_viewports.mddocs/source/concepts/input_coordinate_mapping.md
Render paths in scenes¶
Two common patterns:
Direct
RenderPacketops in scenetick(good for minimal examples)Queued render systems with
RenderQueue+DrawCall+Drawableclasses (good for complex games)Declarative queued rendering via
ConfiguredQueuedRenderSystem,RenderOverlay, andEntityRenderRule(preferred for medium/large games)
Reference implementations:
minimal direct packet:
examples/catalog/scene/minimal_scene/scenes/scene.pydeclarative queued render + draw ops:
games/deja-bounce/src/deja_bounce/scenes/pong/systems/render.pygames/deja-bounce/src/deja_bounce/scenes/pong/draw_ops.pygames/asteroids/src/asteroids/scenes/asteroids/systems/render.pygames/space-invaders/src/space_invaders/scenes/space_invaders/systems/render.py
Common scene failures¶
scene not found: discovery package missing or scene module not imported
no render output: render system never set
ctx.packetunexpected input routing: overlay policy blocks input/update
overlay render confusion: opaque policy hides lower scenes