Skip to content

feat: sprint mega — 22 features, 1124 new tests, red-teamed#17

Open
xConde wants to merge 26 commits into
mainfrom
feat/sprint-mega
Open

feat: sprint mega — 22 features, 1124 new tests, red-teamed#17
xConde wants to merge 26 commits into
mainfrom
feat/sprint-mega

Conversation

@xConde

@xConde xConde commented Mar 5, 2026

Copy link
Copy Markdown
Owner

Summary

Mega sprint delivering broad gameplay, editor, and quality-of-life features across 14 commits. Full regression review and red-team pass completed.

Gameplay

  • Tower abilities — 6 types (rapid fire, chain lightning, napalm, mortar barrage, freeze aura, overcharge) with cooldowns and visual effects
  • Campaign mode — 5-level campaign with difficulty progression, localStorage persistence, cross-route navigation
  • Difficulty system — Easy/Normal/Hard/Nightmare presets scaling enemy health/speed/gold
  • Combo system — Kill streak tracking with gold bonuses at 3/5/10+ tiers
  • Healer enemy — Proximity healing with frozen-healer guard
  • Tower targeting — First/Last/Strong/Weak priority modes
  • Tower unlock system — Campaign-gated tower availability
  • Wave restart — Spend a life to retry the current wave

Visuals & UI

  • Wave composition display — Enemy type dots with tooltips per wave
  • Floating damage numbers — Pooled sprites with type-colored text
  • Slow/freeze visual tint — Enemy mesh color shifts for active effects
  • Hover range preview — Tower placement range ring on board hover
  • Path preview — Dashed spawn-to-exit line visualization
  • End screen stats — Towers placed, enemies killed, accuracy on victory/defeat
  • Interest notification — Gold interest earned per wave banner
  • Pause overlay — Visual pause state with hotkey support

Editor

  • Minimap — Canvas-rendered overview with terrain colors and camera indicator
  • Validation bar — Spawn/exit/path validation blocks play without valid path
  • Map management — Delete/rename maps in editor
  • Cross-view navigation — Campaign/maps/editor links throughout

Infrastructure

  • Mobile touch — Touch event support for tower placement and camera
  • Responsive layout — Combo counter and wave composition reflow at 480px
  • CSS design system — 50+ hardcoded colors extracted to CSS custom properties, 1px borders unified to var(--border-width-thin)
  • SCSS budget fix — Split 48KB component SCSS into 3 files via styleUrls array

Quality

  • 1703 tests (up from 579) — 1124 new tests, zero failures
  • Full regression — 4-agent hostile review against main (component, services, campaign/editor, tests/CSS)
  • Red-team pass — 4-agent hostile review (magic numbers, disposal, state/logic, test gaps)
  • Bugs fixed during review:
    • Frozen enemies leaving range permanently stuck at speed 0
    • Freeze over slow corrupting originalSpeed (restoring to slowed speed)
    • scoreBreakdown race — campaign completion could be silently skipped
    • Stale campaignLevelId leaking across sessions (freeplay triggering campaign progress)
    • tryPlaceTower confirm-before-spend violation (TOCTOU gap)
    • togglePause during completeWave permanently pausing the game
    • getWaveComposition() called 8x per change detection cycle (memoized)
    • 3 disposal leaks in editor (lights, renderPass, composer.dispose())
    • Campaign map builders using hardcoded 24 instead of CAMPAIGN_GRID_SIZE - 1
    • restartCurrentWave using stale gameState.wave snapshot

Test plan

  • npm test — 1703/1703 passing
  • ng build — production build clean, all SCSS under 35KB budget
  • Red-team: magic numbers, disposal, state/logic, test coverage
  • Manual: play campaign levels 1-5, verify difficulty scaling and completion persistence
  • Manual: place/upgrade/sell towers, verify abilities fire and cooldowns display
  • Manual: editor minimap renders, validation bar blocks play without valid path
  • Manual: responsive layout at 480px — combo counter and wave comp reflow

🤖 Generated with Claude Code

xConde and others added 10 commits March 4, 2026 14:25
…ve 1 (partial)

- Tower active abilities system with 6 unique abilities (Rapid Fire, Overcharge,
  Napalm, Freeze, Overload, Barrage) with cooldown tracking and UI
