Compare commits
2 Commits
230fc1bc0c
...
40d07ee68c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40d07ee68c | ||
|
|
8ec240333c |
9
.claude/settings.local.json
Normal file
9
.claude/settings.local.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(find:*)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,13 +12,13 @@ A hockey match engine simulation built with PhaserJS and TypeScript. The engine
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start development server (runs on port 3000)
|
# Start development server (runs on port 3000)
|
||||||
npm run dev
|
pnpm run dev
|
||||||
|
|
||||||
# Build for production
|
# Build for production
|
||||||
npm run build
|
pnpm run build
|
||||||
|
|
||||||
# Preview production build
|
# Preview production build
|
||||||
npm run preview
|
pnpm run preview
|
||||||
```
|
```
|
||||||
|
|
||||||
## Coordinate System
|
## Coordinate System
|
||||||
|
|||||||
336
REVIEW.md
Normal file
336
REVIEW.md
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
# REVIEW.md
|
||||||
|
|
||||||
|
This document provides a systematic checklist for conducting periodic code reviews of the hockey-manager-2 codebase. Use this to maintain code quality, consistency, and adherence to best practices.
|
||||||
|
|
||||||
|
## Review Frequency
|
||||||
|
|
||||||
|
- **Minor Review**: After completing each phase (see [PLAN.md](PLAN.md))
|
||||||
|
- **Major Review**: Every 2-3 phases or when accumulating significant technical debt
|
||||||
|
- **Pre-Release Review**: Before any major release or milestone
|
||||||
|
|
||||||
|
## Review Checklist
|
||||||
|
|
||||||
|
### 1. Code Organization & Architecture
|
||||||
|
|
||||||
|
#### File Structure
|
||||||
|
- [ ] Files are in correct directories according to their responsibility
|
||||||
|
- [ ] No circular dependencies between modules
|
||||||
|
- [ ] Clear separation of concerns (entities, systems, config, scenes)
|
||||||
|
- [ ] Phaser-specific code isolated from game logic where possible
|
||||||
|
|
||||||
|
#### Naming Conventions
|
||||||
|
- [ ] Classes use PascalCase (`Player`, `BehaviorTree`)
|
||||||
|
- [ ] Files match class names (`Player.ts`, `GameScene.ts`)
|
||||||
|
- [ ] Constants use SCREAMING_SNAKE_CASE (`RINK_WIDTH`, `TARGET_FPS`)
|
||||||
|
- [ ] Variables and functions use camelCase (`currentPosition`, `calculateDistance()`)
|
||||||
|
- [ ] Meaningful, descriptive names (avoid `temp`, `data`, `handler` without context)
|
||||||
|
|
||||||
|
### 2. DRY (Don't Repeat Yourself)
|
||||||
|
|
||||||
|
#### Code Duplication
|
||||||
|
- [ ] No duplicate logic across files (extract to shared utilities)
|
||||||
|
- [ ] No duplicate constants (all magic numbers in [constants.ts](src/config/constants.ts))
|
||||||
|
- [ ] No duplicate type definitions (centralize in types file)
|
||||||
|
- [ ] Similar entity behaviors extracted to base classes or systems
|
||||||
|
|
||||||
|
#### Common Patterns to Extract
|
||||||
|
- [ ] Distance calculations → utility function
|
||||||
|
- [ ] Position validation/clamping → utility function
|
||||||
|
- [ ] Phaser object creation → factory functions
|
||||||
|
- [ ] Coordinate conversions (meters ↔ pixels) → utility functions
|
||||||
|
|
||||||
|
### 3. KISS (Keep It Simple, Stupid)
|
||||||
|
|
||||||
|
#### Simplicity Checks
|
||||||
|
- [ ] Functions do one thing and do it well
|
||||||
|
- [ ] No overly clever solutions that sacrifice readability
|
||||||
|
- [ ] Complex algorithms have explanatory comments
|
||||||
|
- [ ] Prefer explicit over implicit behavior
|
||||||
|
- [ ] Avoid premature optimization
|
||||||
|
|
||||||
|
#### Function Complexity
|
||||||
|
- [ ] Functions < 50 lines (guideline, not hard rule)
|
||||||
|
- [ ] Nested conditionals < 3 levels deep
|
||||||
|
- [ ] Function parameters < 5 (consider config objects for more)
|
||||||
|
- [ ] No "god functions" that do too much
|
||||||
|
|
||||||
|
### 4. Type Safety
|
||||||
|
|
||||||
|
#### TypeScript Usage
|
||||||
|
- [ ] No `any` types (use `unknown` if truly needed)
|
||||||
|
- [ ] Interfaces defined for complex objects
|
||||||
|
- [ ] Return types explicitly declared on public methods
|
||||||
|
- [ ] Proper null/undefined handling with optional chaining
|
||||||
|
- [ ] Enums or union types for fixed sets of values
|
||||||
|
|
||||||
|
#### Type Definitions
|
||||||
|
- [ ] Shared types in dedicated types file
|
||||||
|
- [ ] No inline type definitions used multiple times
|
||||||
|
- [ ] Entity state properly typed (position, velocity, attributes)
|
||||||
|
|
||||||
|
### 5. Performance
|
||||||
|
|
||||||
|
#### Hot Path Optimization
|
||||||
|
- [ ] `update()` loops avoid unnecessary allocations
|
||||||
|
- [ ] Object pooling for frequently created/destroyed objects (bullets, particles)
|
||||||
|
- [ ] Minimize garbage collection pressure (reuse objects where possible)
|
||||||
|
- [ ] Expensive calculations cached when appropriate
|
||||||
|
|
||||||
|
#### Phaser Best Practices
|
||||||
|
- [ ] Sprites reused via object pools
|
||||||
|
- [ ] Physics bodies properly cleaned up
|
||||||
|
- [ ] Textures loaded once, referenced many times
|
||||||
|
- [ ] Update loops only process active entities
|
||||||
|
|
||||||
|
### 6. Constants & Configuration
|
||||||
|
|
||||||
|
#### Centralization
|
||||||
|
- [ ] All magic numbers extracted to [constants.ts](src/config/constants.ts)
|
||||||
|
- [ ] Related constants grouped logically (RINK_*, PLAYER_*, PUCK_*)
|
||||||
|
- [ ] Constants documented with units (meters, pixels, seconds)
|
||||||
|
- [ ] Derived constants calculated from base constants
|
||||||
|
|
||||||
|
#### Tunable Values
|
||||||
|
- [ ] Game balance values clearly marked for tuning
|
||||||
|
- [ ] Physics values (speed, acceleration) easy to adjust
|
||||||
|
- [ ] AI behavior probabilities configurable
|
||||||
|
- [ ] Debug flags for visualization toggles
|
||||||
|
|
||||||
|
### 7. Error Handling
|
||||||
|
|
||||||
|
#### Robustness
|
||||||
|
- [ ] Invalid positions clamped/validated
|
||||||
|
- [ ] Division by zero checks
|
||||||
|
- [ ] Null/undefined guards on external data
|
||||||
|
- [ ] Graceful degradation for missing resources
|
||||||
|
|
||||||
|
#### Debugging
|
||||||
|
- [ ] Meaningful console warnings for unexpected states
|
||||||
|
- [ ] Debug visualization available (toggle in constants)
|
||||||
|
- [ ] Assert-like checks in development builds
|
||||||
|
|
||||||
|
### 8. Comments & Documentation
|
||||||
|
|
||||||
|
#### Code Comments
|
||||||
|
- [ ] Complex algorithms explained
|
||||||
|
- [ ] Non-obvious decisions justified
|
||||||
|
- [ ] Public APIs documented (JSDoc style)
|
||||||
|
- [ ] TODOs tracked and dated
|
||||||
|
|
||||||
|
#### Project Documentation
|
||||||
|
- [ ] [CLAUDE.md](CLAUDE.md) reflects current architecture
|
||||||
|
- [ ] [PLAN.md](PLAN.md) updated with completion status
|
||||||
|
- [ ] [NOTES.md](NOTES.md) captures important design decisions
|
||||||
|
- [ ] README accurate for development setup
|
||||||
|
|
||||||
|
### 9. Testing Readiness
|
||||||
|
|
||||||
|
#### Testability
|
||||||
|
- [ ] Pure functions separated from side effects
|
||||||
|
- [ ] Game logic decoupled from Phaser where possible
|
||||||
|
- [ ] Dependency injection for systems (not hardcoded singletons)
|
||||||
|
- [ ] State machines/behavior trees unit-testable
|
||||||
|
|
||||||
|
#### Manual Testing
|
||||||
|
- [ ] Visual debug modes available
|
||||||
|
- [ ] Hot reload works correctly
|
||||||
|
- [ ] No console errors in normal operation
|
||||||
|
- [ ] Performance profiling points identified
|
||||||
|
|
||||||
|
### 10. Git Hygiene
|
||||||
|
|
||||||
|
#### Commit Quality
|
||||||
|
- [ ] Logical, atomic commits
|
||||||
|
- [ ] Clear commit messages
|
||||||
|
- [ ] No commented-out code blocks committed
|
||||||
|
- [ ] No debug console.logs in production code
|
||||||
|
|
||||||
|
#### Branch Management
|
||||||
|
- [ ] Dead branches cleaned up
|
||||||
|
- [ ] Feature branches merged or rebased
|
||||||
|
- [ ] Master/main branch stable
|
||||||
|
|
||||||
|
## Review Process
|
||||||
|
|
||||||
|
### Before Starting Review
|
||||||
|
|
||||||
|
1. **Create a review branch** (optional but recommended)
|
||||||
|
```bash
|
||||||
|
git checkout -b review/phase-N
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Run the build**
|
||||||
|
```bash
|
||||||
|
pnpm run build
|
||||||
|
```
|
||||||
|
Ensure no errors before starting review.
|
||||||
|
|
||||||
|
3. **Document findings** in a `REVIEW_NOTES.md` or GitHub issues
|
||||||
|
|
||||||
|
### During Review
|
||||||
|
|
||||||
|
1. **Scan each section systematically** using checklist above
|
||||||
|
2. **Note issues** with file path and line number
|
||||||
|
3. **Categorize by priority**:
|
||||||
|
- **Critical**: Bugs, type safety issues, performance problems
|
||||||
|
- **Important**: DRY violations, architectural issues
|
||||||
|
- **Nice-to-have**: Better names, additional comments
|
||||||
|
|
||||||
|
4. **Create refactor tasks** for important findings
|
||||||
|
|
||||||
|
### After Review
|
||||||
|
|
||||||
|
1. **Prioritize fixes** (critical → important → nice-to-have)
|
||||||
|
2. **Refactor incrementally** (small, testable changes)
|
||||||
|
3. **Update documentation** if architecture changed
|
||||||
|
4. **Commit refactors separately** from feature work
|
||||||
|
|
||||||
|
## Specific Code Smells to Watch For
|
||||||
|
|
||||||
|
### Hockey Manager Specific
|
||||||
|
|
||||||
|
- **Hardcoded positions**: All positions should derive from constants
|
||||||
|
- **Pixel/meter confusion**: Ensure conversions are correct and consistent
|
||||||
|
- **Missing coordinate validation**: Positions should stay within rink bounds
|
||||||
|
- **Attribute magic numbers**: Player attributes (0-20 scale) should be typed
|
||||||
|
- **Decision probabilities**: AI chances should be in constants, not inline
|
||||||
|
|
||||||
|
### Phaser Specific
|
||||||
|
|
||||||
|
- **Memory leaks**: Sprites/physics bodies not destroyed
|
||||||
|
- **Update loop bloat**: Too much computation in GameScene.update()
|
||||||
|
- **Texture management**: Multiple loads of same texture
|
||||||
|
- **Scale confusion**: Mixing world coordinates with screen coordinates
|
||||||
|
|
||||||
|
### TypeScript Specific
|
||||||
|
|
||||||
|
- **Type assertions**: Excessive use of `as` keyword
|
||||||
|
- **Implicit any**: Missing type annotations
|
||||||
|
- **Non-null assertions**: Overuse of `!` operator
|
||||||
|
- **Enum misuse**: Strings where enums would be clearer
|
||||||
|
|
||||||
|
## Refactoring Patterns
|
||||||
|
|
||||||
|
### Extract Utility Function
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```typescript
|
||||||
|
const dist = Math.sqrt(
|
||||||
|
Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```typescript
|
||||||
|
// In utils/math.ts
|
||||||
|
export function distance(x1: number, y1: number, x2: number, y2: number): number {
|
||||||
|
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extract Constants
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```typescript
|
||||||
|
if (player.speed > 8.5) { // max skating speed
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```typescript
|
||||||
|
// In constants.ts
|
||||||
|
export const MAX_SKATING_SPEED = 8.5; // m/s
|
||||||
|
|
||||||
|
// In code
|
||||||
|
if (player.speed > MAX_SKATING_SPEED) {
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extract Type
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```typescript
|
||||||
|
function updatePlayer(data: { x: number; y: number; team: string }) {
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```typescript
|
||||||
|
// In types.ts
|
||||||
|
interface Position {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Team = 'home' | 'away';
|
||||||
|
|
||||||
|
interface PlayerData {
|
||||||
|
position: Position;
|
||||||
|
team: Team;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlayer(data: PlayerData) {
|
||||||
|
```
|
||||||
|
|
||||||
|
### Simplify Nested Conditionals
|
||||||
|
|
||||||
|
**Before:**
|
||||||
|
```typescript
|
||||||
|
if (hasPuck) {
|
||||||
|
if (inShootingRange) {
|
||||||
|
if (skill > 15) {
|
||||||
|
shoot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**After:**
|
||||||
|
```typescript
|
||||||
|
const canShoot = hasPuck && inShootingRange && skill > 15;
|
||||||
|
if (canShoot) {
|
||||||
|
shoot();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tools & Commands
|
||||||
|
|
||||||
|
### Find Duplicated Code
|
||||||
|
```bash
|
||||||
|
# Search for duplicate function patterns
|
||||||
|
grep -r "function calculateDistance" src/
|
||||||
|
|
||||||
|
# Find magic numbers (numbers not in constants)
|
||||||
|
grep -rE "\b[0-9]+\.?[0-9]*\b" src/ --exclude-dir=config
|
||||||
|
```
|
||||||
|
|
||||||
|
### Count Lines Per File
|
||||||
|
```bash
|
||||||
|
# Find large files that might need splitting
|
||||||
|
find src -name "*.ts" -exec wc -l {} + | sort -rn
|
||||||
|
```
|
||||||
|
|
||||||
|
### TypeScript Strict Checks
|
||||||
|
Ensure `tsconfig.json` has:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
A successful review results in:
|
||||||
|
|
||||||
|
- ✅ All critical issues resolved
|
||||||
|
- ✅ No obvious code duplication
|
||||||
|
- ✅ Constants properly centralized
|
||||||
|
- ✅ Type safety throughout
|
||||||
|
- ✅ Documentation reflects current state
|
||||||
|
- ✅ Build passes without warnings
|
||||||
|
- ✅ Code runs smoothly in dev mode
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Remember**: The goal is maintainable, readable, and performant code. Don't sacrifice clarity for cleverness. When in doubt, be explicit.
|
||||||
585
pnpm-lock.yaml
generated
Normal file
585
pnpm-lock.yaml
generated
Normal file
@ -0,0 +1,585 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
devDependencies:
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^24.6.1
|
||||||
|
version: 24.6.2
|
||||||
|
phaser:
|
||||||
|
specifier: ^3.90.0
|
||||||
|
version: 3.90.0
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.9.3
|
||||||
|
version: 5.9.3
|
||||||
|
vite:
|
||||||
|
specifier: ^5.4.11
|
||||||
|
version: 5.4.20(@types/node@24.6.2)
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.21.5':
|
||||||
|
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.21.5':
|
||||||
|
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.21.5':
|
||||||
|
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.21.5':
|
||||||
|
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.21.5':
|
||||||
|
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.21.5':
|
||||||
|
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.21.5':
|
||||||
|
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.52.3':
|
||||||
|
resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.52.3':
|
||||||
|
resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.52.3':
|
||||||
|
resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.52.3':
|
||||||
|
resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.52.3':
|
||||||
|
resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.52.3':
|
||||||
|
resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.52.3':
|
||||||
|
resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.52.3':
|
||||||
|
resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.52.3':
|
||||||
|
resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.52.3':
|
||||||
|
resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.52.3':
|
||||||
|
resolution: {integrity: sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.52.3':
|
||||||
|
resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.52.3':
|
||||||
|
resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.52.3':
|
||||||
|
resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.52.3':
|
||||||
|
resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.52.3':
|
||||||
|
resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.52.3':
|
||||||
|
resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.52.3':
|
||||||
|
resolution: {integrity: sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.52.3':
|
||||||
|
resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.52.3':
|
||||||
|
resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.52.3':
|
||||||
|
resolution: {integrity: sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.52.3':
|
||||||
|
resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@types/estree@1.0.8':
|
||||||
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
|
'@types/node@24.6.2':
|
||||||
|
resolution: {integrity: sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang==}
|
||||||
|
|
||||||
|
esbuild@0.21.5:
|
||||||
|
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
eventemitter3@5.0.1:
|
||||||
|
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
nanoid@3.3.11:
|
||||||
|
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||||
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
phaser@3.90.0:
|
||||||
|
resolution: {integrity: sha512-/cziz/5ZIn02uDkC9RzN8VF9x3Gs3XdFFf9nkiMEQT3p7hQlWuyjy4QWosU802qqno2YSLn2BfqwOKLv/sSVfQ==}
|
||||||
|
|
||||||
|
picocolors@1.1.1:
|
||||||
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
rollup@4.52.3:
|
||||||
|
resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==}
|
||||||
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
source-map-js@1.2.1:
|
||||||
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
typescript@5.9.3:
|
||||||
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
undici-types@7.13.0:
|
||||||
|
resolution: {integrity: sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==}
|
||||||
|
|
||||||
|
vite@5.4.20:
|
||||||
|
resolution: {integrity: sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==}
|
||||||
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@types/node': ^18.0.0 || >=20.0.0
|
||||||
|
less: '*'
|
||||||
|
lightningcss: ^1.21.0
|
||||||
|
sass: '*'
|
||||||
|
sass-embedded: '*'
|
||||||
|
stylus: '*'
|
||||||
|
sugarss: '*'
|
||||||
|
terser: ^5.4.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
less:
|
||||||
|
optional: true
|
||||||
|
lightningcss:
|
||||||
|
optional: true
|
||||||
|
sass:
|
||||||
|
optional: true
|
||||||
|
sass-embedded:
|
||||||
|
optional: true
|
||||||
|
stylus:
|
||||||
|
optional: true
|
||||||
|
sugarss:
|
||||||
|
optional: true
|
||||||
|
terser:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.21.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.52.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
|
'@types/node@24.6.2':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 7.13.0
|
||||||
|
|
||||||
|
esbuild@0.21.5:
|
||||||
|
optionalDependencies:
|
||||||
|
'@esbuild/aix-ppc64': 0.21.5
|
||||||
|
'@esbuild/android-arm': 0.21.5
|
||||||
|
'@esbuild/android-arm64': 0.21.5
|
||||||
|
'@esbuild/android-x64': 0.21.5
|
||||||
|
'@esbuild/darwin-arm64': 0.21.5
|
||||||
|
'@esbuild/darwin-x64': 0.21.5
|
||||||
|
'@esbuild/freebsd-arm64': 0.21.5
|
||||||
|
'@esbuild/freebsd-x64': 0.21.5
|
||||||
|
'@esbuild/linux-arm': 0.21.5
|
||||||
|
'@esbuild/linux-arm64': 0.21.5
|
||||||
|
'@esbuild/linux-ia32': 0.21.5
|
||||||
|
'@esbuild/linux-loong64': 0.21.5
|
||||||
|
'@esbuild/linux-mips64el': 0.21.5
|
||||||
|
'@esbuild/linux-ppc64': 0.21.5
|
||||||
|
'@esbuild/linux-riscv64': 0.21.5
|
||||||
|
'@esbuild/linux-s390x': 0.21.5
|
||||||
|
'@esbuild/linux-x64': 0.21.5
|
||||||
|
'@esbuild/netbsd-x64': 0.21.5
|
||||||
|
'@esbuild/openbsd-x64': 0.21.5
|
||||||
|
'@esbuild/sunos-x64': 0.21.5
|
||||||
|
'@esbuild/win32-arm64': 0.21.5
|
||||||
|
'@esbuild/win32-ia32': 0.21.5
|
||||||
|
'@esbuild/win32-x64': 0.21.5
|
||||||
|
|
||||||
|
eventemitter3@5.0.1: {}
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
nanoid@3.3.11: {}
|
||||||
|
|
||||||
|
phaser@3.90.0:
|
||||||
|
dependencies:
|
||||||
|
eventemitter3: 5.0.1
|
||||||
|
|
||||||
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.11
|
||||||
|
picocolors: 1.1.1
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
rollup@4.52.3:
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
optionalDependencies:
|
||||||
|
'@rollup/rollup-android-arm-eabi': 4.52.3
|
||||||
|
'@rollup/rollup-android-arm64': 4.52.3
|
||||||
|
'@rollup/rollup-darwin-arm64': 4.52.3
|
||||||
|
'@rollup/rollup-darwin-x64': 4.52.3
|
||||||
|
'@rollup/rollup-freebsd-arm64': 4.52.3
|
||||||
|
'@rollup/rollup-freebsd-x64': 4.52.3
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf': 4.52.3
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf': 4.52.3
|
||||||
|
'@rollup/rollup-linux-arm64-gnu': 4.52.3
|
||||||
|
'@rollup/rollup-linux-arm64-musl': 4.52.3
|
||||||
|
'@rollup/rollup-linux-loong64-gnu': 4.52.3
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu': 4.52.3
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu': 4.52.3
|
||||||
|
'@rollup/rollup-linux-riscv64-musl': 4.52.3
|
||||||
|
'@rollup/rollup-linux-s390x-gnu': 4.52.3
|
||||||
|
'@rollup/rollup-linux-x64-gnu': 4.52.3
|
||||||
|
'@rollup/rollup-linux-x64-musl': 4.52.3
|
||||||
|
'@rollup/rollup-openharmony-arm64': 4.52.3
|
||||||
|
'@rollup/rollup-win32-arm64-msvc': 4.52.3
|
||||||
|
'@rollup/rollup-win32-ia32-msvc': 4.52.3
|
||||||
|
'@rollup/rollup-win32-x64-gnu': 4.52.3
|
||||||
|
'@rollup/rollup-win32-x64-msvc': 4.52.3
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
|
undici-types@7.13.0: {}
|
||||||
|
|
||||||
|
vite@5.4.20(@types/node@24.6.2):
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.21.5
|
||||||
|
postcss: 8.5.6
|
||||||
|
rollup: 4.52.3
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/node': 24.6.2
|
||||||
|
fsevents: 2.3.3
|
||||||
@ -25,3 +25,7 @@ export const COLOR_GOAL_CREASE = 0x87ceeb;
|
|||||||
|
|
||||||
// Game settings
|
// Game settings
|
||||||
export const FPS = 60;
|
export const FPS = 60;
|
||||||
|
export const DEBUG = true;
|
||||||
|
|
||||||
|
// Player movement
|
||||||
|
export const PLAYER_ROTATION_SPEED = 1; // radians per second
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import Phaser from 'phaser';
|
import Phaser from 'phaser';
|
||||||
import { SCALE } from '../config/constants';
|
import { SCALE, PLAYER_ROTATION_SPEED } from '../config/constants';
|
||||||
|
|
||||||
export type PlayerPosition = 'LW' | 'C' | 'RW' | 'LD' | 'RD' | 'G';
|
export type PlayerPosition = 'LW' | 'C' | 'RW' | 'LD' | 'RD' | 'G';
|
||||||
export type TeamSide = 'home' | 'away';
|
export type TeamSide = 'home' | 'away';
|
||||||
@ -33,6 +33,9 @@ export class Player extends Phaser.GameObjects.Container {
|
|||||||
public state: PlayerState;
|
public state: PlayerState;
|
||||||
private speedMultiplier: number = 1.0;
|
private speedMultiplier: number = 1.0;
|
||||||
|
|
||||||
|
// Rotation (angle in radians, 0 = facing right)
|
||||||
|
private currentAngle: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scene: Phaser.Scene,
|
scene: Phaser.Scene,
|
||||||
id: string,
|
id: string,
|
||||||
@ -73,20 +76,6 @@ export class Player extends Phaser.GameObjects.Container {
|
|||||||
this.body.setOffset(-radius, -radius); // Center the body on the container
|
this.body.setOffset(-radius, -radius); // Center the body on the container
|
||||||
this.body.setCollideWorldBounds(true);
|
this.body.setCollideWorldBounds(true);
|
||||||
|
|
||||||
// Set up physics-based movement
|
|
||||||
// Max velocity based on speed attribute (e.g., speed 80 -> 8 m/s = 160 px/s)
|
|
||||||
const maxSpeed = (this.attributes.speed / 10) * SCALE;
|
|
||||||
this.body.setMaxVelocity(maxSpeed, maxSpeed);
|
|
||||||
|
|
||||||
// Drag simulates ice friction (higher = more friction)
|
|
||||||
// Lower drag = more gliding (realistic for ice)
|
|
||||||
this.body.setDrag(100, 100);
|
|
||||||
|
|
||||||
// Acceleration determines how quickly player reaches max speed
|
|
||||||
// Higher skill = better acceleration control
|
|
||||||
const acceleration = (this.attributes.skill / 10) * SCALE * 10;
|
|
||||||
this.body.setAcceleration(0, 0); // Will be set each frame based on target
|
|
||||||
|
|
||||||
this.createSprite();
|
this.createSprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,9 +151,55 @@ export class Player extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update player movement each frame (physics-based)
|
* Update player movement each frame
|
||||||
*/
|
*/
|
||||||
public update(_delta: number) {
|
public update(delta: number) {
|
||||||
|
// Calculate distance to target
|
||||||
|
const dx = this.targetX - this.gameX;
|
||||||
|
const dy = this.targetY - this.gameY;
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
// If close enough to target, stop
|
||||||
|
if (distance < 0.1) {
|
||||||
|
this.body.setVelocity(0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate desired angle toward target
|
||||||
|
const targetAngle = Math.atan2(dy, dx);
|
||||||
|
|
||||||
|
// Smoothly rotate toward target angle
|
||||||
|
const deltaSeconds = delta / 1000;
|
||||||
|
const maxRotation = PLAYER_ROTATION_SPEED * deltaSeconds;
|
||||||
|
|
||||||
|
// Calculate shortest angular difference
|
||||||
|
let angleDiff = targetAngle - this.currentAngle;
|
||||||
|
// Normalize to [-PI, PI]
|
||||||
|
while (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
|
||||||
|
while (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
|
||||||
|
|
||||||
|
// Apply rotation with limit
|
||||||
|
const rotationStep = Math.sign(angleDiff) * Math.min(Math.abs(angleDiff), maxRotation);
|
||||||
|
this.currentAngle += rotationStep;
|
||||||
|
|
||||||
|
// Normalize current angle
|
||||||
|
while (this.currentAngle > Math.PI) this.currentAngle -= Math.PI * 2;
|
||||||
|
while (this.currentAngle < -Math.PI) this.currentAngle += Math.PI * 2;
|
||||||
|
|
||||||
|
// Update visual rotation (convert to degrees, subtract 90 because 0 angle is up in Phaser)
|
||||||
|
this.setRotation(-this.currentAngle);
|
||||||
|
|
||||||
|
// Calculate velocity based on current facing direction and speed attribute
|
||||||
|
// speed attribute (0-100) maps to actual m/s (e.g., 80 -> 8 m/s)
|
||||||
|
const baseSpeed = (this.attributes.speed / 10) * SCALE; // Convert to pixels/s
|
||||||
|
const speed = baseSpeed * this.speedMultiplier; // Apply speed multiplier
|
||||||
|
|
||||||
|
// Move in the direction the player is currently facing
|
||||||
|
const velX = Math.cos(this.currentAngle) * speed;
|
||||||
|
const velY = Math.sin(this.currentAngle) * speed;
|
||||||
|
|
||||||
|
this.body.setVelocity(velX, -velY); // Negative Y because screen coords
|
||||||
|
|
||||||
// Update game position based on physics body center
|
// Update game position based on physics body center
|
||||||
const centerX = (this.scene.game.config.width as number) / 2;
|
const centerX = (this.scene.game.config.width as number) / 2;
|
||||||
const centerY = (this.scene.game.config.height as number) / 2;
|
const centerY = (this.scene.game.config.height as number) / 2;
|
||||||
@ -172,28 +207,5 @@ export class Player extends Phaser.GameObjects.Container {
|
|||||||
const bodyY = this.body.y + this.body.height / 2;
|
const bodyY = this.body.y + this.body.height / 2;
|
||||||
this.gameX = (bodyX - centerX) / SCALE;
|
this.gameX = (bodyX - centerX) / SCALE;
|
||||||
this.gameY = -(bodyY - centerY) / SCALE;
|
this.gameY = -(bodyY - centerY) / SCALE;
|
||||||
|
|
||||||
// Calculate distance to target
|
|
||||||
const dx = this.targetX - this.gameX;
|
|
||||||
const dy = this.targetY - this.gameY;
|
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
||||||
|
|
||||||
// If close enough to target, reduce acceleration (coast)
|
|
||||||
if (distance < 1.0) {
|
|
||||||
this.body.setAcceleration(0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate acceleration direction toward target
|
|
||||||
const dirX = dx / distance;
|
|
||||||
const dirY = dy / distance;
|
|
||||||
|
|
||||||
// Acceleration magnitude based on skill attribute and speed multiplier
|
|
||||||
// Higher skill = better acceleration (more responsive)
|
|
||||||
const baseAcceleration = (this.attributes.skill / 10) * SCALE * 10;
|
|
||||||
const acceleration = baseAcceleration * this.speedMultiplier;
|
|
||||||
|
|
||||||
// Apply acceleration toward target (negative Y for screen coords)
|
|
||||||
this.body.setAcceleration(dirX * acceleration, -dirY * acceleration);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Phaser from 'phaser';
|
import Phaser from 'phaser';
|
||||||
import { GameScene } from './GameScene';
|
import { GameScene } from './GameScene';
|
||||||
import { RINK_LENGTH, RINK_WIDTH, SCALE, FPS } from '../config/constants';
|
import { RINK_LENGTH, RINK_WIDTH, SCALE, FPS, DEBUG } from '../config/constants';
|
||||||
|
|
||||||
const config: Phaser.Types.Core.GameConfig = {
|
const config: Phaser.Types.Core.GameConfig = {
|
||||||
type: Phaser.AUTO,
|
type: Phaser.AUTO,
|
||||||
@ -12,7 +12,7 @@ const config: Phaser.Types.Core.GameConfig = {
|
|||||||
default: 'arcade',
|
default: 'arcade',
|
||||||
arcade: {
|
arcade: {
|
||||||
gravity: { x: 0, y: 0 },
|
gravity: { x: 0, y: 0 },
|
||||||
debug: true
|
debug: DEBUG
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fps: {
|
fps: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user