Commit Graph

23 Commits

Author SHA1 Message Date
123b341ed7 Replace debugLog and console.* with loglevel logger
- Create centralized logger module (src/core/logger.ts)
- Replace all debugLog() calls with log.debug()
- Replace console.log() with log.info()
- Replace console.warn() with log.warn()
- Replace console.error() with log.error()
- Delete deprecated src/core/debug.ts
- Configure log levels: debug for dev, warn for production
- Add localStorage override for production debugging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 05:24:18 -06:00
5e67b796ba Add ESLint and refactor leaderboard to join with users table
- Add ESLint with typescript-eslint for unused code detection
- Fix 33 unused variable/import warnings across codebase
- Remove player_name from leaderboard insert (normalized design)
- Add ensureUserProfile() to upsert user display_name to users table
- Update leaderboard queries to join with users(display_name)
- Add getDisplayName() helper for leaderboard entries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 03:52:03 -06:00
44c685ac2d Cleanup batch 5: Remove unused exported types
Made 75+ types internal (removed export keyword) across 24 files:
- Analytics event types (kept GameEventMap, GameEventName, GameEventProperties)
- Level config types (QuaternionArray, MaterialConfig, etc.)
- Ship types (SightConfig, InputState, etc.)
- Store state types (AuthState, GameConfigData, etc.)
- Various config interfaces

These types are still used internally but were never imported elsewhere.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 18:11:40 -06:00
8570c22a0c Cleanup batch 1: Delete 11 unused source files
Removed files identified by knip as never imported:
- src/utils/scoreEvent.ts (duplicate type)
- src/components/shared/VectorInput.svelte
- src/levels/storage/ILevelStorageProvider.ts
- src/ship/shipEngine.ts
- src/levels/config/levelSerializer.ts
- src/levels/generation/levelEditor.ts
- src/levels/generation/levelGenerator.ts
- src/levels/stats/levelStats.ts
- src/ui/screens/controlsScreen.ts
- src/ui/screens/settingsScreen.ts
- src/environment/celestial/planetTextures.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 17:41:02 -06:00
b4baa2beba Migrate to cloud-only level system using Supabase
All checks were successful
Build / build (push) Successful in 1m44s
Remove all local level storage concepts and load levels exclusively from
Supabase cloud. Simplifies LevelRegistry from 380+ lines to ~50 lines.
Uses CloudLevelEntry directly throughout the codebase instead of wrapper
types like LevelDirectoryEntry.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 17:26:24 -06:00
c9d7b0f3a5 Update ship positions 2025-11-28 10:46:39 -06:00
a9ae41c7eb Fix WebXR camera setup and pointer selection timing
- Create consolidated setupXRCamera() method in Level1 to handle all XR
  camera initialization in one place
- Use intermediate TransformNode (xrCameraRig) for camera rotation since
  WebXR camera only uses rotationQuaternion which XR frame updates overwrite
- Fix pointer selection feature registration timing - must register after
  XR session starts, not during initialize()
- Move pointer registration to onStateChangedObservable and setupXRCamera()
- Don't stop render loop before entering XR as it may prevent observables
  from firing properly
