Imported from To0nsa/rpg-runner (
lib/ui/AGENTS.md). Install upstream withnpx skills add To0nsa/rpg-runner --skill ui. Copyright stays with the author.
AGENTS.md - UI Layer
Instructions for AI coding agents working in lib/ui/.
UI Layer Responsibility
lib/ui/ is now a full Flutter app layer, not just overlays. It owns:
- the app shell and route graph
- bootstrap, auth warmup, resume handling, and profile onboarding
- hub/setup/meta/town/profile/leaderboard pages
- HUD, controls, and game-over presentation
- theme extensions and shared UI components
- app state, Firebase client adapters, and local orchestration around backend data
- run-session creation, replay submission, board/leaderboard loading, and ghost manifest/cache orchestration
- viewport integration, scoped orientation/system UI helpers, and haptics
Widgets should stay focused on presentation and orchestration, not backend or gameplay internals.
Current Important Areas
lib/ui/app/:UiApp, routes, navigation shelllib/ui/bootstrap/: startup loader, brand splash, profile-name setuplib/ui/pages/: hub, level/setup, town, options, messages, profile, leaderboardslib/ui/hud/andlib/ui/controls/: in-run overlays and input widgetslib/ui/components/,lib/ui/text/,lib/ui/icons/,lib/ui/theme/: shared design system pieceslib/ui/state/:AppState, auth/profile/ownership/run/board APIs, Firebase-backed implementations, and app-state controllerslib/ui/state/run/: run-session API, replay-submission spool/coordinator, and submission status valueslib/ui/state/boards/: active-board, leaderboard, ghost manifest, and ghost replay cache clientslib/ui/assets/: preview cache and warmup lifecyclelib/ui/viewport/andlib/ui/scoped/: viewport fitting and scoped system UI/orientation behavior
House Style
Accepted account deletion resets memory before device cleanup or sign-out. Keep server acceptance separate from local cleanup errors, fence late state writes, and retry cleanup without reauthentication. Unknown deletion responses must never count as acceptance.
Default to the existing UI patterns:
- use
ThemeExtension-driven component themes - expose semantic widget inputs such as
variant,size, ids, callbacks, and selected state - avoid style-knob APIs unless the user explicitly asks for them
- keep widgets small by resolving theme specs up front instead of scattering visual calculations in
build - keep page-local widgets near the page that owns them, but move any widget reused across flows into
lib/ui/components/
When cleaning up UI code, prefer a full migration to the active component/theme pattern over leaving half-old, half-new APIs in place.
Modern Flutter Rules
- use
WidgetStateandWidgetStateProperty, not deprecatedMaterialState* - use
Color.withValues(alpha: ...), notwithOpacity - avoid side effects in
build - keep
SystemChromeusage in app-shell or scoped helper code, not leaf widgets
This repo already centralizes global immersive-mode behavior in UiApp and route-scoped behavior in scoped/. Reuse that.
App State And Backend Access
AppState is the main orchestration boundary for authenticated app state. Current responsibilities include:
- auth session bootstrap
- loading remote profile data
- loading and mutating remote ownership canonical state
- preparing run-start descriptors from selected level/character/loadout after auth + ownership preflight
- creating remote run sessions and consuming server-issued run tickets
- submitting completed run replays for asynchronous validation
- loading active boards, leaderboards, ranks, and ghost manifests
- awarding run gold back into remote progression through validated run flows
- handling account deletion reset flow
Rules:
- widgets should call
AppStateor a narrow UI-facing abstraction, not Firebase SDKs directly - keep backend contract handling in
lib/ui/state/** - when a callable/backend contract changes, update both the client adapter and the consuming UI/state flow
- when a run/replay/leaderboard payload changes, also check
packages/run_protocol/**,functions/src/**, andservices/replay_validator/**
Run Route Responsibilities
The run route is a UI-owned assembly of lower layers:
RunnerGameWidgetcreates and owns the controller, Flame game, aim preview state, and overlay wiringRunnerGameRoutescopes orientation and system UI behavior for embedded or routed runs- HUD and controls read snapshots and send input through the existing router/controller path
Do not push menu or backend concerns down into lib/game/. Do not bypass the run widget and assemble ad-hoc game routes in random pages.
UI State Versus Gameplay State
Keep the separation clean:
- gameplay truth comes from Core snapshots and events
- app/meta state lives in
AppStateand its value objects - ephemeral widget state stays local to the widget subtree when possible
Avoid duplicating gameplay state in UI-only models just to make rendering easier.
Asset, Preview, And Warmup Rules
The UI layer already manages preview and warmup behavior:
- hub selection warmup in
UiApp - run cache purging after leaving a run
- preview asset lifecycle in
lib/ui/assets/
If a page or widget needs art previews, integrate with the existing asset lifecycle instead of adding one-off preload code.
What Belongs In This Layer
Good fits for lib/ui/:
- route changes
- page flow and onboarding logic
- component/theme cleanup
- HUD layout and controls
- backend-client integration through
AppStateand state APIs - local and remote leaderboard presentation, ghost loading, and profile/account flows
Bad fits for lib/ui/:
- authoritative gameplay rules
- Flame-only rendering concerns
- direct Firestore or Cloud Functions usage from widget trees
- system-wide side effects fired from
build
Testing Expectations
UI changes should be verified with the right slice:
- widget tests for components, pages, overlays, and route behavior
- state tests for
AppStateand UI-facing APIs where relevant - integration tests when the change spans app shell, run route, and backend/state interactions
Documentation Responsibilities
If you change UI architecture or public usage, update:
- this file for UI-layer rules
lib/AGENTS.mdfor app-wide boundariesREADME.mdor public API docs when embedding or setup behavior changes
For app-level architecture, see lib/AGENTS.md. For the backend contract side of profile/ownership/account flows, see functions/AGENTS.md.