nordic-skating / mistral-medium-35-littlejs / files / LITTLEJS_CONVERSION_PLAN.md
Branch mistral-medium-35-littlejs · default branch · all branches
LITTLEJS_CONVERSION_PLAN.md
185c6976 2026-10-19 Pavel Safronov | 1 | # LittleJS Conversion Plan for Nordic Skating |
| 2 | ||
| 3 | ## Overview | |
| 4 | ||
| 5 | This document outlines a comprehensive plan to migrate the Nordic Skating project from its current Three.js-based architecture to **LittleJS**, a tiny fast JavaScript game engine with 2D/3D capabilities. | |
| 6 | ||
| 7 | ### Key Insight: LittleJS Three.js Plugin | |
| 8 | ||
| 9 | LittleJS has a **Three.js plugin** that allows using Three.js as an alternative renderer. This means: | |
| 10 | - We can **keep the existing Three.js rendering code** largely intact | |
| 11 | - We gain LittleJS's game loop, input system, scene management, audio, and other features | |
| 12 | - We get built-in mobile support, touch controls, and better performance management | |
| 13 | - The engine handles the animation loop, delta time, and frame rate independence | |
| 14 | ||
| 15 | ### Why Migrate? | |
| 16 | ||
| 17 | 1. **Simplified Architecture**: LittleJS provides a unified framework for game development | |
| 18 | 2. **Better Input Handling**: Built-in support for keyboard, mouse, touch, gamepads, and device orientation | |
| 19 | 3. **Audio System**: Built-in audio with ZzFX sound generation (could supplement or replace current Web Audio) | |
| 20 | 4. **Scene Management**: Built-in scene system for menus, game states, etc. | |
| 21 | 5. **Mobile Optimization**: Designed for mobile devices with touch controls | |
| 22 | 6. **Performance**: Optimized game loop and rendering | |
| 23 | 7. **Tooling**: Built-in level editors, debug tools, particle systems | |
| 24 | 8. **Size**: Small footprint (~135KB minified, but bundlers can tree-shake unused features) | |
| 25 | ||
| 26 | --- | |
| 27 | ||
| 28 | ## Current Architecture Analysis | |
| 29 | ||
| 30 | ### Current Tech Stack | |
| 31 | - **Rendering**: Three.js (WebGL-based 3D rendering) | |
| 32 | - **Build**: Vite with TypeScript | |
| 33 | - **Audio**: Web Audio API (custom ice sound synthesis) | |
| 34 | - **Input**: Custom implementation for keyboard, mouse, touch, gamepad, device orientation | |
| 35 | - **World Generation**: Procedural lake generation with noise functions | |
| 36 | - **Physics**: Custom skater physics and ice acoustics | |
| 37 | - **State Management**: Custom history/state handling for lake seeds | |
| 38 | ||
| 39 | ### Core Systems | |
| 40 | ||
| 41 | 1. **World/Lake System** (`src/world/lake.ts`) | |
| 42 | - Procedural channel generation | |
| 43 | - Ice thickness calculation | |
| 44 | - Islet and island generation | |
| 45 | - Fork handling | |
| 46 | ||
| 47 | 2. **Skater System** (`src/skater.ts`) | |
| 48 | - Position, direction, speed management | |
| 49 | - Steering and turning physics | |
| 50 | - Autopilot logic | |
| 51 | - Stride and push mechanics | |
| 52 | ||
| 53 | 3. **Rendering System** (`src/render/`) | |
| 54 | - Ice rendering with dynamic textures | |
| 55 | - Shore/bank rendering | |
| 56 | - Sky and weather effects | |
| 57 | - Snow and drifts | |
| 58 | - Marks (tracks, cracks) | |
| 59 | ||
| 60 | 4. **Audio System** (`src/audio/iceSound.ts`) | |
| 61 | - Custom Web Audio synthesis | |
| 62 | - Ice singing, cracking, striking sounds | |
| 63 | - Wind and snow sounds | |
| 64 | - Physics-based sound generation | |
| 65 | ||
| 66 | 5. **Input System** (`src/input.ts`) | |
| 67 | - Keyboard, mouse, touch | |
| 68 | - Gamepad support | |
| 69 | - Device orientation (tilt steering) | |
| 70 | ||
| 71 | 6. **UI System** | |
| 72 | - Settings dialog | |
| 73 | - About dialog | |
| 74 | - Sound, pace, tilt, randomize buttons | |
| 75 | - Responsive design | |
| 76 | ||
| 77 | --- | |
| 78 | ||
| 79 | ## Conversion Strategy | |
| 80 | ||
| 81 | ### Phase 1: Preparation and Setup (1-2 days) | |
| 82 | ||
| 83 | #### 1.1 Install LittleJS | |
| 84 | ```bash | |
| 85 | npm install littlejsengine | |
| 86 | ``` | |
| 87 | ||
| 88 | #### 1.2 Update package.json | |
| 89 | ```json | |
| 90 | { | |
| 91 | "dependencies": { | |
| 92 | "littlejsengine": "^latest", | |
| 93 | "simplex-noise": "^4.0.3", | |
| 94 | "three": "^0.180.0" | |
| 95 | } | |
| 96 | } | |
| 97 | ``` | |
| 98 | ||
| 99 | #### 1.3 Create LittleJS Entry Point | |
| 100 | Create `src/littlejs-entry.ts` as the new main entry point: | |
| 101 | ```typescript | |
| 102 | import { engineInit, gameInit, gameUpdate, gameRender } from 'littlejsengine' | |
| 103 | import { main } from './main-littlejs' | |
| 104 | ||
| 105 | // Initialize LittleJS with our game functions | |
| 106 | engineInit( | |
| 107 | () => main.init(), | |
| 108 | () => main.update(), | |
| 109 | () => main.updatePost(), | |
| 110 | () => main.render(), | |
| 111 | () => main.renderPost() | |
| 112 | ) | |
| 113 | ``` | |
| 114 | ||
| 115 | #### 1.4 Update HTML Entry Point | |
| 116 | Update `index.html` to use LittleJS: | |
| 117 | ```html | |
| 118 | <!DOCTYPE html> | |
| 119 | <html> | |
| 120 | <head> | |
| 121 | <meta charset="UTF-8"> | |
| 122 | <title>Nordic Skating</title> | |
| 123 | <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
| 124 | </head> | |
| 125 | <body> | |
| 126 | <canvas id="littlejsCanvas"></canvas> | |
| 127 | <script type="module" src="/src/littlejs-entry.ts"></script> | |
| 128 | </body> | |
| 129 | </html> | |
| 130 | ``` | |
| 131 | ||
| 132 | ### Phase 2: Core Engine Integration (2-3 days) | |
| 133 | ||
| 134 | #### 2.1 Initialize LittleJS with Three.js Plugin | |
| 135 | ```typescript | |
| 136 | // src/main-littlejs.ts | |
| 137 | import * as THREE from 'three' | |
| 138 | import { engine, setThreeRenderer } from 'littlejsengine' | |
| 139 | import { Lake } from './world/lake' | |
| 140 | import { Skater } from './skater' | |
| 141 | ||
| 142 | class NordicSkatingGame { | |
| 143 | private lake: Lake | |
| 144 | private skater: Skater | |
| 145 | private scene: THREE.Scene | |
| 146 | private camera: THREE.PerspectiveCamera | |
| 147 | private renderer: THREE.WebGLRenderer | |
| 148 | ||
| 149 | init(): void { | |
| 150 | // Initialize LittleJS | |
| 151 | engineInit(this.gameInit, this.gameUpdate, this.gameUpdatePost, | |
| 152 | this.gameRender, this.gameRenderPost) | |
| 153 | ||
| 154 | // Set up Three.js renderer for LittleJS | |
| 155 | setThreeRenderer(THREE) | |
| 156 | ||
| 157 | // Create Three.js scene | |
| 158 | this.scene = new THREE.Scene() | |
| 159 | this.camera = new THREE.PerspectiveCamera(70, 1, 0.1, 1500) | |
| 160 | this.camera.rotation.order = 'YXZ' | |
| 161 | ||
| 162 | // Initialize world | |
| 163 | this.lake = createLake(12345, { impossibleIce: false }) | |
| 164 | this.skater = createSkater(this.lake, 0) | |
| 165 | ||
| 166 | // Set up fog (matches current implementation) | |
| 167 | this.scene.fog = new THREE.Fog(0, 30, 600) | |
| 168 | this.scene.background = this.scene.fog.color | |
| 169 | } | |
| 170 | ||
| 171 | gameInit(): void { | |
| 172 | // Called by LittleJS on initialization | |
| 173 | } | |
| 174 | ||
| 175 | gameUpdate(): void { | |
| 176 | // Handle input, update skater, world, etc. | |
| 177 | } | |
| 178 | ||
| 179 | gameRender(): void { | |
| 180 | // Render the scene | |
| 181 | renderer.render(this.scene, this.camera) | |
| 182 | } | |
| 183 | } | |
| 184 | ||
| 185 | export const main = new NordicSkatingGame() | |
| 186 | ``` | |
| 187 | ||
| 188 | #### 2.2 Map Input Systems | |
| 189 | ||
| 190 | **Current Input:** | |
| 191 | - Keyboard (Arrow keys, WASD, M, R) | |
| 192 | - Mouse/Touch drag for steering | |
| 193 | - Gamepad buttons and sticks | |
| 194 | - Device orientation (tilt steering) | |
| 195 | ||
| 196 | **LittleJS Input Mapping:** | |
| 197 | ```typescript | |
| 198 | // In gameUpdate() | |
| 199 | const steer = inputGetState('arrowLeft') - inputGetState('arrowRight') | |
| 200 | + inputGetState('a') - inputGetState('d') | |
| 201 | + inputGetAxis('mouseX') * 0.1 // Mouse/touch | |
| 202 | + inputGetAxis('gamepadLeftX') // Gamepad | |
| 203 | + inputGetAxis('deviceOrientationGamma') * 0.05 // Tilt | |
| 204 | ||
| 205 | const muted = inputGetPressed('m') | |
| 206 | const randomize = inputGetPressed('r') | |
| 207 | ``` | |
| 208 | ||
| 209 | **Note:** LittleJS has built-in device orientation support that we can use instead of our custom implementation. | |
| 210 | ||
| 211 | #### 2.3 Integrate Audio System | |
| 212 | ||
| 213 | **Option A: Keep Current Web Audio (Recommended)** | |
| 214 | The current audio system is highly specialized for ice physics. We can keep it and just trigger it from LittleJS's game loop. | |
| 215 | ||
| 216 | **Option B: Migrate to LittleJS Audio** | |
| 217 | LittleJS has a simpler audio system. We'd need to port the ice acoustics synthesis. | |
| 218 | ||
| 219 | **Recommendation:** Start with Option A, as the current audio is complex and physics-based. Later consider if LittleJS's audio effects can supplement it. | |
| 220 | ||
| 221 | ### Phase 3: Scene and Rendering Migration (3-5 days) | |
| 222 | ||
| 223 | #### 3.1 Camera System | |
| 224 | ||
| 225 | **Current:** | |
| 226 | - First-person camera following skater | |
| 227 | - Dynamic FOV based on speed | |
| 228 | - Pitch and heading calculations | |
| 229 | ||
| 230 | **LittleJS Integration:** | |
| 231 | ```typescript | |
| 232 | gameRender(): void { | |
| 233 | // Update camera position based on skater | |
| 234 | const push = this.skater.under === 0 && sincePush(this.skater) < pushFor | |
| 235 | ? Math.sin((Math.PI * sincePush(this.skater)) / pushFor) : 0 | |
| 236 | ||
| 237 | const hurry = (this.skater.speed - PACES.cruise.speed) / | |
| 238 | (PACES.olympic.speed - PACES.cruise.speed) | |
| 239 | const crouch = hurry > 0 ? PACES.olympic.crouch * hurry : | |
| 240 | PACES.meander.crouch * Math.min(1, -hurry * 2.3) | |
| 241 | const fov = baseFov + 12 * Math.max(-0.4, Math.min(1.1, hurry)) | |
| 242 | ||
| 243 | camera.fov = fov | |
| 244 | camera.aspect = engine.canvas.width / engine.canvas.height | |
| 245 | camera.updateProjectionMatrix() | |
| 246 | ||
| 247 | const along = Math.atan(this.skater.channel.slope(this.skater.s)) | |
| 248 | const look = this.skater.heading - 0.25 * Math.sin(this.skater.heading - along) | |
| 249 | camera.position.set( | |
| 250 | this.skater.x, | |
| 251 | EYE - crouch + 0.03 * push - 1.3 * sunk, | |
| 252 | this.skater.s | |
| 253 | ) | |
| 254 | camera.rotation.set(-pitch, -look, -0.02 * this.skater.turn * this.skater.speed) | |
| 255 | ||
| 256 | renderer.render(scene, camera) | |
| 257 | } | |
| 258 | ``` | |
| 259 | ||
| 260 | #### 3.2 World Rendering Components | |
| 261 | ||
| 262 | **Ice Rendering** (`src/render/ice.ts`): | |
| 263 | - Keep as Three.js mesh | |
| 264 | - Integrate into LittleJS render loop | |
| 265 | - Update texture coordinates based on skater position | |
| 266 | ||
| 267 | **Shores Rendering** (`src/render/shores.ts`): | |
| 268 | - Keep current Three.js implementation | |
| 269 | - Update chunk management in gameUpdate() | |
| 270 | ||
| 271 | **Sky Rendering** (`src/render/sky.ts`): | |
| 272 | - Keep as Three.js mesh with shaders | |
| 273 | - Update time-based animations in gameUpdate() | |
| 274 | ||
| 275 | **Snow and Drifts** (`src/render/snow.ts`, `src/render/drifts.ts`): | |
| 276 | - Keep current particle systems | |
| 277 | - Integrate with LittleJS particle system if beneficial | |
| 278 | ||
| 279 | **Marks** (`src/render/marks.ts`): | |
| 280 | - Keep current implementation | |
| 281 | - Update based on skater position | |
| 282 | ||
| 283 | ### Phase 4: Game Logic Integration (2-3 days) | |
| 284 | ||
| 285 | #### 4.1 Skater Physics | |
| 286 | ||
| 287 | Port the skater update logic to use LittleJS's delta time: | |
| 288 | ```typescript | |
| 289 | gameUpdate(): void { | |
| 290 | const dt = engine.timing.lastTimeStep | |
| 291 | ||
| 292 | // Update skater | |
| 293 | const steer = this.getSteeringInput() | |
| 294 | stepSkater(this.skater, this.lake, steer, dt) | |
| 295 | ||
| 296 | // Update marks | |
| 297 | marks.follow(this.skater.x, this.skater.s, dt) | |
| 298 | if (dt > 0) marks.track(this.skater.x, this.skater.s) | |
| 299 | ||
| 300 | // Check for pushes | |
| 301 | const pushed = Math.floor(this.skater.stride) !== strides | |
| 302 | if (pushed) { | |
| 303 | marks.push(this.skater.x, this.skater.s, this.skater.heading, | |
| 304 | Math.floor(this.skater.stride) % 2 ? 1 : -1) | |
| 305 | } | |
| 306 | } | |
| 307 | ``` | |
| 308 | ||
| 309 | #### 4.2 Lake Generation | |
| 310 | ||
| 311 | Keep the procedural lake generation as-is. It's already frame-independent and seed-based. | |
| 312 | ||
| 313 | #### 4.3 Weather and Time Systems | |
| 314 | ||
| 315 | Integrate with LittleJS's timing system: | |
| 316 | ```typescript | |
| 317 | // In gameUpdate() | |
| 318 | const weather = this.getCurrentWeather() | |
| 319 | const timeOfDay = this.getCurrentTime() | |
| 320 | ||
| 321 | // Update sky based on time | |
| 322 | sky.update(engine.timing.time) | |
| 323 | ||
| 324 | // Update wind | |
| 325 | const blowing = weather.wind[0] + | |
| 326 | (weather.wind[1] - weather.wind[0]) * | |
| 327 | (0.5 + 0.5 * Math.sin(engine.timing.time * 0.23) * | |
| 328 | Math.sin(engine.timing.time * 0.071 + 1)) | |
| 329 | ``` | |
| 330 | ||
| 331 | ### Phase 5: UI Migration (2-3 days) | |
| 332 | ||
| 333 | #### 5.1 Settings and About Dialogs | |
| 334 | ||
| 335 | **Option A: Use LittleJS UI System** | |
| 336 | LittleJS has a basic UI system with buttons, sliders, etc. We can use this for the settings dialog. | |
| 337 | ||
| 338 | **Option B: Keep Current HTML/CSS UI** | |
| 339 | Keep the existing dialog elements and just trigger them from LittleJS input. | |
| 340 | ||
| 341 | **Recommendation:** Start with Option B for faster migration, then consider Option A for future enhancements. | |
| 342 | ||
| 343 | #### 5.2 Buttons and Controls | |
| 344 | ||
| 345 | Map current buttons to LittleJS: | |
| 346 | - Sound button: `inputGetPressed('m')` or UI button | |
| 347 | - Randomize: `inputGetPressed('r')` or UI button | |
| 348 | - Pace: UI button or keyboard | |
| 349 | - Tilt: UI button | |
| 350 | - Settings: UI button | |
| 351 | - About: UI button | |
| 352 | ||
| 353 | #### 5.3 HUD Elements | |
| 354 | ||
| 355 | LittleJS has built-in text rendering: | |
| 356 | ```typescript | |
| 357 | gameRenderPost(): void { | |
| 358 | // Draw HUD elements | |
| 359 | drawTextScreen(`Speed: ${Math.round(this.skater.speed * 3.6)} km/h`, | |
| 360 | vec2(10, 10), 20, colorWhite) | |
| 361 | ||
| 362 | // Draw hints | |
| 363 | if (this.showHint) { | |
| 364 | drawTextScreen(this.hintText, vec2(centerX, 100), 30, colorWhite) | |
| 365 | } | |
| 366 | } | |
| 367 | ``` | |
| 368 | ||
| 369 | ### Phase 6: State Management (1-2 days) | |
| 370 | ||
| 371 | #### 6.1 Lake Seed and History | |
| 372 | ||
| 373 | **Current:** Uses browser history API to manage lake seeds | |
| 374 | ||
| 375 | **LittleJS Integration:** | |
| 376 | - Keep history API usage | |
| 377 | - Or use LittleJS's scene system for different "levels" | |
| 378 | ||
| 379 | **Recommendation:** Keep current approach as it works well for sharing links. | |
| 380 | ||
| 381 | #### 6.2 Settings Persistence | |
| 382 | ||
| 383 | Keep current localStorage approach, it's working well. | |
| 384 | ||
| 385 | ### Phase 7: Audio Integration (2-3 days) | |
| 386 | ||
| 387 | #### 7.1 Ice Sound System | |
| 388 | ||
| 389 | **Keep Current Implementation:** | |
| 390 | The ice sound synthesis is complex and physics-based. It should remain as Web Audio API code. | |
| 391 | ||
| 392 | **Integration:** | |
| 393 | ```typescript | |
| 394 | // In gameInit() | |
| 395 | audio = new AudioContext() | |
| 396 | sound = new IceSound(audio) | |
| 397 | ||
| 398 | // In gameUpdate() | |
| 399 | if (sounding()) { | |
| 400 | sound.wind(blowing) | |
| 401 | sound.glide(thickness, pushAmount) | |
| 402 | sound.strike(thickness) | |
| 403 | // etc. | |
| 404 | } | |
| 405 | ``` | |
| 406 | ||
| 407 | **Note:** Need to handle audio context suspend/resume based on user interaction. | |
| 408 | ||
| 409 | #### 7.2 Sound Button | |
| 410 | ||
| 411 | ```typescript | |
| 412 | // In gameUpdate() | |
| 413 | if (inputGetPressed('m')) { | |
| 414 | setMuted(!muted) | |
| 415 | } | |
| 416 | ``` | |
| 417 | ||
| 418 | ### Phase 8: Testing and Optimization (3-5 days) | |
| 419 | ||
| 420 | #### 8.1 Input Testing | |
| 421 | - Test all input methods (keyboard, mouse, touch, gamepad, tilt) | |
| 422 | - Verify steering feel is preserved | |
| 423 | - Test on mobile devices | |
| 424 | ||
| 425 | #### 8.2 Performance Testing | |
| 426 | - Verify frame rate on desktop and mobile | |
| 427 | - Check memory usage | |
| 428 | - Test with various lake complexities | |
| 429 | ||
| 430 | #### 8.3 Audio Testing | |
| 431 | - Verify all ice sounds work correctly | |
| 432 | - Test wind and weather sounds | |
| 433 | - Check audio on mobile devices | |
| 434 | ||
| 435 | #### 8.4 Visual Testing | |
| 436 | - Verify ice rendering at all distances | |
| 437 | - Check shore and island rendering | |
| 438 | - Test sky and weather effects | |
| 439 | - Verify marks (tracks, cracks) rendering | |
| 440 | ||
| 441 | ### Phase 9: Cleanup and Documentation (1-2 days) | |
| 442 | ||
| 443 | #### 9.1 Code Cleanup | |
| 444 | - Remove deprecated code | |
| 445 | - Update comments | |
| 446 | - Ensure consistent code style | |
| 447 | ||
| 448 | #### 9.2 Update Documentation | |
| 449 | - Update README with new LittleJS-based instructions | |
| 450 | - Update build and run instructions | |
| 451 | - Document any changes in behavior | |
| 452 | ||
| 453 | #### 9.3 Final Testing | |
| 454 | - Full regression testing | |
| 455 | - Performance benchmarking | |
| 456 | - Mobile device testing | |
| 457 | ||
| 458 | --- | |
| 459 | ||
| 460 | ## Detailed File Migration Plan | |
| 461 | ||
| 462 | ### Core Files to Create/Modify | |
| 463 | ||
| 464 | 1. **`src/littlejs-entry.ts`** (New) | |
| 465 | - LittleJS engine initialization | |
| 466 | - Entry point for the application | |
| 467 | ||
| 468 | 2. **`src/main-littlejs.ts`** (New, replaces `src/main.ts`) | |
| 469 | - Main game class | |
| 470 | - Initializes all systems | |
| 471 | - Manages game loop | |
| 472 | ||
| 473 | 3. **`src/game-config.ts`** (New) | |
| 474 | - Game configuration constants | |
| 475 | - LittleJS engine settings | |
| 476 | ||
| 477 | ### Files to Adapt | |
| 478 | ||
| 479 | 1. **`src/world/lake.ts`** (Minimal changes) | |
| 480 | - Keep as-is, may need to adjust imports | |
| 481 | - Ensure compatible with ESM | |
| 482 | ||
| 483 | 2. **`src/skater.ts`** (Minimal changes) | |
| 484 | - Keep physics logic | |
| 485 | - May need to adjust timing to use LittleJS delta time | |
| 486 | ||
| 487 | 3. **`src/render/*.ts`** (Minimal changes) | |
| 488 | - Keep Three.js rendering code | |
| 489 | - May need to adjust how they're instantiated | |
| 490 | ||
| 491 | 4. **`src/audio/iceSound.ts`** (Minimal changes) | |
| 492 | - Keep Web Audio implementation | |
| 493 | - Adjust how it's triggered | |
| 494 | ||
| 495 | 5. **`src/input.ts`** (Significant changes) | |
| 496 | - Replace with LittleJS input system | |
| 497 | - May keep some utility functions (tiltSteer, padSteer) | |
| 498 | ||
| 499 | 6. **`src/settings.ts`** (Minimal changes) | |
| 500 | - Keep as-is | |
| 501 | - May adjust how settings are applied | |
| 502 | ||
| 503 | ### Files to Deprecate | |
| 504 | ||
| 505 | 1. **`src/main.ts`** (Replace with `main-littlejs.ts`) | |
| 506 | ||
| 507 | --- | |
| 508 | ||
| 509 | ## Migration Order Recommendation | |
| 510 | ||
| 511 | 1. **Setup Phase** (Day 1) | |
| 512 | - Install LittleJS | |
| 513 | - Create basic entry point | |
| 514 | - Get LittleJS running with empty game | |
| 515 | ||
| 516 | 2. **Core Integration** (Days 2-3) | |
| 517 | - Set up Three.js with LittleJS | |
| 518 | - Port input system | |
| 519 | - Get basic rendering working | |
| 520 | ||
| 521 | 3. **Game Logic** (Days 4-5) | |
| 522 | - Integrate skater physics | |
| 523 | - Integrate lake generation | |
| 524 | - Basic movement working | |
| 525 | ||
| 526 | 4. **Rendering** (Days 6-7) | |
| 527 | - Integrate ice rendering | |
| 528 | - Integrate shores | |
| 529 | - Integrate sky | |
| 530 | ||
| 531 | 5. **Audio** (Days 8-9) | |
| 532 | - Integrate ice sounds | |
| 533 | - Test audio triggering | |
| 534 | ||
| 535 | 6. **UI** (Days 10-11) | |
| 536 | - Port settings dialog | |
| 537 | - Port about dialog | |
| 538 | - Add HUD elements | |
| 539 | ||
| 540 | 7. **Polish** (Days 12-13) | |
| 541 | - Weather system | |
| 542 | - Snow and drifts | |
| 543 | - Marks (tracks, cracks) | |
| 544 | ||
| 545 | 8. **Testing** (Days 14-15) | |
| 546 | - Full testing on all devices | |
| 547 | - Performance optimization | |
| 548 | - Bug fixes | |
| 549 | ||
| 550 | --- | |
| 551 | ||
| 552 | ## Risk Assessment | |
| 553 | ||
| 554 | ### Low Risk Items | |
| 555 | - Lake generation (already modular) | |
| 556 | - Settings system (already modular) | |
| 557 | - Three.js rendering (can coexist with LittleJS) | |
| 558 | ||
| 559 | ### Medium Risk Items | |
| 560 | - Input system migration (need to test feel) | |
| 561 | - Skater physics timing (delta time changes) | |
| 562 | - Audio system integration | |
| 563 | ||
| 564 | ### High Risk Items | |
| 565 | - Mobile device testing (need physical devices) | |
| 566 | - Performance on low-end devices | |
| 567 | - Tilt steering on iOS (permission issues) | |
| 568 | ||
| 569 | --- | |
| 570 | ||
| 571 | ## Rollback Plan | |
| 572 | ||
| 573 | If the migration encounters significant issues: | |
| 574 | ||
| 575 | 1. **Partial Migration**: Keep using Three.js for rendering while using LittleJS for input, audio, and game loop | |
| 576 | 2. **Incremental Migration**: Migrate one system at a time, keeping the old code until new is proven | |
| 577 | 3. **Fallback**: Can always revert to current implementation if needed | |
| 578 | ||
| 579 | --- | |
| 580 | ||
| 581 | ## Success Criteria | |
| 582 | ||
| 583 | 1. All current features work as before | |
| 584 | 2. Frame rate >= current implementation | |
| 585 | 3. Input feel is preserved or improved | |
| 586 | 4. Audio quality is preserved | |
| 587 | 5. Visual quality is preserved | |
| 588 | 6. Mobile experience is improved | |
| 589 | 7. Code is more maintainable | |
| 590 | ||
| 591 | --- | |
| 592 | ||
| 593 | ## Estimated Timeline | |
| 594 | ||
| 595 | | Phase | Duration | Start Date | End Date | | |
| 596 | |-------|----------|------------|----------| | |
| 597 | | Phase 1: Setup | 1-2 days | TBD | TBD | | |
| 598 | | Phase 2: Core Integration | 2-3 days | TBD | TBD | | |
| 599 | | Phase 3: Scene Migration | 3-5 days | TBD | TBD | | |
| 600 | | Phase 4: Game Logic | 2-3 days | TBD | TBD | | |
| 601 | | Phase 5: UI Migration | 2-3 days | TBD | TBD | | |
| 602 | | Phase 6: State Management | 1-2 days | TBD | TBD | | |
| 603 | | Phase 7: Audio Integration | 2-3 days | TBD | TBD | | |
| 604 | | Phase 8: Testing | 3-5 days | TBD | TBD | | |
| 605 | | Phase 9: Cleanup | 1-2 days | TBD | TBD | | |
| 606 | | **Total** | **17-26 days** | | | | |
| 607 | ||
| 608 | **Note:** This is a part-time estimate. For full-time work, reduce by ~50%. | |
| 609 | ||
| 610 | --- | |
| 611 | ||
| 612 | ## Next Steps | |
| 613 | ||
| 614 | 1. Review this plan and provide feedback | |
| 615 | 2. Set up development environment with LittleJS | |
| 616 | 3. Create proof-of-concept with basic movement | |
| 617 | 4. Proceed with migration phase by phase | |
| 618 | 5. Test thoroughly at each phase | |
| 619 | ||
| 620 | --- | |
| 621 | ||
| 622 | ## Additional Considerations | |
| 623 | ||
| 624 | ### LittleJS Features to Leverage Later | |
| 625 | ||
| 626 | 1. **Particle System**: Could enhance snow, drifts, and crack effects | |
| 627 | 2. **Level Editor**: Could be used for testing specific lake configurations | |
| 628 | 3. **Pathfinding**: Could be used for autopilot improvements | |
| 629 | 4. **Networking**: Could enable multiplayer features | |
| 630 | 5. **Cloud Saves**: Could save settings and favorite lakes | |
| 631 | 6. **Medals/Leaderboards**: Could add competitive elements | |
| 632 | ||
| 633 | ### Features That Might Be Simplified | |
| 634 | ||
| 635 | 1. **Input Handling**: LittleJS handles many input complexities | |
| 636 | 2. **Audio Management**: LittleJS can manage audio context | |
| 637 | 3. **Delta Time**: Automatic handling of frame timing | |
| 638 | 4. **Canvas Management**: LittleJS handles canvas sizing and pixel ratio | |
| 639 | ||
| 640 | ### Features to Keep Custom | |
| 641 | ||
| 642 | 1. **Lake Generation**: Too specialized for LittleJS's built-in systems | |
| 643 | 2. **Ice Acoustics**: Too physics-specific | |
| 644 | 3. **Procedural World**: Unique to Nordic Skating | |
| 645 | ||
| 646 | --- | |
| 647 | ||
| 648 | ## Conclusion | |
| 649 | ||
| 650 | The migration to LittleJS is **feasible and beneficial**, particularly because of the Three.js plugin. The migration can be done incrementally with minimal disruption to the existing codebase. The biggest benefits will be in input handling, game loop management, and mobile optimization. | |
| 651 | ||
| 652 | **Recommendation:** Proceed with the migration as outlined in this plan. |