RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
Performance And Engine Refactor Plan

n

RapidGameFramework should stay fast, lightweight, and platform independent. The target is that a released game built on the framework can run smoothly on a five-year-old phone after normal content and art optimization.

This plan treats performance as framework work first. Game code should improve by adopting optimized shared systems instead of each game carrying its own special-case fixes.

Arcade Pong is the active released game and should be the first rollout target for performance-sensitive work. Post-release feedback is tracked in Arcade Pong Release Feedback and mapped into the sprint tasks below so release polish does not drift away from the optimization plan.

Current Status

The broad optimization/refactor sprint track is closed for the current release cycle. This page is retained as the implementation record, baseline reference, and future optimization backlog. Active release work now lives in Release Sprint Plan, and new engine work should be targeted to a measured problem or an active release checklist.

Optimization Principles

  • Measure before large rewrites. Add small profiling hooks and smoke checks before moving code.
  • Keep manager APIs stable while internals improve.
  • Prefer data-driven configuration, but cache parsed and normalized data for hot paths.
  • Avoid per-frame allocation, repeated JSON reads, repeated texture extraction, repeated theme/style construction, and repeated node creation.
  • Pool high-churn nodes and clear scene-local references when leaving screens.
  • Optimize for browser/mobile first, then desktop.
  • Keep fallback behavior visible and safe when assets are missing.

Baseline Targets

Use these targets as release-readiness goals. They can tighten later when the framework has more profiling data.

  • Frame pacing: 60 FPS on desktop/browser for simple demos; 30+ FPS on a five-year-old phone for active gameplay.
  • Startup: first playable menu within a few seconds after splash screens on web/mobile.
  • Memory: no unbounded growth after repeated scene changes, repeated achievements/settings popups, repeated Pong matches, or repeated tactical field runs.
  • Asset loading: game startup loads only shared assets plus active game assets; scene startup warms only required sprite/audio ids when possible.
  • CI: headless smoke stays green, and any new benchmark/profiling smoke is deterministic enough for CI.

Sprint 1: Baseline And Instrumentation

Goal: know where time and memory are going before refactoring.

Status: complete. Sprint 1 delivered performanceMonitor, a reusable opt-in monitor for timers, counters, gauges, frame samples, node counts, manager cache stats, callable timing, provider cache deltas, saveable summary dictionaries, scene instantiation loop benchmarks, and a compact debug overlay. The active scene-entry baseline list lives in data/performance/sprint1_baselines.json and is smoke-tested as informational coverage without threshold gating. Headless smoke writes a compact report to builds/performance/performance_baseline_report.json.

Tasks:

  • Add a lightweight performanceMonitor system for timers, counters, frame samples, cache sizes, node counts, and scene transition marks.
  • Add opt-in debug overlays or logs for local builds only.
  • Add smoke helpers that can exercise scene open/close loops and report cache growth.
  • Keep scene baseline profiles data-driven so games can be added or removed without changing the benchmark runner.
  • Write compact baseline JSON report artifacts from the normal smoke harness.
  • Capture current baselines for:
    • Main menu startup.
    • Arcade Pong match loop.
    • Reflecting Pool event choice loop.
    • Emoji Card Collector shop/inventory list rendering.
    • Project Alchemy field entry, movement, spell cast, and exit.
    • Platformer level load, movement, death, and level transition.

Acceptance:

  • Baseline metrics can be captured without changing gameplay behavior.
  • Smoke coverage verifies the baseline machinery across all current active game entry scenes.
  • Metrics identify the first three hot-path candidates for Sprint 2 and Sprint 3.
  • No benchmark failures block release builds until thresholds are agreed.