- Campaign mode with 5 built-in maps of increasing difficulty, progression
  tracking, star ratings, and score persistence
- Map manager overlay in editor with rename and delete functionality
- 1379/1379 tests passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- HEALER enemy type with cross-shaped mesh, heals nearby allies within
  range (healRate: 10 HP/s, healRange: 3 tiles), appears in waves 8-10
- Wave restart (Q key): replay current wave at -1 life cost, clears
  enemies and projectiles but keeps towers
- Pause overlay: semi-transparent backdrop with blur, "PAUSED" text
  with pulse animation, click-to-resume
- Campaign route added to app-routing (/campaign)
- 1396/1396 tests passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Tower unlock system: Basic available from start, other towers unlock
  by completing campaign levels (Sniper=L1, Splash=L2, etc.)
- Locked towers shown grayed out with unlock hint in tower selection
- Navigation links between editor, campaign, map select, and game views
- Campaign button in victory/defeat overlay for quick access
- 1434/1434 tests passing (38 new tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TargetingPriority const enum with 4 strategies
- Click-to-cycle button in tower info panel
- FIRST targets closest to exit, LAST farthest, STRONGEST most HP,
  WEAKEST least HP
- Default: FIRST (preserves existing behavior)
- 1439/1439 tests passing (5 new targeting tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mobile touch controls: tap-to-place towers, tap placed tower to
  select, drag to pan, pinch to zoom (touch core was already wired)
- Responsive layout: horizontally scrollable tower panel on small
  screens, hidden keyboard hints on mobile, touch-specific help overlay
- Interest notification: floating "+Xg interest" popup on wave
  completion with 3-second auto-dismiss animation
- 1443/1443 tests passing (4 new tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… validation

- Enemy slow/freeze visual: tint enemy meshes blue when slowed, restore on expire
- Hover range preview: translucent range ring on tile hover before tower placement
- End screen stats: detailed game stats grid (kills, damage, gold, shots, leaked)
- Editor validation: real-time status bar showing spawn/exit/path readiness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Difficulty modes (Easy/Normal/Hard/Nightmare) with enemy stat scaling
- Kill streak combo system with bonus gold and combo counter UI
- Floating damage number sprites on enemy hit (pooled, color-coded)
- Enemy path preview line during SETUP phase (dashed gold line)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wave composition panel showing enemy types/counts during combat + next wave preview
- Editor minimap with bird's-eye terrain view, spawn/exit markers, toggle visibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e edge cases

Critical fixes:
- Campaign completeLevel() never called on VICTORY — progress was frozen
- Campaign playLevel() didn't set difficulty or level ID on MapBridgeService
- restartGame() didn't re-apply difficulty after reset
- PathVisualizationService.cleanup() couldn't remove line from scene
- restartCurrentWave() leaked damage/gold popup sprites

Cross-feature fixes:
- Frozen healer no longer heals allies (speed === 0 guard)
- Damage numbers freeze during pause (visual consistency)
- Wave restart resets combo counter
- Healer enemy dot color added to wave preview CSS
- MapSelectComponent clears stale campaign level ID

Magic number extraction:
- 12 hardcoded literals → named constants in combat/effects/ui constants
- Slow/chain/mortar tower fallback values → TOWER_CONFIGS references
- Chain arc opacity, napalm DoT fraction, health bar offsets extracted

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… breakpoints

- GameBoardComponent: 66 new tests (tower mgmt, abilities, game control, navigation, notifications)
- Editor: 38 new tests (edit modes, brush, undo/redo, navigation, canPlayMap)
- TowerCombatService: 18 new tests (ability cooldowns, mortar DoT, chain falloff, barrage, napalm)
- EnemyService: 7 new tests (healer mechanics, NIGHTMARE scaling, movement edges)
- WaveService: 24 new tests (boss boundaries, high-wave scaling, reset state)
- Campaign/MapSelect: 2 new navigation tests
- CSS: extracted 30+ hardcoded colors to CSS vars, unified difficulty colors, responsive at 480px

1691/1691 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Mar 5, 2026

Copy link
Copy Markdown

Deploying novarise with  Cloudflare Pages  Cloudflare Pages

Latest commit: 873dddd
Status: ✅  Deploy successful!
Preview URL: https://718b9541.novarise.pages.dev
Branch Preview URL: https://feat-sprint-mega.novarise.pages.dev

View logs

xConde and others added 4 commits March 4, 2026 21:04
Split 48KB game-board.component.scss into 3 files (~13KB + 18KB + 18KB)
using Angular's styleUrls array — no @use imports needed, same
ViewEncapsulation scope.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…cleanup

Critical fixes:
- Frozen enemies leaving tower range now correctly unfreeze (was permanent)
- Freeze over slow no longer corrupts originalSpeed (was restoring to slowed speed)
- scoreBreakdown race eliminated — campaign completeLevel() moved to state subscription
- Stale campaignLevelId cleared in ngOnDestroy() (freeplay no longer triggers campaign)

Performance:
- getWaveComposition() memoized as property — was called 8x per CD cycle in template

Logic fixes:
- restartCurrentWave() reads authoritative wave from service, not stale snapshot
- Chain damage guard changed from <= 0 to < 1 (Math.round can produce 0)
- Healer freeze guard uses <= 0 instead of === 0 magic literal
- Removed unused healthMult from generateEndlessWave()
- ENDLESS_ENEMY_CYCLE exported from wave.model.ts — single source of truth

CSS:
- Added missing --action-red CSS var
- Added flying enemy dot to wave-preview
- Replaced z-index: 50 magic number with var(--z-index-modal)

Tests:
- Added Three.js scene disposal in afterEach (tower-combat, enemy specs)
- Added HEALER stats tests (healRate, healRange)
- Enemy type count assertion uses EnemyType enum length instead of hardcoded 9

1693/1693 tests passing.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
… output

CSS hardcodes eliminated:
- 11 border 1px → var(--border-width-thin) in editor SCSS
- 3 border 1px → var(--border-width-thin) in overlays/tower-panel
- rgba overlay backgrounds → var(--overlay-dim) / var(--overlay-dim-70)
- rgba ability button states → var(--action-yellow-bg-hover), var(--action-green-bg-active)
- rgba pause-btn gold states → var(--game-gold-a15/a30/a50)
- rgba campaign reset hover → var(--reset-btn-bg-hover/shadow-hover)
- blur(2px) → blur(0.125rem) for unit consistency

Behavior fixes:
- Campaign goBack() uses Location.back() instead of hardcoded /edit route
- Removed dead deleteMapClick @output from edit-controls

1693/1693 tests passing.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…t gaps

Disposal fixes (novarise.component.ts):
- Store all lights in array, dispose shadow maps + remove from scene in ngOnDestroy
- Store renderPass as instance property, dispose in ngOnDestroy
- Add composer.dispose() after render target disposal

State/logic fixes:
- tryPlaceTower: spendGold first, refund on placeTower failure (confirm-before-spend)
- completeWave/startWave: clear isPaused to prevent stuck pause during phase transition
- Campaign map builders: replace hardcoded 24 with CAMPAIGN_GRID_SIZE - 1

Test coverage (+10 tests):
- clearProjectiles() slow/freeze restoration and projectile cleanup
- Targeting priorities LAST and STRONGEST
- Campaign completeLevel called on VICTORY with correct args
- Corrupted localStorage fallback in campaign service
- completeWave/startWave clear isPaused

1703/1703 tests passing.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@xConde xConde changed the title feat: sprint mega — 22 features, 1112 new tests feat: sprint mega — 22 features, 1124 new tests, red-teamed Mar 5, 2026
xConde and others added 12 commits March 5, 2026 10:47
…ditor

Gameplay fixes:
- Gold multiplier now applied to enemy kills and wave rewards (NIGHTMARE/HARD/EASY scaling was broken)
- Mortar projectiles in-flight after tower sold now still explode (stats captured at fire time)
- Wave soft-lock prevented: spawn retries capped at 60 attempts before discarding entry
- Ability activation blocked during INTERMISSION (was wasting cooldowns)
- Restart preserves player-selected difficulty (was reverting to mapBridge default)
- First-frame deltaTime spike eliminated (was causing 100ms physics jump on frame 2)

Visual fixes:
- Health bars billboard toward camera every frame (was facing fixed +Z direction)
- Projectiles track enemy Y position (was flying at ground level toward flying enemies)
- Damage numbers, gold/damage popups now speed-scaled at 2x/3x (was lingering)

UI fixes:
- [disabled] attribute added to restart-wave-btn and upgrade-btn (was CSS-only, keyboard accessible)
- Pause button disabled outside COMBAT phase (was clickable but non-functional)
- Minimap toggle shows state indicator (was 'M' in both branches)

Editor fixes:
- playMap() sets bridge state before navigate (was race condition with ngOnDestroy)
- Auto-save only updates existing maps, no longer creates duplicates on every navigation
- Spawn/exit markers hide when points are undone (was visible at last position)
- Rectangle preview limit raised from 100 to 625 tiles (was silently invisible for large selections)
- fillRectangle() height mode uses EDITOR_HEIGHT.stepSize constant (was hardcoded 0.2)

1704/1704 tests passing.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…verflow

UI fixes:
- Combo counter z-index raised above wave-composition panel (was overlapping)
- Interest notification z-index uses CSS var (was raw magic number 60)
- Map select container scrolls internally (was clipped by body overflow: hidden)
- Locked tower buttons excluded from tab order (tabindex=-1)
- Help overlay scoped inside .board-container (was global selector)

Visual fixes:
- Freeze/slow color state: freeze expiry checks for active slow before restoring
  color — prevents permanent blue tint on enemies with overlapping effects
- Chain lightning arcs use actual enemy Y position (was ground-level, disconnected
  from flying enemies)

1704/1704 tests passing.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Block launching maps without spawn/exit points (5 new tests)
- Hide campaign button in freeplay end-game overlay
- Prevent multiple screen shakes after DEFEAT
- Double-click occupied tile opens tower info instead of deselecting

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…over-slow

expireFreezeEffect's continue guard skipped entries where slow was still
active, making the restore-to-slowed-speed branch unreachable. Enemies
frozen while slowed stayed at speed 0 until slow expired, then jumped
to full speed — bypassing the slowed phase entirely.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add trackBy functions to all 16 *ngFor directives across game-board,
  map-select, campaign, editor, and edit-controls templates
- Add focus traps with role=dialog, aria-modal, tabindex=-1, and
  escape-to-close on pause, victory/defeat, help, and map manager overlays

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- HUD collapses secondary stats at <480px, max-width prevents overflow
- Wave composition hidden at <480px to not block gameplay
- Pause/victory overlays scale down on small screens
- Map select and campaign get responsive grid layouts
- Touch targets raised to 44px minimum on pointer:coarse devices
- Replace ~20 hardcoded rgba/color literals with CSS custom properties
- Add --game-star-glow, --text-muted, --panel-bg custom properties

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
TowerCombatService.update() now returns killedWithTypes alongside killed,
attributing each kill to its tower type (chain, projectile, mortar DoT).
Game loop calls gameStatsService.recordKill() so the score breakdown
shows accurate per-tower kill counts instead of zeros.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Brush scale/opacity and particle oscillation/rotation literals moved to
editor-ui.constants.ts per no-magic-numbers convention.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…idempotency

- addGold/addScore reject negative amounts (prevents corruption)
- completeWave clamps reward to >= 0
- startWave guards against COMBAT phase (prevents wave skip on double-tap)
- awardInterest tracks per-intermission flag (prevents compound exploit)
- 26 new tests covering all edge cases

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Replace single-step waypoint advance with while loop that consumes
  full movement budget per tick — fixes lag at high speed/large deltaTime
- Apply difficulty speed multiplier to mini-swarm children (was base speed)
- 19 new tests: multi-hop, mini-swarm scaling, pathfinding edges, speed guards

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Splash and napalm branches called damageEnemy on dead enemies still in
the map. Added health <= 0 guard matching existing mortar DoT and chain
lightning patterns. 8 new tests cover splash guards, killedWithTypes
attribution, chain arc cleanup, and mortar-after-sell.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…config

- TILE_COLORS, TILE_RENDER_CONFIG, GRID_LINE_CONFIG in board.constants
- ENDLESS_PRIMARY/SECONDARY_SPLIT, MIN_SPAWN_INTERVAL in wave.model
- DELTA_TIME_CAP_S in rendering.constants
- Upgrade flash/glow offsets in effects.constants
- Health bar half-width derived from HEALTH_BAR_CONFIG.width

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant