feat: hardening IV — decomposition, tests, resilience, mobile#21
Open
xConde wants to merge 40 commits into
Open
feat: hardening IV — decomposition, tests, resilience, mobile#21xConde wants to merge 40 commits into
xConde wants to merge 40 commits into
Conversation
- Add grid size bounds (5-30), tile dimension checks, terrain type validation, spawn/exit coordinate and count validation to validateMapJson - Add validateMapPlayability method for pre-game checks (spawn/exit presence, no overlap, dimensions) - Add pre-game validation in map-select before navigating to /play - Add defensive checks in map-bridge convertToGameBoard (null guard, gridSize clamping, tiles validation) - 33 new tests covering all validation edge cases (1689 total, all passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-board Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… game-board Move setup panel (difficulty, modifiers, endless mode) and tower info panel (stats, upgrade/sell, specialization, targeting) into standalone child components. Parent retains all business logic; children only emit events. 1730 tests passing (was 1656 — +20 new component tests, +54 from prior step). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mirror the game-board error handling pattern: try/catch around ngAfterViewInit init chain, WebGL detection before renderer creation, animate() guard against null renderer, ngOnDestroy guards for partial init, and error overlay UI with fallback navigation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t; cache tower costs Move tower selection bar (buttons, tooltips, affordability) and game controls (wave start, pause, speed, range/path toggles) into standalone child components with their own templates, SCSS, and specs. Pre-compute effective tower costs into a Map to eliminate template function calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 3 hand-crafted playable demo maps with distinct layouts - Built-in Maps section on map-select with distinct styling - Demo maps not editable/deletable (read-only built-ins) - Row-major visual grid → column-major tiles conversion utility - 149 new tests (demo map validation + map-select integration) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ange rings - Extract handleInteraction() — eliminates 56 lines of duplicated click/tap logic - Extract recordGameEndIfNeeded() — consolidates duplicated game-end recording - Cache tileMeshArray and towerChildrenArray for raycasting performance - Refresh range rings after tower upgrade when showAllRanges is active - Add spawn retry safety net (SPAWN_MAX_RETRIES=300) in wave.service Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Map storage: explicit QuotaExceededError detection with warning logs - Settings service: log warnings on save failures instead of silent swallow - Player profile: pre-computed unlockedSet avoids Set allocation per getProfile() - Remove 18 unused CSS custom properties (verified grep-clean) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- EditHistoryService, CameraControlService, EditorStateService: @Injectable() - Added all three to EditorModule providers array - Updated spec files to provide services explicitly in TestBed - Services now destroyed on route away from /edit (no stale state) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tors, skip link - prefers-reduced-motion: disables animations/transitions system-wide - ARIA live regions on HUD (lives, gold, wave status) - :focus-visible indicators using theme colors - Skip-to-content link for keyboard navigation - 3 new ARIA tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Game and editor show spinner overlay while renderer initializes - Spinner hidden on success or error (error fallback takes over) - Respects prefers-reduced-motion (animation disabled) - 2 new tests for isLoading state Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Web app manifest with fullscreen display mode - SVG placeholder icon (192x192 and 512x512 referenced) - Theme color, apple-mobile-web-app meta tags - Viewport locked for gameplay (no pinch-zoom conflicts) - Manifest added to Angular build assets Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… bloom - Cap devicePixelRatio to 1.5 on mobile (prevents 9x overdraw on 3x screens) - Cap shadow map to 1024px on mobile (from 2048) - Halve particle count on mobile - Skip bloom pass on phones (≤480px) — expensive GPU effect - Centralized MOBILE_CONFIG constants - Same optimizations applied to editor renderer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…spawn retry - Wave service: endless generation scaling, getMaxWaves, spawn retry skip, reward formula (11 tests) - Tower combat: targeting strategies (nearest/first/strongest), cycle wrap, chain dedup (8 tests) - Enemy service: shield absorption edge cases, MIN_ENEMY_SPEED floor, SPEED_DEMONS selective, flying SLOW immunity (13 tests → trimmed to fit) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Deploying novarise with
|
| Latest commit: |
5138207
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://d3196c50.novarise.pages.dev |
| Branch Preview URL: | https://feat-hardening-iv.novarise.pages.dev |
…convention - Replace magic numbers in init-error overlay SCSS with CSS custom properties (both game + editor) - Fix PWA manifest to reference existing icon.svg instead of missing PNG files - Rename catch(e) to catch(error) in player-profile and settings services Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge origin/main into feat/hardening-iv. Resolved conflicts: - game-board.component.ts: adopt 3-point lighting from visual-overhaul, retain mobile shadow cap - enemy.service.spec.ts: keep both hardening IV edge case tests + visual-overhaul animation tests - tower-combat.service.spec.ts: keep both targeting/sell tests + zigzag/impact flash tests 1893/1893 tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… comment - Add console.warn when enemy is silently skipped after SPAWN_MAX_RETRIES - Move recordGameEndIfNeeded() JSDoc to correct method - Fix misleading wave preview template comment (INTERMISSION only, not SETUP) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add SKYBOX_CONFIG.timeScale for ms→seconds conversion (replaces `* 0.001`) - Add sinNormalized() utility for [-1,1]→[0,1] mapping (replaces `* 0.5 + 0.5`) - Document GLSL shader magic numbers inline per CLAUDE.md convention Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- saveMap() returns null on storage failure; callers show appropriate alerts - File import rejects files > 10 MB (prevents browser tab crash) - Achievements array capped to defined count on localStorage load - testCanvas WebGL context released after feature detection (both components) - migrateOldFormat() preserves source data when save fails - importMapFromJson() simplified with null-propagation from saveMap() - +4 tests: save failure/success alerts, file size limit, achievements cap Red team pass 2 + 3: 5 findings, all fixed. STRATEGIC_AUDIT.md updated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add camera.updateMatrixWorld() before all raycaster.setFromCamera() calls in both game and editor — OrbitControls.update() changes camera position without refreshing matrixWorld, causing stale rays after zoom - Disable left-click orbit (reserved for tower placement), move orbit to right-click; WASD still pans, scroll still zooms - Shrink minimap from 150px to 80px on phones (≤480px) and reposition from bottom-left to top-left to avoid overlapping the tower selection bar - Derive minimap mobileBreakpoint from MOBILE_CONFIG.phoneBreakpoint (single source of truth) - Add MOUSE_ACTION_DISABLED constant to camera.constants.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
window.innerWidth doesn't reflect the actual layout width when using DevTools device simulation or when the game is embedded in a narrower container. Use container.clientWidth instead for reliable mobile detection at minimap init time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
window.innerWidth and container.clientWidth both fail to reflect the CSS viewport in DevTools device simulation. matchMedia queries the same viewport that CSS media queries use, so it works reliably everywhere. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…etection JS-based viewport detection (window.innerWidth, clientWidth, matchMedia) failed to reliably detect mobile in DevTools responsive mode and on deployed previews. Moved all minimap positioning to CSS class (.minimap-canvas in styles.css) with @media (max-width: 480px) query. Desktop: bottom-left 150px. Mobile: top-left 80px. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…y tower bar - Minimap: top: 5.5rem (below HUD+wave status) instead of top: 8px - Controls: bottom offset 11rem (was 8.5rem) to clear the ~10rem tower grid - Speed buttons stay horizontal on mobile to reduce vertical footprint Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FPS counter and keyboard shortcut help (?) are not useful on phones. Hiding them at ≤480px so the audio toggle has room and doesn't crowd into the HUD bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…screen Tower selection on mobile (≤480px) now renders as a narrow column on the left side below the minimap (icon + cost only, no name/hotkey/tooltip). This frees the entire bottom of the screen that the 3×2 grid was eating. Speed controls move to bottom-right with no offset needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… ref
Sprint 1: Add GameBoardTile spec (41 tests) — factory methods, edge cases
Sprint 2: Add three-utils spec (11 tests) — disposeMaterial with all input types
Sprint 3: Fix stale enemy leak reference — updateEnemies() now returns
LeakedEnemyInfo { id, leakDamage } instead of bare IDs, eliminating
fragile post-lookup pattern
1898 → 1950 tests, all passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…onstants Sprint 4: Explicit statusEffectService.removeAllEffects() on enemy kill/leak before removeEnemy(), preventing stale effect entries (+4 tests) Sprint 5: Reset minimap visible flag in cleanup() to prevent state leak across restart cycles (+3 tests) Sprint 6: Extract 4 magic numbers from game-board.component.ts into GAME_TIMING_CONFIG, TOWER_VISUAL_CONFIG, ENEMY_VISUAL_CONFIG 1950 → 1957 tests, all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ouch Sprint 7: WebGL context loss recovery — shows overlay on GPU context loss, auto-resumes on restoration, guards animate loop (+2 tests) Sprint 8: Restart state consistency integration tests — 20 tests verifying all services reset to initial state after restartGame() Sprint 9: Keyboard shortcut test coverage — M/m (minimap), H/h (help), V/v (path), Space, plus VICTORY/DEFEAT blocking for all keys (+18 tests) Sprint 10: Mobile touch hardening — multi-touch guard prevents tower placement during pinch-to-zoom, phase guard in handleInteraction blocks raycasting during VICTORY/DEFEAT (+7 tests) 1957 → 2005 tests, all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 11: Guard WebGL context restore — check renderer.getContext() before resuming animate loop after context restoration Sprint 12: Verified tower cache rebuild — no fix needed, cache already rebuilt on add/remove, upgrades only modify existing mesh properties Sprint 13: Fix tower cost desync — tryPlaceTower() now uses getEffectiveTowerCost() instead of inline calculation Sprint 14: Wave preview overflow-x: hidden, recordGameEnd idempotence test, contextLost flag test (+2 tests) 2005 → 2007 tests, all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cs, edge cases Sprint 15: Dedicated context-lost-overlay CSS class with shared SCSS placeholder — separates recoverable vs init error overlay semantics Sprint 16: Minimap init() guard — auto-cleanup if canvas exists, prevents orphaned canvases on double-init (+1 test) Sprint 17: Editor mobile audit — no changes needed, already has proper touch targets (44px), bottom sheet, and 768px breakpoints Sprint 18: Skybox shader magic numbers fully documented inline, 5 enemy service edge case tests (remove nonexistent, empty map, no spawn points, damage dead enemy, no exit points) 2007 → 2013 tests, all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e cases Sprint 19: Map storage resilience — guard loadMap against missing data field, guard getAllMaps against non-array parsed result (+2 tests) Sprint 20: GameStateService edge case tests — 13 new tests covering setPhase idempotency, startWave DEFEAT guard, loseLife(0), exhaustive reset verification, endless highestWave tracking, rapid startWave double-call guard, reward accumulation, defensive copies (+13 tests) 2013 → 2028 tests, all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, auto-save guard - Remove unused MINIMAP_CONFIG mobile constants (CSS handles sizing) - Remove dead MINI_SWARM_MESH_SEGMENTS import from enemy.service - Normalize minimap show/toggle display values to use CSS default - Add try-catch to editor ngOnDestroy auto-save to prevent silent failures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Minimap moves from top-left (crowded between HUD and tower bar) to bottom-left corner. Tower bar now starts at 5.5rem (right below HUD) instead of 11rem, using the freed vertical space. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Production-hardening sprint: decomposed game-board god component into 6 child components, added 393 tests (1635→2028), hardened localStorage/WebGL/state resilience, redesigned mobile layout, added PWA manifest + a11y foundations.
Technical Implementation
Test Results
✓ 2028 tests passing, 0 failures
Risk Assessment
git revertthe merge commit🤖 Generated with Claude Code