Initial hot-path candidates:

  1. Asset and sprite cache pipeline: spritesheet extraction, scaled texture generation, palette output, and per-scene warm/cache boundaries. This feeds directly into Sprint 2.
  2. Reusable UI and modal/list rendering: achievements, settings, inventory, game menus, and results popups have repeatedly shown layout churn and mobile sizing issues. This feeds directly into Sprint 3.
  3. Scene lifecycle cleanup: headless smoke passes but Godot reports persistent RID/resource/ObjectDB leaks at shutdown after loading many scenes. This should be investigated alongside scene transition and pooled-node cleanup before deeper gameplay optimization. Current cleanup work favors explicit controller/tool disposal over broad root-node teardown, because deferred UI callbacks can still reference application singletons after a scene smoke check has already finished.

Crash fix:

  • The native Godot 4.7 Windows headless crash was reproduced when report output was controlled through command-line script args or temporary environment variables. The stable fix is to avoid those triggers and write the compact report from the normal smoke path every run.

Sprint 2: Asset And Sprite Pipeline

Goal: make asset lookup predictable and cheap.

Status: started. spriteManager now separates decoded source-image caching from final texture, scaled texture, animation-frame, path-texture, and sheet-cell caches. This reduces repeated image decoding/get-image work during spritesheet cell extraction and path-based scaled UI lookups. Sprite manifests now support warm_profiles; Arcade Pong seeds a match profile and Project Alchemy seeds a field_slice profile for data-driven scene warmup. Scene transitions can now call clear_transient_cache() or trim_texture_cache() to drop generated scene/UI texture products while preserving decoded source images for the next warm profile. Arcade Pong, Card Game, Reflecting Pool, Platformer, and Project Alchemy now use targeted warm profiles at scene startup instead of warming every loaded sprite pack. spriteRenderManager now exposes draw diagnostics so dense custom playfields can report sprite hits, fallbacks, missing lookups, and rotated draws to performanceMonitor.

Tasks:

  • Audit spriteManager, spriteRenderManager, paletteManager, and renderNodePool cache behavior.
  • Separate source texture caches from scene-use caches.
  • Add per-game and per-scene cache warm lists from sprite manifests.
  • Add cache eviction/clear rules for leaving a game scene or editor tool. Initial sprite cache boundaries are complete; roll them into active scenes as each game is profiled.
  • Avoid regenerating scaled textures/materials every time a UI list redraws.
  • Verify spritesheet cell extraction and animation frame lookup are cached by stable keys.

Game rollout:

  • Arcade Pong: prewarm ball, paddle, powerup, scoreboard, and menu sprites. Initial match profile wiring is complete.
    • Planned release-feedback work: final power-up icons, final music/SFX assets, browser-safe music transition/preload behavior, and shader/material animation polish with low-power fallbacks.
  • Card Game: prewarm visible card frames/icons and lazy-load deeper collection pages. Initial visible_card_shell profile wiring is complete.
  • Project Alchemy: prewarm active field actors/effects/tiles by adventure or arena profile. Initial field_slice profile wiring is complete.
  • Reflecting Pool: prewarm resource icons and current event card image only. Initial hud_and_pool profile wiring is complete for resources and pool effects; event image warming should stay current-event scoped as that renderer is profiled.
  • Platformer: prewarm player, walker, core tiles, coin, and exit art. Initial level_core profile wiring is complete.

Acceptance:

  • Reopening a screen does not increase sprite/cache counts indefinitely.
  • High-frequency gameplay no longer performs texture loads or sheet extraction.

Sprint 3: UI Layout, Theme, And Menu Rendering

Goal: reduce allocation and layout churn from reusable UI.

Status: started. inventoryList now pools row buttons across renders, hides unused rows instead of freeing them, and exposes row reuse stats through get_stats()/get_cache_stats(). This is the first step toward larger list virtualization for card inventories, battle pickers, editor palettes, and future RPG/platformer inventories. layoutManager now caches reusable panel, button, and achievement-row StyleBoxFlat resources per theme/state so repeated theme application does not recreate identical style boxes. buttonRowPool now covers fixed action rows such as Arcade Pong power-up slots, future spell/action bars, HUD command rows, and editor toolbars without destroying/recreating buttons each refresh. Smoke coverage now captures layout style-cache and row-pool providers through performanceMonitor.capture_provider_stats(), so future baseline reports can include UI cache diagnostics.