- Fix audio paths in shipAudio.ts to use correct asset locations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 10:22:59 -06:00
a9070a5d8f Add leaderboard infinite scroll and improve seed script scoring
All checks were successful
Build / build (push) Successful in 1m45s
- Add pagination support to CloudLeaderboardService with offset parameter
- Implement infinite scroll in Leaderboard.svelte using IntersectionObserver
- Update seed script to use actual game scoring formulas (time, accuracy, fuel, hull multipliers)
- Add level-specific asteroid counts and par times to seed data
- Create BUGS.md to track known issues
- Partial work on XR camera orientation (documented in BUGS.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 12:51:43 -06:00
3ff1ffeb45 Simplify level system and add asteroid-mania level
All checks were successful
Build / build (push) Successful in 1m29s
- Add new asteroid-mania level to directory and DEFAULT_LEVEL_ORDER
- Remove level caching entirely (always fetch fresh from network)
- Delete legacy router.ts, levelSelector.ts, and levelVersionManager.ts
- Remove unused router handlers from main.ts (~120 lines)
- Fix projectile curving by cloning velocity vector in weaponSystem.ts
- Update LevelSelect.svelte to include asteroid-mania

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 15:34:23 -06:00
3f164df9e8 Add game results leaderboard system
All checks were successful
Build / build (push) Successful in 1m30s
- Create GameResultsService for storing game results in localStorage
- Create gameResultsStore Svelte store for reactive data access
- Add Leaderboard component showing top 20 scores
- Add leaderboard route and navigation link
- Record game results on victory/death/stranded (not manual exits)
- Fix header visibility when exiting game
- Fix camera error by stopping render loop after cleanup
- Clear canvas after cleanup to prevent last frame showing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 12:39:23 -06:00
28c1b2b2aa Fix routing, cleanup, and game restart issues
- Switch from svelte-spa-router to svelte-routing for clean URLs without hashes
- Fix relative asset paths to absolute paths (prevents 404s on nested routes)
- Fix physics engine disposal using scene.disablePhysicsEngine()
- Fix Ship observer cleanup to prevent stale callbacks after level disposal
- Add _gameplayStarted flag to prevent false game-end triggers during init
- Add hasAsteroidsToDestroy check to prevent false victory on restart
- Add RockFactory.reset() to properly reinitialize asteroid mesh between games
- Add null safety checks throughout RockFactory for static properties

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 11:21:05 -06:00
fa15fce4ef Fixed some physics problems. 2025-11-24 17:03:41 -06:00
e31e25f9e5 Fix physics issues: sleep behavior, center of mass, and input scaling
This commit resolves several physics-related issues that were causing
unexpected behavior in ship and asteroid movement:

**Physics Sleep System**
- Fixed abrupt stops by preventing Havok from putting bodies to sleep
- Added PhysicsActivationControl.ALWAYS_ACTIVE for ship and asteroids
- Made ship sleep behavior configurable via shipPhysics.alwaysActive
- Sleep was causing sudden velocity zeroing at low speeds

**Center of Mass Issues**
- Discovered mesh-based physics calculated offset CoM: (0, -0.38, 0.37)
- Override ship center of mass to (0, 0, 0) to prevent thrust torque
- Applying force at offset CoM was creating unwanted pitch rotation
- Added debug logging to track mass properties

**Input Deadzone Improvements**
- Implemented smooth deadzone scaling (0.1-0.15 range)
- Replaced hard threshold cliff with linear interpolation
- Prevents abrupt control cutoff during gentle inputs
- Added VR mode check to disable keyboard fallback in VR

**Configuration System**
- Added DEFAULT_SHIP_PHYSICS constant as single source of truth
- Added tunable parameters: linearDamping, angularDamping, alwaysActive
- Added fuel consumption rates: linearFuelConsumptionRate, angularFuelConsumptionRate
- Tuned for 1 minute linear thrust, 2 minutes angular thrust at 60Hz
- All physics parameters now persist to localStorage

**Other Fixes**
- Changed orbit center to STATIC motion type (was ANIMATED)
- Fixed linear force application point (removed offset)
- Added ship initial velocity support from level config
- Changed physics update from every 10 frames to every physics tick
- Increased linear input threshold from 0.1 to 0.15

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 14:03:32 -06:00
71ff46e4cf Implement comprehensive scoring system with star ratings
All checks were successful
Build / build (push) Successful in 1m35s
Add linear-clamped scoring system that rewards speed, accuracy, fuel
efficiency, and hull integrity. Scores are always positive with a 0.5x
multiplier floor for refueling/repairs.

Scoring Components:
- Create scoreCalculator module with configurable scoring logic
- Time multiplier: Exponential decay from par time (0.1x to 3.0x)
- Accuracy multiplier: Linear 1.0x to 2.0x based on hit percentage
- Fuel efficiency: Linear with 0.5x floor (handles refueling >100%)
- Hull integrity: Linear with 0.5x floor (handles deaths/repairs >100%)
- Star rating system: 0-3 stars per category (12 stars max)

Integration:
- Add calculateFinalScore() to GameStats
- Support parTime in level config metadata
- Auto-calculate par time from difficulty level in Level1
  - Recruit: 300s, Pilot: 180s, Captain: 120s, Commander: 90s, Test: 60s
- Display comprehensive score breakdown on status screen

Status Screen Updates:
- Increase mesh size from 1.5x1.0m to 1.5x2.25m (portrait orientation)
- Increase texture from 1024x768 to 1024x1536 (fit all content)
- Add score display section with:
  - Final score in gold with thousand separators
  - Score multiplier breakdown for each category
  - Unicode star ratings (★★★) per category
  - Total stars earned (X/12)

Formula:
finalScore = 10,000 × time × accuracy × fuel × hull

All multipliers ≥ 0.5, ensuring scores are never negative even with
multiple refuels/deaths. System rewards balanced excellence across all
performance metrics.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 06:32:55 -06:00
1422c5b926 Add centralized input control management and mission brief improvements
All checks were successful
Build / build (push) Successful in 1m31s
- Create InputControlManager singleton for centralized ship controls and pointer selection management
  - Last-wins behavior for state changes
  - Mutually exclusive ship controls and VR pointer selection
  - Observable events for state changes with requester tracking
  - Enables debugging and prevents conflicts between UI components

- Refactor Ship class to use InputControlManager
  - Remove disableControls() and enableControls() methods
  - Register input systems with InputControlManager on initialization
  - Simplify control state management throughout ship lifecycle

- Update StatusScreen to use InputControlManager
  - Remove manual pointer selection enable/disable methods
  - Delegate control management to InputControlManager
  - Automatic laser pointer enabling when screen shows

- Update Level1 mission brief to use InputControlManager
  - Consistent control management for mission brief display
  - Proper pointer selection during mission brief interaction

- Fix controller input trigger blocking bug
  - Triggers now properly blocked when controls disabled
  - Prevents shooting when status screen or mission brief is visible
  - Only X-button (status screen toggle) allowed when disabled

- Add START MISSION button to mission brief
  - Replace "Pull trigger to start" text with clickable button
  - Green styled button matching StatusScreen design
  - Works with VR laser pointer interaction
  - Trigger pull still works as fallback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 17:25:11 -06:00
eccf101b73 Implement Svelte-based UI architecture with component system
All checks were successful
Build / build (push) Successful in 1m20s
Major refactoring of the UI layer to use Svelte components:
- Replace inline HTML with modular Svelte components
- Add authentication system with UserProfile component
- Implement navigation store for view management
- Create comprehensive settings and controls screens
- Add level editor with JSON validation
- Implement progression tracking system
- Update level configurations and base station model

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:01:17 -06:00
ff8d69b6ec Add VR controller remapping configuration system
All checks were successful
Build / build (push) Successful in 1m32s
Implement comprehensive controller remapping UI that allows users to customize
VR controller button and stick mappings with per-axis granularity and inversion
controls. Configuration persists to localStorage and applies on level start.

## Features
- Full-page controller remapping UI at #/controls
- Per-axis stick mapping (4 dropdowns: leftX, leftY, rightX, rightY)
- Individual axis inversion toggles (8 total invert options)
- Button remapping (6 buttons: trigger, A, B, X, Y, squeeze)
- Available actions: yaw, pitch, roll, forward thrust, camera, status screen
- Configuration validation with warnings for duplicates/missing controls
- Preview/test functionality to review current mapping
- Reset to default option
- localStorage persistence with backward compatibility

## Implementation
- ControllerMappingConfig singleton manages configuration and validation
- ControlsScreen handles UI logic and form manipulation
- ControllerInput applies mapping by translating raw input to actions
- Actions mapped back to virtual stick positions for ShipPhysics
- No changes needed to ShipPhysics - receives correctly mapped values

## User Flow
1. Navigate to Controls via header menu
2. Select action for each stick axis (yaw/pitch/roll/forward/none)
3. Toggle invert checkboxes as needed
4. Assign button actions (fire/camera/status/none)
5. Save configuration
6. Changes apply when starting new level

## Technical Details
- Storage key: 'space-game-controller-mapping'
- Raw stick values stored, mapping applied in getInputState()
- Supports future actions without code changes
- Validation ensures critical controls (fire, forward) are mapped

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 08:11:04 -06:00
e9ddf91b85 Implement trigger-based mission brief dismissal for VR gameplay
All checks were successful
Build / build (push) Successful in 1m33s
Add mission briefing system that displays when entering VR and requires
trigger pull to dismiss before gameplay begins. This prevents accidental
weapon firing and provides clear mission objectives to players.

## Key Features
- Mission brief displays on VR entry with objectives from directory.json
- Ship controls disabled during briefing (movement, rotation, weapons)
- Either controller trigger dismisses brief and starts game timer
- First trigger pull does not fire weapons, only dismisses briefing
- Subsequent trigger pulls fire weapons normally

## Implementation Details
- Added MissionBrief class with mesh-based UI parented to ship
- Ship class gains disableControls()/enableControls() methods
- New mission brief trigger observable bypasses normal shoot handling
- ControllerInput modified to allow triggers through when disabled
- Level1 orchestrates control flow: disable → show brief → enable
- Game timer and physics recording start only after dismissal

## Technical Changes
- controllerInput.ts: Allow trigger events when controls disabled
- ship.ts: Add control state tracking and mission brief observable
- level1.ts: Integrate mission brief into XR initialization flow
- missionBrief.ts: New class for displaying briefing with trigger detection
- Fixed property name mismatch in level selection event dispatch
- Added cache-busting for dev mode level loading
- Exposed LevelRegistry to window for debugging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 07:44:46 -06:00
fd1a92f7e3 Add analytics abstraction layer with intelligent batching
All checks were successful
Build / build (push) Successful in 2m0s
Implements a flexible, provider-agnostic analytics system with New Relic adapter featuring intelligent event batching for cost optimization.

Features:
- Type-safe event tracking with TypeScript interfaces
- Pluggable adapter architecture for multiple providers
- Intelligent batching (reduces data usage by 70-90%)
- Event sampling for high-volume events
- Zero breaking changes to existing New Relic setup
- Debug mode for development testing

Integration points:
- Session tracking in main.ts
- Level start and WebXR events in level1.ts
- Asteroid destruction and hull damage in ship.ts
- Performance snapshots and session end in gameStats.ts

Events tracked:
- session_start, session_end
- webxr_session_start
- level_start
- asteroid_destroyed (20% sampled)
- hull_damage
- gameplay_snapshot (60s intervals, 50% sampled)

Cost optimization:
- Batching reduces individual events by ~70%
- Sampling reduces high-frequency events by 50-80%
- Combined savings: ~90% data reduction
- Keeps usage safely under New Relic free tier (100GB/month)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-12 16:22:28 -06:00
9b22b06d08 Fix critical bug: Repeating voice messages now stop when resources recover
All checks were successful
Build / build (push) Successful in 1m24s
Added stateKey field to VoiceMessage interface to explicitly link messages
with warning states, preventing infinite repeat loops.

Bug fixes:
- Messages check warning state exists before re-queuing
- clearWarningState() now purges matching messages from queue
- Proper cleanup when resources increase above thresholds

Changes to voiceAudioSystem.ts:
- VoiceMessage interface: Added stateKey field
- queueMessage(): Added stateKey parameter
- handleStatusChange(): Pass state keys when queueing warnings
- update(): Validate state exists before re-queuing repeating messages
- clearWarningState(): Filter queue to remove messages with matching stateKey

Also includes explosion audio improvements:
- Use onEndedObservable instead of setTimeout for audio cleanup
- Adjusted explosion force and duration parameters

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 16:57:12 -06:00
b523d5e31a Add repeating voice announcements with danger/warning prioritization
Implemented repeating voice messages that automatically replay at intervals until the condition clears, with danger messages superseding warnings.

Changes:
- VoiceMessage interface: Added repeatInterval and lastPlayedTime fields
- queueMessage(): Now accepts repeatInterval parameter (0 = no repeat)
- update(): Implements repeat logic
  - After sequence completes, checks repeatInterval
  - Re-queues message with timestamp tracking
  - Waits for interval to elapse before replaying
- clearWarningState(): New method to clear specific warning states
- handleStatusChange(): Enhanced logic with prioritization
  - Clears warning states when resources increase above thresholds
  - Danger warnings (< 10%): repeat every 2s, clear warning state
  - Regular warnings (10-30%): repeat every 4s, only if not in danger
  - Empty warnings: play once, no repeat

Behavior:
- Fuel 25%: "warning → fuel" repeats every 4s
- Fuel drops to 8%: Warning stops, "danger → fuel" repeats every 2s
- Fuel recovers to 15%: Danger stops, "warning → fuel" resumes
- Fuel recovers to 35%: All warnings stop
- Refueling/repairing clears states, allows re-triggering

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 16:24:28 -06:00
415496b3a2 Add voice audio system for cockpit computer announcements
All checks were successful
Build / build (push) Successful in 1m21s
Implemented VoiceAudioSystem class that loads voice clips and plays them sequentially in response to game events (fuel/hull/ammo warnings).

Changes:
- VoiceAudioSystem: New class for managing voice audio
  - Loads 13 voice MP3 files (warning, danger, fuel, hull, ammo, etc.)
  - Priority queue system (HIGH, NORMAL, LOW)
  - Sequential playback with state polling
  - One-shot warning tracking to prevent spam
  - Non-spatial audio (cockpit computer voice)

- Ship: Integrated VoiceAudioSystem
  - Initialize voice system after ShipAudio
  - Subscribe to ShipStatus.onStatusChanged events
  - Call update() in render loop for sequential playback

Features:
- Event-driven warnings trigger on status thresholds
  - Fuel/hull/ammo < 30%: "warning" → resource name
  - Fuel/hull/ammo < 10%: "danger" → resource name
  - Resource = 0: resource name → "empty"
- Comprehensive debug logging for troubleshooting
- State machine handles queue and playback sequencing

Note: Current implementation has a bug in getMaxValue() calculation that prevents warnings from triggering correctly. Will be fixed in next commit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 15:18:41 -06:00
0dc3c9d68d Restructure codebase into logical subdirectories
All checks were successful
Build / build (push) Successful in 1m20s
## Major Reorganization

Reorganized all 57 TypeScript files from flat src/ directory into logical subdirectories for improved maintainability and discoverability.

## New Directory Structure

```
src/
├── core/ (4 files)
│   └── Foundation modules: defaultScene, gameConfig, debug, router
│
├── ship/ (10 files)
│   ├── Ship coordination and subsystems
│   └── input/ - VR controller and keyboard input
│
├── levels/ (10 files)
│   ├── config/ - Level schema, serialization, deserialization
│   ├── generation/ - Level generator and editor
│   └── ui/ - Level selector
│
├── environment/ (11 files)
│   ├── asteroids/ - Rock factory and explosions
│   ├── celestial/ - Suns, planets, textures
│   ├── stations/ - Star base loading
│   └── background/ - Stars, mirror, radar
│
├── ui/ (9 files)
│   ├── hud/ - Scoreboard and status screen
│   ├── screens/ - Login, settings, preloader
│   └── widgets/ - Discord integration
│
├── replay/ (7 files)
│   ├── Replay system components
│   └── recording/ - Physics recording and storage
│
├── game/ (3 files)
│   └── Game systems: stats, progression, demo
│
├── services/ (2 files)
│   └── External integrations: auth, social
│
└── utils/ (5 files)
    └── Shared utilities and helpers
```

## Changes Made

### File Moves (57 files)
- Core modules: 4 files → core/
- Ship system: 10 files → ship/ + ship/input/
- Level system: 10 files → levels/ (+ 3 subdirs)
- Environment: 11 files → environment/ (+ 4 subdirs)
- UI components: 9 files → ui/ (+ 3 subdirs)
- Replay system: 7 files → replay/ + replay/recording/
- Game systems: 3 files → game/
- Services: 2 files → services/
- Utilities: 5 files → utils/

### Import Path Updates
- Updated ~200 import statements across all files
- Fixed relative paths based on new directory structure
- Fixed case-sensitive import issues (physicsRecorder, physicsStorage)
- Ensured consistent lowercase filenames for imports

## Benefits

1. **Easy Navigation** - Related code grouped together
2. **Clear Boundaries** - Logical separation of concerns
3. **Scalability** - Easy pattern for adding new features
4. **Discoverability** - Find ship code in /ship, levels in /levels, etc.
5. **Maintainability** - Isolated modules easier to update
6. **No Circular Dependencies** - Clean dependency graph maintained

## Testing

- All TypeScript compilation errors resolved
- Build succeeds with new structure
- Import paths verified and corrected
- Case-sensitivity issues fixed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 12:53:18 -06:00