Skip to content

Latest commit

 

History

History
100 lines (80 loc) · 3.57 KB

File metadata and controls

100 lines (80 loc) · 3.57 KB

Map Generation Freeze Fix

Problem

The game would freeze when starting the map, making it appear unresponsive to users.

Root Cause

The generateMap() function in src/world/generation.ts was processing 3,223 entities (including 3,000 grass instances) synchronously in a single JavaScript call. This blocked the main thread and prevented the browser from updating the UI, causing the freeze.

Solution

Implemented chunked asynchronous processing to allow the browser to remain responsive during map generation:

Key Changes

  1. Async Function Signature (src/world/generation.ts:280)

    export async function generateMap(
        weatherSystem: WeatherSystem, 
        chunkSize: number = 100,
        onProgress?: (current: number, total: number) => void
    ): Promise<void>
  2. Chunked Processing Loop

    • Processes entities in batches (default 100 per chunk)
    • Yields control to browser between chunks using await new Promise(resolve => setTimeout(resolve, 0))
    • Allows UI updates and prevents blocking
  3. Progress Callbacks (main.js:692)

    await generateMap(weatherSystem, 100, (current, total) => {
        const percent = Math.floor((current / total) * 100);
        startButton.innerHTML = `<span class="spinner"></span>Generating ${percent}%... 🍭`;
    });
  4. Helper Function Extraction

    • Created processMapEntity() to handle individual entity creation
    • Made code more modular and testable
  5. Async Procedural Generation

    • Made populateProceduralExtras() async with chunking (100 per chunk)
    • Ensures all generation stages remain non-blocking
  6. Named Constants

    • Added DEFAULT_MAP_CHUNK_SIZE = 100 for map entity chunks
    • Added DEFAULT_PROCEDURAL_CHUNK_SIZE = 100 for procedural extra chunks
    • Improves maintainability and consistency

Performance Impact

Before

  • ❌ UI freeze for several seconds
  • ❌ No visual feedback during generation
  • ❌ Browser "Not Responding" warnings possible
  • ❌ Poor user experience

After

  • ✅ Responsive UI throughout generation
  • ✅ Real-time progress updates (0-100%)
  • ✅ Smooth, professional loading experience
  • ✅ Browser remains interactive

Technical Details

Chunking Strategy

  • Map entities: 100 entities per chunk (~32 chunks for 3,223 entities)
  • Procedural extras: 100 per chunk (4 chunks for 400 extras)
  • Yield frequency: Every chunk via setTimeout(resolve, 0)

Estimated Timing

With 100 entities per chunk and typical processing speed:

  • Each chunk: ~10-50ms processing
  • Yield between chunks: ~4-16ms
  • Total time: Similar to synchronous (maybe +10-20% overhead)
  • Key difference: Browser can update UI between chunks

Browser Event Loop Integration

Process Chunk 1 (100 entities) → Yield → UI Update → 
Process Chunk 2 (100 entities) → Yield → UI Update →
...
Process Chunk N → Complete

Testing

  • ✅ Code compiles without errors
  • ✅ Page loads successfully
  • ✅ No JavaScript runtime errors
  • ⚠️ Full WebGPU testing requires compatible browser

Future Improvements

  1. Web Workers: Move generation to background thread for even better performance
  2. Streaming Generation: Start rendering visible entities first, load distant objects later
  3. Incremental Loading: Load map in spatial chunks based on camera position
  4. IndexedDB Caching: Cache generated map for faster subsequent loads

Related Files

  • src/world/generation.ts - Core generation logic
  • main.js - Button handler and progress UI
  • assets/map.json - Map data (3,223 entities)