Tasks:

  • Profile layoutManager, achievement screens, settings screens, inventory lists, and menu rendering.
  • Cache reusable StyleBox, font, and color-role outputs per active theme. StyleBox caching is started for panel, button, and achievement rows.
  • Add standard list virtualization or row pooling for large inventory, collection, achievement, and editor lists. Inventory row pooling is started; nested cell pooling and viewport virtualization remain future work.
  • Add fixed action-row pooling for small HUD/menu rows that refresh often. Initial buttonRowPool wiring is complete for Arcade Pong power-up slots.
  • Replace repeated full-tree rebuilds with targeted refreshes where useful.
  • Standardize modal sizing and scroll shells so large text/mobile layouts do not trigger repeated resize/rebuild loops.

Game rollout:

  • Card Game inventory/shop/fight lists use virtualized or pooled rows.
  • Arcade Pong difficulty/settings/results popups use shared modal sizing only.
  • Arcade Pong main menu gains a shared controller/game information page with controller, keyboard, how-to-play, and power-up description tabs navigable by RB/LB.
  • Arcade Pong achievements and stats views use shared scrollable modal/screen shells so mobile layouts do not exceed the viewport.
  • Arcade Pong match-complete/new-match flow stays on the shared result/modal controller so dismiss/back behavior cannot softlock.
  • Main menu and game submenus reuse shared navigation rows and icon caches.
  • Achievement screens use shared rows with predictable height and no overlap.

Acceptance:

  • Large card collections remain responsive on mobile/browser.
  • Theme changes apply once per tree and do not rebuild unrelated game state.

Sprint 4: Game Loop And Entity Systems

Goal: move repeated active-game update logic into reusable, allocation-light systems.

Tasks:

  • Audit _process and _draw usage in active scenes.
  • Move transient actors/projectiles/pickups toward entityManager, entityRenderer, projectileLifecycleManager, and runManager.
  • Ensure update loops mutate existing dictionaries/arrays carefully instead of rebuilding large collections every frame.
  • Centralize fixed-step simulation helpers where deterministic behavior matters.
  • Add clear ownership rules for scene-local state versus saveable manager state.

Game rollout:

  • Arcade Pong: balls, rockets, powerups, score effects, and AI decisions move toward entity/update helpers.
    • Done this pass: rocket projectile batch stepping and hit/out-of-bounds partitioning moved into arcadePhysicsManager.step_projectiles(...).
    • Release-feedback target: stretch the playfield vertically, reduce browser frame drops as ball speed rises, and keep swept collision reliable so fast balls do not tunnel through paddles during frame spikes.
  • Project Alchemy: projectiles, enemies, pickups, exits, and field status use entity/run helpers.
  • Platformer: enemies, pickups, hazards, exits, and checkpoints move toward reusable level/entity helpers.

Acceptance:

  • Active gameplay allocates little or no memory per frame in normal loops.
  • Scene transitions clean up pooled nodes and transient entities.

Sprint 5: Data Loading And Save State

Goal: prevent slow startup and repeated parsing as content grows.

