- 6 procedural, vertically-tiling backgrounds generated in BootScene:
Grid, Hex Nodes, Starfield, Synthwave, Circuit, Void
- config/backgrounds.js registry + utils/background.js helper; selection
persisted via storage (KEYS.background)
- Menu / Game / GameOver use the selected background texture
- Settings overlay gains a BACKGROUND selector: in-panel live preview tile
+ < name > cycling, updates the menu background live and persists choice
- Fix: stepper/arrow buttons now add both bg and label to the modal so the
-, +, <, > glyphs render above the panel
B1 Seeded RNG + Daily Challenge
- utils/random.js wraps Phaser seedable RND (Between/frac are NOT seedable)
- All gameplay spawning (PlatformManager, Platform, Enemy) uses seeded rng
- GameScene reads mode/seed in init and seeds the run; daily shows a HUD badge
and keeps a per-day best (daily_<YYYYMMDD>); MenuScene DAILY button;
GameOver RETRY preserves mode and shows today's best
- Verified: same seed -> identical layout, different seed -> different
B2 New content
- Enemy mev_bot: homing chaser that eases toward the player (unlock >1500)
- Platform reorg: phantom, semi-transparent, vanishes shortly after landing
(unlock >600); no power-ups on breaking/reorg; SPAWN_RATES + UNLOCK config
- Verified spawn distribution at high difficulty includes all new types
B3 Settings
- SoundManager gains volume (persisted); MenuScene SETTINGS overlay with
volume stepper, particle-quality Low/High toggle, two-step reset progress
B4 Stats
- StatsManager tracks lifetime games/jumps/stomps/blocks/best combo, flushed
at game over; MenuScene STATS overlay; hooks in GameScene/ScoreManager
B5 Difficulty tuning via UNLOCK thresholds and rebalanced spawn rates
Functionally verified in-browser via eval (no console errors, deterministic
daily, content spawns, particles emit). Visual screenshot unavailable in the
headless preview because the hidden tab pauses Phaser's loop.
A1 Pooled particle system
- New ParticleManager owns 9 reusable Phaser emitters created once per scene
(jump, explosion, powerup, puff, sparks, flame, wind, spring, speedline)
- BootScene generates reusable white textures (px_square/soft/streak/ring)
- GameScene burst helpers + EffectsManager flow effects now delegate to the
pool instead of allocating rectangles + tweens every frame
- Quality auto-detect (low on mobile/small screens) cuts particle counts
A2 Fix high-speed landing tunneling
- Cap downward velocity at PHYSICS.maxFallSpeed (boosts unaffected)
- platformCollisionFilter now uses a swept deltaY one-way check so a fast
fall can never be wrongly rejected or passed through
A3 Safe storage
- New utils/storage.js wraps localStorage with in-memory fallback so private
mode / quota errors cannot crash the game; all access routed through it
A4-A6 Lifecycle and robustness
- Global error / unhandledrejection guard recovers to the menu
- GameScene auto-pauses on tab hidden and cleans up the cross-scene listener
on shutdown; fps pacing + disableContextMenu in game config
- Moving platforms use a proper dynamic body instead of destroy()+new Body
Verified in-browser: menu + game load with zero console errors, all emitters
active, normal bouncing works, fall speed capped.
- Camera now uses a trigger line at 42% from top. Player rises/falls
freely below the line; camera only scrolls up past it, never down.
- Remove playerShadow graphics that followed the hero around.
- Ignore .vercel-cli-config (CLI auth cache used as Windows workaround).
Root cause: startFollow used lerpY=0.05 + roundPixels=true. At rocket
velocity (~1400 px/s) the camera lagged ~466px behind the player, then
snapped in chunks every frame, giving the impression of low FPS / shake.
Fix:
- Replace startFollow with manual upward-only camera tracking that
matches the player exactly (doodle-jump standard behavior)
- Disable camera roundPixels so antialiasing actually smooths motion
- Round bg tilePositionY to integer to avoid grid texture shimmer
- Slightly thin out boost effects (flame 3->2/frame, speed line 40->65ms)
to keep frame budget headroom on weaker devices
- EffectsManager handles all powerup visual feedback in one place
- Replace circle trail with proper effects per type:
* Rocket: yellow->red flame particles from feet + occasional bright spark
* Propeller: white/blue wind streaks around player
* Spring: gold/green spark trail while ascending fast
- Boost start burst: two expanding rings + radial sparks + camera shake
(orange/gold for rocket, cyan for propeller, green/gold for spring)
- Boost end puff: gray smoke cloud spreading from player
- Screen edge speed lines during boost (alternate left/right edges)
- Player no longer tilts with horizontal input during boost; rocket
stays rigid upright with tiny lean, propeller has gentle sinusoidal wobble
- Extract createButton/pixelText helpers to src/utils/ui.js with
sensible defaults and per-call option overrides
- MenuScene now shows BADGES button opening the achievement panel
(10 entries, count of unlocked, star icons for completed)
- GameOverScene buttons migrated to shared utility, removing duplicate
hover/click handlers
- Smaller LEADERBOARD button to make room for BADGES alongside
- AchievementsManager with 10 unlockables and toast popups
(Genesis Block, Chain Reaction x3, Bug Hunter, First Flight,
Liftoff, Power Trip, Survivor 500, Skyscraper 1000,
Speedrun 100/60s, Gas Baron 50k)
- Score popups: +N text floats above player on every landing
(gold and larger for genesis platforms)
- Powerup duration bar in HUD bottom, color-coded per power-up,
uses scaleX for smooth depletion animation
- New enemy: Failed Tx, falls from above with sine drift, unlocks
at difficulty > 800, can be stomped, tinted red
- Dynamic background: dark cosmic overlay alpha scales with height
(max 0.5 at very high altitudes)
- Achievement hooks integrated into ScoreManager, GameScene
- Combo no longer resets if combo was already 0 (was triggering log spam)
- SoundManager via Web Audio API (no asset files needed) with procedural
SFX for jump, spring, powerup, stomp, break, death, milestone, new-best
- Sound persists mute state in localStorage; mute button on Menu and Game
- Pause system: ESC key or onscreen pause button, modal overlay with
Resume and Main Menu options, physics correctly paused/resumed
- First-run tutorial overlay explaining controls and platform types,
dismissed and remembered via localStorage flag
- Touch indicator hints fade after 3.5s on touch devices only
- Menu start triggers AudioContext initialization (browser autoplay rules)
- GameOverScene supports ENTER/SPACE shortcut for retry, NEW BEST text
now pulses, sounds fire on each transition
- Fix Rocket/PropellerHat hitboxes (relative to sprite size, not magic offsets)
- Spring now destroys itself on use with squash animation instead of staying invisible
- Guard all powerups against double-trigger via consumed flag
- Save genesis glow tween reference for clean destroy
- Player.die() disables collisions (no more post-death platform bounces)
- Replace hardcoded enemy spawn cap 0.5 with DIFFICULTY.maxEnemyRate
- Enemy spawn position now anchored to platform X (-60/+60), not random
- Powerup spawn clamped to screen bounds
- Skip powerup spawn on breaking platforms (was unfair)
- ScoreManager.addPoints() public method; remove direct score mutation
- HUD elements use setScrollFactor(0) instead of per-frame repositioning
- All magic numbers extracted to SCORE / PHYSICS / POWERUP_DURATION config
- Remove dead code: showDeathVignette, drawDebug, createParticles, deathOverlay
- Remove dead constants: PLATFORM_WIDTH/HEIGHT, PLAYER_MAX_SPEED, tileBias
- Remove SUBMIT TO CHAIN fake button, replace with Coming Soon text
- Safer cleanup loop: collect-then-destroy instead of mutating during iterate
- gwei particles now have setScrollFactor(0.3) for parallax depth