nordic-skating / local-littlejs / files / CONVERSION_PLAN.md
Branch local-littlejs · default branch · all branches
CONVERSION_PLAN.md
39d08b63 2026-10-20 Pavel Safronov | 1 | # Nordic Skating to LittleJS Conversion Plan |
| 2 | ||
| 3 | ## Overview | |
| 4 | This document outlines the strategy for converting the Nordic Skating project from Three.js to LittleJS. | |
| 5 | ||
| 6 | ## Current Project Analysis | |
| 7 | ||
| 8 | ### Key Components Using Three.js: | |
| 9 | 1. **Main Render Loop** (`src/main.ts`) | |
| 10 | - WebGLRenderer setup | |
| 11 | - Scene and camera management | |
| 12 | - Animation loop | |
| 13 | ||
| 14 | 2. **Render Components** | |
| 15 | - `ice.ts`: Ice surface with textures and materials | |
| 16 | - `sky.ts`: Sky dome with custom shader (322 lines of GLSL) | |
| 17 | - `marks.ts`: Skating trail marks with line geometry | |
| 18 | - `drifts.ts`: Drift effects | |
| 19 | - `snow.ts`: Particle system with custom shader | |
| 20 | - `shores.ts`: Shore elements | |
| 21 | ||
| 22 | ### Three.js Features Used: | |
| 23 | - WebGLRenderer | |
| 24 | - Scene, PerspectiveCamera | |
| 25 | - Mesh, Geometry (PlaneGeometry, SphereGeometry, BufferGeometry) | |
| 26 | - Materials (MeshLambertMaterial, LineBasicMaterial, ShaderMaterial) | |
| 27 | - Textures and texture loading | |
| 28 | - Custom GLSL shaders for sky and snow effects | |
| 29 | - Points system for particles | |
| 30 | ||
| 31 | ## LittleJS Capabilities Analysis | |
| 32 | ||
| 33 | ### Key Features Available in LittleJS: | |
| 34 | 1. **2D/3D Hybrid Rendering**: WebGL2 + Canvas2D | |
| 35 | 2. **3D Support**: | |
| 36 | - Built-in 3D renderer that shares canvas with 2D | |
| 37 | - Shape builders, OBJ and glTF model loading | |
| 38 | - Shadow maps, lights, cameras | |
| 39 | 3. **Shaders**: Shadertoy-style shaders for post-processing or object-level effects | |
| 40 | 4. **Particles**: Robust particle effect system | |
| 41 | 5. **Physics**: Arcade physics and Box2D integration | |
| 42 | 6. **Textures**: Runtime texture loading and atlas support | |
| 43 | 7. **Audio**: Sound and music support with spatial audio | |
| 44 | 8. **Input**: Comprehensive input handling (mouse, keyboard, touch) | |
| 45 | ||
| 46 | ### Compatibility Notes: | |
| 47 | - LittleJS has its own 3D renderer, but also supports Three.js as a plugin | |
| 48 | - Custom shaders can be adapted to LittleJS's shader system | |
| 49 | - Particle systems need conversion from THREE.Points to LittleJS particles | |
| 50 | - Material system is different but conceptually similar | |
| 51 | ||
| 52 | ## Conversion Strategy | |
| 53 | ||
| 54 | ### Phase 1: Setup and Prototyping (Week 1) | |
| 55 | ||
| 56 | **Tasks:** | |
| 57 | 1. Install LittleJS alongside Three.js | |
| 58 | 2. Create minimal prototype showing basic scene | |
| 59 | 3. Test shader compatibility | |
| 60 | 4. Verify performance characteristics | |
| 61 | ||
| 62 | **Implementation:** | |
| 63 | ```bash | |
| 64 | npm install littlejsengine --save | |
| 65 | ``` | |
| 66 | ||
| 67 | ### Phase 2: Core Infrastructure Migration (Week 2-3) | |
| 68 | ||
| 69 | **Tasks:** | |
| 70 | 1. Replace Three.js renderer with LittleJS | |
| 71 | 2. Migrate scene management | |
| 72 | 3. Convert camera system | |
| 73 | 4. Set up animation loop compatibility | |
| 74 | ||
| 75 | **Key Changes:** | |
| 76 | - Replace `THREE.WebGLRenderer` with `engineInit()` pattern | |
| 77 | - Adapt `gameUpdate()` and `gameRender()` callbacks | |
| 78 | - Convert coordinate systems (LittleJS uses different conventions) | |
| 79 | ||
| 80 | ### Phase 3: Component-by-Component Migration (Week 4-6) | |
| 81 | ||
| 82 | **Order of Migration:** | |
| 83 | 1. **Sky System** (`sky.ts`) | |
| 84 | - Highest priority due to complex shader | |
| 85 | - Test shader compatibility first | |
| 86 | ||
| 87 | 2. **Ice Surface** (`ice.ts`) | |
| 88 | - Plane geometry conversion | |
| 89 | - Material adaptation | |
| 90 | ||
| 91 | 3. **Snow Particles** (`snow.ts`) | |
| 92 | - Convert THREE.Points to LittleJS particles | |
| 93 | - Adapt custom shader | |
| 94 | ||
| 95 | 4. **Skating Marks** (`marks.ts`) | |
| 96 | - Line geometry to LittleJS equivalent | |
| 97 | ||
| 98 | 5. **Drifts and Shores** | |
| 99 | - Final render components | |
| 100 | ||
| 101 | ### Phase 4: Integration and Testing (Week 7-8) | |
| 102 | ||
| 103 | **Tasks:** | |
| 104 | 1. Verify all components work together | |
| 105 | 2. Test performance characteristics | |
| 106 | 3. Optimize shaders and rendering | |
| 107 | 4. Ensure mobile compatibility | |
| 108 | 5. Test on various devices/browsers | |
| 109 | ||
| 110 | ## Technical Challenges and Solutions | |
| 111 | ||
| 112 | ### 1. Custom Shaders Conversion | |
| 113 | **Challenge**: Sky and snow use complex GLSL shaders with custom uniforms. | |
| 114 | ||
| 115 | **Solution**: | |
| 116 | - Adapt shaders to LittleJS's shader system | |
| 117 | - Map Three.js uniforms to LittleJS equivalents | |
| 118 | - Test shader performance in LittleJS context | |
| 119 | ||
| 120 | ### 2. Coordinate System Differences | |
| 121 | **Challenge**: LittleJS may use different coordinate conventions. | |
| 122 | ||
| 123 | **Solution**: | |
| 124 | - Create conversion utilities for positions/rotations | |
| 125 | - Test thoroughly with existing lake geometries | |
| 126 | ||
| 127 | ### 3. Particle System Migration | |
| 128 | **Challenge**: THREE.Points with custom shader to LittleJS particles. | |
| 129 | ||
| 130 | **Solution**: | |
| 131 | - Use LittleJS's particle system API | |
| 132 | - Adapt vertex/fragment shaders to LittleJS format | |
| 133 | - Maintain same visual appearance and performance | |
| 134 | ||
| 135 | ### 4. Material System Differences | |
| 136 | **Challenge**: Different material property names and capabilities. | |
| 137 | ||
| 138 | **Solution**: | |
| 139 | - Create material conversion utilities | |
| 140 | - Test all material combinations (transparent, emissive, etc.) | |
| 141 | ||
| 142 | ## Implementation Plan | |
| 143 | ||
| 144 | ### Step 1: Setup Dual Environment | |
| 145 | ```typescript | |
| 146 | // In main.ts | |
| 147 | import * as THREE from 'three' | |
| 148 | import { engineInit } from 'littlejsengine' | |
| 149 | ||
| 150 | // Keep Three.js for now, add LittleJS alongside | |
| 151 | function gameInit() { | |
| 152 | // Initialize both systems | |
| 153 | } | |
| 154 | ||
| 155 | function gameUpdate() { | |
| 156 | // Update both systems in parallel during transition | |
| 157 | } | |
| 158 | ||
| 159 | function gameRender() { | |
| 160 | // Render with both, compare results | |
| 161 | } | |
| 162 | ||
| 163 | engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost) | |
| 164 | ``` | |
| 165 | ||
| 166 | ### Step 2: Create Adapter Utilities | |
| 167 | ```typescript | |
| 168 | // src/adapters/littlejs-adapter.ts | |
| 169 | ||
| 170 | export class LittleJSAdapter { | |
| 171 | static convertColor(threeColor: THREE.Color): number { | |
| 172 | // Convert Three.js Color to LittleJS format | |
| 173 | } | |
| 174 | ||
| 175 | static convertVector3(vec: THREE.Vector3): [number, number, number] { | |
| 176 | // Convert Three.js Vector3 to tuple | |
| 177 | } | |
| 178 | ||
| 179 | static createMaterial(options: { | |
| 180 | color?: THREE.Color, | |
| 181 | transparent?: boolean, | |
| 182 | emissive?: THREE.Color | |
| 183 | }): any { | |
| 184 | // Create LittleJS material equivalent | |
| 185 | } | |
| 186 | } | |
| 187 | ``` | |
| 188 | ||
| 189 | ### Step 3: Migrate Sky Component First | |
| 190 | ```typescript | |
| 191 | // New sky-littlejs.ts | |
| 192 | import { engine, createShaderMaterial } from 'littlejsengine' | |
| 193 | ||
| 194 | export class SkyLittleJS { | |
| 195 | private mesh: any | |
| 196 | ||
| 197 | constructor() { | |
| 198 | // Create LittleJS equivalent of sky dome | |
| 199 | this.mesh = engine.createMesh({ | |
| 200 | geometry: engine.createSphereGeometry(1000, 32, 16), | |
| 201 | material: createShaderMaterial({ | |
| 202 | vertex: adaptedVertexShader, | |
| 203 | fragment: adaptedFragmentShader, | |
| 204 | uniforms: this.setupUniforms() | |
| 205 | }) | |
| 206 | }) | |
| 207 | } | |
| 208 | ||
| 209 | private setupUniforms() { | |
| 210 | // Map Three.js uniforms to LittleJS format | |
| 211 | } | |
| 212 | } | |
| 213 | ``` | |
| 214 | ||
| 215 | ## Testing Strategy | |
| 216 | ||
| 217 | 1. **Unit Tests**: Test each component in isolation | |
| 218 | 2. **Visual Regression**: Compare screenshots before/after | |
| 219 | 3. **Performance Benchmarks**: Measure FPS and memory usage | |
| 220 | 4. **Cross-Browser Testing**: Ensure compatibility across browsers | |
| 221 | 5. **Mobile Testing**: Verify touch controls and performance | |
| 222 | ||
| 223 | ## Rollback Plan | |
| 224 | ||
| 225 | If conversion proves problematic: | |
| 226 | 1. Maintain Three.js as primary renderer | |
| 227 | 2. Use LittleJS for specific optimized components only | |
| 228 | 3. Keep both renderers with feature flags | |
| 229 | 4. Gradual migration path remains open | |
| 230 | ||
| 231 | ## Success Criteria | |
| 232 | ||
| 233 | 1. All visual elements maintain same appearance | |
| 234 | 2. Performance meets or exceeds current implementation | |
| 235 | 3. Mobile compatibility improved | |
| 236 | 4. Bundle size reduced (target: < 50KB gzipped) | |
| 237 | 5. No regression in functionality | |
| 238 | 6. Easier to maintain and extend | |
| 239 | ||
| 240 | ## Timeline Estimate | |
| 241 | ||
| 242 | - **Total Duration**: 8 weeks | |
| 243 | - **Critical Path**: Shader conversion and particle system migration | |
| 244 | - **Risk Areas**: Complex shaders, coordinate system differences | |
| 245 | ||
| 246 | ## Resources | |
| 247 | ||
| 248 | - LittleJS Documentation: https://github.com/KilledByAPixel/LittleJS | |
| 249 | - Three.js to LittleJS Migration Guide (to be created) | |
| 250 | - Test cases for visual regression | |
| 251 | - Performance benchmarks |