Closeout status:

  • dataCacheManager provides a reusable runtime JSON cache for managers and scenes that repeatedly load stable data files. It now tracks cache hits and misses through get_cache_stats() so performanceMonitor can include JSON catalog reuse in provider snapshots.
  • Arcade Pong paddle color, ball skin, AI profile, power-up, game settings, and achievement definition catalogs now use the shared cache path instead of direct scene-local JSON parsing.
  • Arcade Pong score, match-end, power-up, rocket-hit, and rally stat updates now use batched statsManager.record_events(...) calls so each gameplay event evaluates achievements once instead of repeatedly after every counter write.
  • saveManager now exposes a reusable delayed save queue. Arcade Pong uses it for mid-match stat/cosmetic/settings changes, then flushes immediately at match completion, game-settings close, start-menu navigation, or scene exit.
  • Platformer Demo now loads its movement settings and level index through dataCacheManager, and smoke coverage validates both cached startup files.
  • Card Game and Project Alchemy now load achievement definition catalogs through dataCacheManager via statsManager.load_achievement_data(...).
  • Project Alchemy's scene-local _load_json(...) helper now routes through dataCacheManager, giving its remaining prototype/menu JSON reads the same cached path without rewriting the owning managers mid-sprint.
  • cardManager, packManager, alchemyManager, and combatCardFactory now expose data-based loader APIs. Card Game cards/packs and Project Alchemy elements/reactions/combat cards use cached data while retaining old file-based convenience loaders for tools and small scripts.
  • adventureManager and gridCombatManager now expose data-based loader APIs; Project Alchemy adventure definitions and enemy archetypes use cached startup data as well.
  • buildProfileManager.audit_single_game_profile(...) now exposes a reusable single-game packaging audit so CI/editor tooling can verify required shared roots, game roots, other-game excludes, and accidental cross-game data includes.
  • Headless smoke coverage protects the Arcade Pong single-game release profile so the active release package keeps its required Arcade Pong/shared assets and excludes unrelated game data.

Tasks:

  • Add normalized data registries for JSON loaded repeatedly across managers.
  • Cache validation results during runtime while preserving editor/CI strictness.
  • Split large game data into indexed packs where appropriate.
  • Audit save/load for unnecessary deep duplicates on hot paths.
  • Keep save migrations explicit and covered by fixture saves.

Game rollout:

  • Card Game card catalogs and pack/shop data load once per scene/session.
  • Project Alchemy reaction/codex/adventure data uses indexed lookup maps.
  • Arcade Pong match presets, ball/paddle cosmetic data, stats, achievement event data, power-up definitions, and AI profiles use cached normalized lookups instead of repeated JSON parsing.
  • Build profiles keep single-game exports from carrying irrelevant game data where Godot export filters allow it.

Closeout:

  • Closed for the current optimization pass. The four main game scenes no longer contain direct gameplay catalog FileAccess/JSON.parse reads in the audit; sprite pack loading remains owned by spriteManager.
  • Future content catalogs should prefer dataCacheManager plus manager-level load_*_data(...) APIs from the start.
  • Follow-up work moves to Sprint 6 rollout: apply delayed save queues to other games where hot-path writes are identified, add cache/export-plan checks to future individual release profiles, and keep adding data-based loaders for new multi-manager catalogs.

Acceptance:

  • Re-entering menus or games does not reread unchanged JSON unnecessarily.
  • Save/load remains dictionary-based and migration-safe.

Sprint 6: Cross-Game Optimization Rollout

Goal: apply the optimized framework paths consistently.

Handoff: see Framework Handoff for the current completed-cache rollout, validation status, known shutdown-warning caveat, and the recommended next pickup point.

