scene/minimal_scene¶
Goal¶
Understand the smallest useful SimScene implementation that still demonstrates:
scene registration and discovery
frame-by-frame
tick(input_frame, dt)executionbackend-agnostic rendering via
RenderPacketruntime telemetry (backend name, frame, dt, viewport)
Why this tutorial exists¶
This is the base scene pattern used before introducing:
action maps and intent systems
world/entity simulation
queued render systems and draw ops
commands and overlays
If this scene is clear, advanced scene architecture is easier to reason about.
Source map¶
Settings profile:
examples/settings/scene/minimal_scene.ymlExample builder:
examples/catalog/scene/minimal_scene/main.pyRuntime scene:
examples/catalog/scene/minimal_scene/scenes/scene.pyShared runner:
examples/_shared/runner.py
Scene lifecycle walkthrough¶
MinimalScene does this:
@register_scene("minimal_scene")registers scene id in auto registry.__init__(ctx)initializes local runtime state:_elapsed_frames_last_backend_name
tick(input_frame, dt):increments time/frame counters
reads runtime config (
self.context.config)reads viewport telemetry (
window.get_viewport())computes animation position (
sinpulse)returns
RenderPacket.from_ops([draw])
draw(backend)callback:records concrete backend class name
draws panel + animated rectangle + text diagnostics
This is intentionally one-file, one-scene, no systems.
Code excerpt¶
Key parts from
examples/catalog/scene/minimal_scene/scenes/scene.py:
SCENE_ID = "minimal_scene"
@register_scene(SCENE_ID)
class MinimalScene(SimScene):
def __init__(self, ctx: RuntimeContext):
super().__init__(ctx)
self._elapsed = 0.0
self._frames = 0
def tick(self, input_frame: InputFrame, dt: float) -> RenderPacket:
self._elapsed += dt
self._frames += 1
vp = self.context.services.window.get_viewport()
def draw(backend: Backend):
backend.render.draw_rect(24, 24, 640, 390, color=(0, 0, 0, 220))
backend.text.draw(
40, 36, f"frame={self._frames} viewport={vp.window_w}x{vp.window_h}"
)
return RenderPacket.from_ops([draw])
Why this is important:
@register_scene(...)is how scene IDs become discoverable.tick(...)is the per-frame simulation/render hook.self.context.services.*is the runtime service access surface.RenderPacketis the unit consumed by the render pipeline.
Config behavior¶
From main.py, this example supports:
--backend--fps--virtual-width,--virtual-height--window-width,--window-height--enable-profiler--postfx-enabled,--postfx-active
Config precedence:
CLI passthrough overrides
examples/settings/scene/minimal_scene.ymlshared example defaults (
examples/settings/settings.yml)hardcoded fallback values in builder
Run¶
Default:
mini-arcade run --example scene/minimal_scene
Force pygame:
mini-arcade run --example scene/minimal_scene --pass-through --backend pygame
Force native:
mini-arcade run --example scene/minimal_scene --pass-through --backend native
Override timing/resolution:
mini-arcade run --example scene/minimal_scene --pass-through --fps 72 --virtual-width 960 --virtual-height 540
What to verify¶
On screen you should see:
backend: <class>changes between pygame/native runsframeincrements continuouslydtfluctuates near expected frame timefps targetreflects CLI overrideviewport values react to resize
Behavior checks:
animated rectangle moves smoothly (tick + dt are active)
F1toggles debug overlayESCexits cleanly
How this scales to real games¶
When moving from this minimal scene to gameplay scenes:
move local state into
models.pyworld dataclassreplace inline input handling with action-map intent systems
split rendering into
draw_ops.py+ render systemmove side effects into commands
Reference next levels:
built-in scene-stack telemetry overlay: debug_overlay_builtin.md
base menu scene pattern: menu_scene_base.md
config-first scene setup: ../config/engine_config_basics.md
full game architecture: ../create_game.md
scene internals deep dive: ../../concepts/scenes_internals.md
Common mistakes¶
Missing package discovery entry: scene is registered but never imported/discovered.
Forgetting
--pass-through: CLI override flags do not reach the example builder.Returning no
RenderPacket: scene runs but displays nothing.