Current status:

  • Started the rollout with build/export profile guardrails because they affect every playable build and directly influence package size.
  • buildProfileManager now exposes a batch audit for individual game profiles, and the CI profile validator mirrors those checks before export work begins.
  • platformer_demo was normalized to the same shared_roots plus game-specific include_roots shape used by the other individual profiles, avoiding broad res://scripts packaging.
  • Main menu achievement pages now use the shared achievementScreen page renderer, so title/filter/list/back layout follows the same reusable path as in-game achievement overlays instead of a scene-local hand-built variant.
  • Main menu platformer level-selection catalogs now use dataCacheManager, so launcher-level game catalogs follow the same cached JSON path as gameplay scenes instead of reopening/parsing level indexes directly.
  • Card Game inventory and fight-picker tables now use cardInventoryAdapter to prepare filtered, sorted, selected, stat-highlighted inventoryList rows. This removes scene-local card table rules and gives future card/deck games a reusable adapter instead of rebuilding list behavior per game.
  • Project Alchemy active field camera, centered playfield transforms, visible object range checks, and grid-line ranges now delegate to gridViewportManager. This keeps the six-tile reveal/half-cell context stable while making the same responsive grid camera available to future tactical, dungeon, and editor-backed games.
  • Platformer level rendering now uses levelManager cached semantic rects and visible tile-record slices. Larger side-scrolling/metroidvania levels can reuse the same camera-window query instead of rebuilding every tile record or scanning whole maps during draw/pickup loops.
  • Platformer exits and enemies now use shared levelManager object/world-rect culling helpers. Future large levels can keep off-camera objects out of draw work without each game inventing a separate visibility check.
  • Platformer level attempts now create a runManager state at level load, update run counters/collected coin totals during play, and complete/fail the run before result popups. This gives future platformers a shared place for level summaries without making the movement loop own result bookkeeping.
  • resultsScreenController.show_popup(...) now bundles result-popup creation, viewport fitting, theme/text application, and focus into one reusable call. Platformer retry/completion popups use this path so future level games avoid repeating popup sizing and focus boilerplate.
  • Reflecting Pool pool-effect spawning now resolves through the game sprite map and warmed spriteManager cache instead of falling back to raw per-effect load(...) calls.
  • Start Menu screen backgrounds now resolve through spriteManager.get_texture_for_path(...), so launcher art such as the Arcade Pong menu background uses the shared path texture cache instead of direct scene-local loads.
  • Splash screen logo art now uses the same cached path-texture entry point, so individual builds and the all-demos shell avoid direct logo loads during startup transitions.
  • Theme-driven panel/button/screen background images now resolve through the layout manager's shared spriteManager path cache rather than direct theme style loads.
  • Reusable resource_hud icons now resolve through a default spriteManager instance, so sprite_id and legacy icon_path resource art share the same scaled texture cache without scene-local load(...) fallbacks.
  • Reflecting Pool choice-effect indicators now rely on the scene spriteManager scaled texture cache only, removing the last direct icon_path load in that button render path.
  • gameSettingsPanel.load_definition(...), aiController.load_profiles(...), and arcadePowerupManager.load_definitions(...) now use dataCacheManager internally. Future games that use these convenience file loaders get cached JSON reads even before wiring their own scene-level data cache.
  • Card/deck convenience loaders now follow the same pattern: cardManager.load_cards(...), packManager.load_packs(...), combatCardFactory.load_catalog(...), and combatCardFactory.load_definitions(...) all route through dataCacheManager while preserving their data-based loader APIs.
  • Project Alchemy reusable loaders now join the cached path as well: alchemyManager.load_definitions(...), alchemyManager.load_reactions(...), gridCombatManager.load_archetypes(...), and adventureManager.load_adventure(...) reuse parsed JSON while keeping their parsed-data APIs available for scene-level caches and tests.
  • Core UI/gameplay loaders now follow the cached-data convention: menuManager.load_menu(...), inputManager.load_actions(...), and levelManager.load_level(...) reuse parsed JSON while preserving existing menu stack, input binding, and derived level-geometry cache behavior.
  • Palette, tutorial, and unlock loaders now use the same cached JSON path: paletteManager.load_palettes(...), tutorialManager.load_steps(...), and unlockManager.load_rules(...) keep stable catalog data cached while leaving recolored texture and progression-state caches separate.
  • Project Alchemy now uses the same delayed save queue pattern as Arcade Pong: normal _save_state() calls queue the latest state, _process() advances the pending timer, and scene exit flushes any pending write. This removes direct disk writes from grid-step gameplay while preserving the dictionary save contract and global achievement persistence on flush.
  • Card Game startup now lazy-builds the battle inventory table and battle card panels when the Battle screen first opens instead of during _ready(). This keeps the initial Shop entry lighter while preserving the reusable inventoryList battle picker path.
  • Card Game also defers the Set/Collection grid until the Collection screen is opened, avoiding startup allocation of every collection tile on the initial Shop entry.
  • Standard settings popup creation is now deferred until Settings is opened in migrated scenes. Reflecting Pool, Card Game, Arcade Pong, and Project Alchemy all use this on-demand shared modal path so startup avoids allocating settings UI that the player may never open.
  • The Reflecting Pool launcher/main scene now uses its targeted hud_and_pool sprite warm profile instead of warming every loaded UI, resource, event, and pool-effect sprite at startup. Event artwork remains lazy-loaded as events are drawn.
  • Arcade Pong now defers Stats and controller/game Info popups until those menu items are opened. The match screen still builds the required difficulty, result, and game-settings modals up front, while optional informational screens stay out of the initial playfield allocation.
  • Arcade Pong rocket projectiles now use arcadePhysicsManager.step_projectiles(...) for batch movement, target-hit partitioning, and out-of-bounds cleanup. The scene keeps only the game-specific stun/SFX/stat response.
  • Arcade Pong multiball movement and scoring now use arcadePhysicsManager.step_ball_group(...) and collect_ball_group_scoring(...), moving primary/extra ball promotion out of the scene and into reusable arcade framework code.
  • Card Game stats now reuse the shared statsPanel popup instance and refresh its rows when reopened instead of freeing and rebuilding the same modal tree.
  • Project Alchemy now defers defeat, victory/reward, and adventure transition popups until those run states are reached, keeping normal field/lab entry focused on active gameplay UI.
  • achievementScreen now supports in-place popup refreshes. Reflecting Pool, Arcade Pong, and Card Game use that shared path so reopening achievements updates current global achievement state without freeing and rebuilding the entire popup tree.
  • resourceManager.load(...) now uses dataCacheManager internally and exposes load_resource_data(...) for callers that already have parsed resource JSON. Reflecting Pool keeps its existing API while avoiding repeated resource-file parsing on reset/startup paths.
  • eventManager now uses dataCacheManager for directory/event-pack loads, including top-level JSON array packs, and exposes load_event_pack_data(...) for callers that already have parsed event data.
  • actionEffectManager.load_actions(...) and alchemyGraphManager.load_graph(...) now route through dataCacheManager, while load_action_data(...) and load_graph_data(...) remain available for editor/import tools that already have parsed dictionaries.
  • buildProfileManager.load_profile(...) now uses dataCacheManager, reducing repeated parse work in CI/editor validation paths that reload the profile directory for menus, audits, and export plans.
  • statsManager.load_achievements(...) now uses dataCacheManager internally and exposes get_cache_stats(), so achievement catalogs loaded by main menus, game menus, and smoke tests share the same cached JSON path.
  • buildInfo.load_info(...) now routes build metadata through dataCacheManager while preserving local/editor date resolution. Splash and menu helpers can reload metadata without reparsing the same build-info file.
  • performanceMonitor.load_baseline_profiles(...) now uses dataCacheManager and exposes cache diagnostics, so repeated baseline scene audits do not reparse the same profile catalog.
  • audioManager now reads its music manifest through dataCacheManager while leaving actual audio streams on Godot's ResourceLoader path. This avoids repeated manifest parsing without duplicating imported audio resources.
  • Sprint 6 is closed for the broad rollout pass. The reusable cache, visual, delayed-save, lazy-UI, and focused lifecycle patterns are now established across the current games. Remaining work should be handled as targeted maintenance or playtest-driven migration, not as another sweeping cache pass.
  • Direct JSON readers that remain are intentionally fresh paths: save/user state, theme and sprite editors after writes, validation tools that need exact error reporting, and resource-specific loaders that already own a separate runtime cache.
  • Headless smoke now prints compact section checkpoints for CI/debug runs. The previous stall was traced to sprite_mapper.gd repeatedly loading the same sheet images while validating mappings during _ready(). The mapper now caches validation images per loaded sprite file, so tool validation stays useful without wedging headless CI. On the Windows Codex desktop sandbox, Godot headless script runs must be launched with filesystem access to Godot's normal AppData editor/cache folders; otherwise Godot 4.7 can crash before any GDScript executes. With that access, local full-smoke validation runs cleanly.
  • Scene lifecycle cleanup remains a focused follow-up: a naive root-wide free before quit() was rejected because deferred callbacks from older scene checks can still fire against freed nodes and crash Godot headless. The right fix is to make individual scene/popup checks disconnect or close their own deferred work before freeing.
  • A later root-level smoke teardown attempt reproduced the same failure mode: freed pause/menu/editor nodes still had deferred callbacks pending, and some scene scripts observed missing autoloads during _ready(). Keep teardown work local to the scene/helper that owns the callback instead of sweeping the whole root after the run.
  • Targeted lifecycle hooks are now in place for reusable UI/audio helpers: pauseOverlayController.dispose() disconnects submenu/theme hooks, standard_settings_popup.dispose() drops managed popup references and settings-change signals, achievementNotifier.dispose() cancels queued and active toast notifications, and audioManager.dispose() stops playback and clears stream caches for temporary tool/test instances. audioManager also exposes get_cache_stats() for provider snapshots so browser music/SFX cache state can be tracked alongside sprite and UI caches.
  • Current scenes now call the reusable cleanup hooks they own on exit: Arcade Pong disposes pause/settings helpers after flushing saves, Reflecting Pool and Card Game dispose achievement/pause/settings helpers, and Project Alchemy flushes delayed saves before disposing its shared settings popup builder.
  • Local validation passes through scripts/ci/build_profiles.py --validate-only --profiles all --platforms all.

Latest smoke benchmark snapshot:

  • emoji_card_collector_entry: ~415 nodes. This includes more initialized card-game shell state than the earlier lazy-only snapshot, but remains far below the original eager Collection/Battle allocation path.
  • project_alchemy_entry: ~391 nodes. Active-field performance is still the important measure here, but startup is no longer the largest cross-game outlier.
  • arcade_pong_entry: ~127 nodes.
  • main_menu_startup: ~23 nodes.
  • platformer_demo_entry: 1 measured root node.
  • reflecting_pool_entry: 1 measured root node.

Tasks:

Deferred targeted tasks:

  • Replace remaining scene-local custom code with optimized framework helpers only when playtest or profiling identifies that path as active risk.
  • Keep each game playable after each migration.
  • Add focused smoke tests for each newly migrated path before touching the next game.
  • Compare future post-refactor metrics against Sprint 1 baselines.
  • Apply the Sprint 5 cache/save patterns to future games or newly hot paths where an audit shows repeated catalog reads or hot-path persistence writes.
  • Add single-game build profile audits for new release profiles as they become active.

Release handoff:

  • The broad engine optimization rework is wrapped for now. Baselines, cache paths, lazy UI, sprite warm profiles, low-power mode, result popup helpers, level culling, and active-run summaries are all established with smoke coverage.
  • Next work should be driven by the release lanes: Arcade Pong Release Feedback for the next Arcade Pong update and Emoji Card Collector First Release Plan for the first Emoji Card Collector release.
  • New framework changes should enter only when they directly unblock one of those release checklists or a profiler/playtest identifies a concrete performance risk.

Order:

  1. Arcade Pong, because it is released and frame-sensitive.
  2. Main menu/settings/achievements, because every build uses them.
  3. Card Game inventory/shop, because list size and UI churn will grow.
  4. Project Alchemy active field, because it has the most future content.
  5. Platformer, because it will drive larger level/editor needs.
  6. Reflecting Pool, mostly to adopt shared UI/assets and keep it lightweight.

Acceptance:

  • All current games use the optimized shared systems where practical.
  • No game-specific optimization creates a second framework pattern.
  • Performance notes are updated in the relevant example docs.

Sprint 7: Mobile And Browser Hardening

Goal: make old-phone performance part of normal release discipline.

Status: complete for the current release-hardening pass. The repeatable validation checklist now lives in Mobile And Browser Hardening Checklist and covers Arcade Pong release paths, cross-game menu/settings/input behavior, low-power mode requirements, and asset/package checks. The first low-power slice is now wired through settingsManager, the standard settings popup, res://data/system/low_power_presets.json, optional spriteManager warm-profile entries, Arcade Pong's field power-up/effect-label path, inputManager no-churn touch/control switching, and audioManager next-track queue suppression.

Tasks:

  • Define browser/mobile test scenarios and manual checklist. Initial checklist is complete in Mobile And Browser Hardening Checklist.
  • Include Arcade Pong release scenarios in that checklist: match start, multiball, fast/slow ball, rockets, music transitions, achievements, stats, difficulty selection, controller switching, keyboard switching, and touch-control hiding.
  • Add settings presets for low-power mode: reduced effects, smaller caches, lower animation update rates, and simpler backgrounds. Initial implementation: reusable low_power_mode setting plus Arcade Pong field power-up cap, slower spawn pace, smaller held-slot icons, and hidden transient field effect text from low_power_presets.json. The audio manager also skips queued next-track streams from the same profile in low-power mode to reduce browser/mobile memory pressure.
  • Verify touch/controller/keyboard switching does not rebuild controls every frame. Initial implementation complete: inputManager.update_input_module(...) avoids redundant on-screen-control visibility writes, and onscreenControlManager.get_stats() exposes visibility-change diagnostics for smoke/performance checks.
  • Review audio decode/preload behavior for browser memory pressure. Initial implementation complete: queued next-track preload is disabled while low-power mode is active.
  • Review exported asset sizes and compression by profile. Initial implementation complete: CI artifact-size checks are wired for build jobs and Pages, while Arcade Pong now marks alternate ball skins as optional warmups so low-power starts can lazy-load cosmetic variants.

Acceptance:

  • A low-power mode exists and is data-driven.
  • Manual playtest checklist includes old-phone/browser-specific steps.
  • Itch-hosted individual builds and GitLab Pages all_demos remain responsive.

Follow-up:

  • Apply optional warm-profile annotations to future large cosmetic sprite sets as they are added.
  • Use the mobile/browser checklist on real devices before the next Arcade Pong release and record any device-specific findings in the release feedback page.
  • Treat further browser hitches as playtest-driven targeted fixes rather than more broad Sprint 7 groundwork.

Module Audit Order

Prioritize modules with the largest impact on frame time, memory, or repeated allocation:

  1. spriteManager, spriteRenderManager, renderNodePool, paletteManager.
  2. layoutManager, achievementScreen, settingsManager, gameSettingsPanel.
  3. inventoryList, inventoryCategoryPanel, menuManager, uiFlowManager.
  4. entityManager, entityRenderer, runManager, projectileLifecycleManager.
  5. arcadePhysicsManager, arcadePowerupManager, aiController, matchManager.
  6. levelManager, levelEditorManager, characterController2D.
  7. gridCombatManager, gridWorldManager, targetingManager, battlefieldGenerator.
  8. saveManager, statsManager, audioManager, buildProfileManager.

Definition Of Done

Each optimization sprint should finish with:

  • A short before/after note in this plan or the relevant example doc.
  • Smoke coverage for changed reusable behavior.
  • No unresolved parser warnings treated as errors.
  • No new repeated JSON load in hot paths.
  • No obvious unbounded cache growth after repeated scene changes.
  • At least one current game migrated to the optimized path.