Files
yaze/docs/internal/agents/archive/wasm-docs-2025/wasm-debug-infrastructure.md

14 KiB

WASM Debug Infrastructure for AI Integration

Date: November 25, 2025 (Updated) Status: Current - Active debugging API Version: 2.3.0 Purpose: Comprehensive debug API for Gemini/Antigravity AI integration to analyze rendering issues and game state in the yaze web application.

Note: This document is the high-level overview for WASM debugging. For detailed API reference, see wasm-yazeDebug-api-reference.md. For general WASM status and control APIs, see wasm_dev_status.md.

Overview

The WASM debug infrastructure provides JavaScript access to internal yaze data structures for AI-powered debugging of dungeon palette rendering issues and other visual artifacts.

Memory Configuration

The WASM build uses optimized memory settings configured in src/app/app.cmake:

Setting Value Purpose
INITIAL_MEMORY 256MB Reduces heap resizing during ROM load (~200MB needed for overworld)
MAXIMUM_MEMORY 1GB Prevents runaway allocations
STACK_SIZE 8MB Handles recursive operations during asset decompression
ALLOW_MEMORY_GROWTH 1 Enables dynamic heap expansion

Emscripten Flags:

-s INITIAL_MEMORY=268435456 -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=1073741824 -s STACK_SIZE=8388608

ROM Loading Progress

The WASM build reports loading progress through C++ WasmLoadingManager. Progress can be monitored in the browser UI or console.

Loading Stages

Progress Stage
0% Reading ROM file...
5% Loading ROM data...
10% Initializing editors...
18% Loading graphics sheets...
26% Loading overworld...
34% Loading dungeons...
42% Loading screen editor...
50%+ Loading remaining editors...
100% Complete

Monitoring Loading in Console

// Check ROM loading status
window.yaze.control.getRomStatus()

// Check graphics loading status
window.yazeDebug.arena.getStatus()

// Get editor state after loading
window.yaze.editor.getSnapshot()

Loading Indicator JavaScript API

// Called by C++ via WasmLoadingManager
window.createLoadingIndicator(id, taskName)       // Creates loading overlay
window.updateLoadingProgress(id, progress, msg)   // Updates progress (0.0-1.0)
window.removeLoadingIndicator(id)                 // Removes loading overlay
window.isLoadingCancelled(id)                     // Check if user cancelled

Files Modified/Created

Core Debug Inspector

  • src/web/yaze_debug_inspector.cc (renamed from palette_inspector.cpp)
    • Main WASM debug inspector providing JavaScript bindings via Emscripten
    • Exports functions for palette, ROM, overworld, arena, and emulator debugging

JavaScript API

  • src/web/shell.html
    • Added window.yazeDebug API object for browser console access
    • Enhanced paletteInspector with better error handling
    • Added pixel inspector overlay for visual debugging

File System Fixes

  • src/web/app.js
    • Fixed race condition in initPersistentFS()
    • Added detection for C++ runtime-initialized IDBFS
    • Improved user feedback when file system is initializing

Build System

  • src/app/app.cmake
    • Updated to include web/yaze_debug_inspector.cc for WASM builds

Debug API Reference

JavaScript API (window.yazeDebug)

// Check if API is ready
window.yazeDebug.isReady()  // Returns: boolean

// Capabilities
window.yazeDebug.capabilities  // ['palette', 'arena', 'timeline', 'pixel-inspector', 'rom', 'overworld']

// Palette Debugging
window.yazeDebug.palette.getEvents()      // Get palette debug events
window.yazeDebug.palette.getFullState()   // Full palette state with metadata
window.yazeDebug.palette.getData()        // Raw palette data
window.yazeDebug.palette.getComparisons() // Color comparison data
window.yazeDebug.palette.samplePixel(x,y) // Sample pixel at coordinates
window.yazeDebug.palette.clear()          // Clear debug events

// ROM Debugging
window.yazeDebug.rom.getStatus()                      // ROM load state, size, title
window.yazeDebug.rom.readBytes(address, count)        // Read up to 256 bytes from ROM
window.yazeDebug.rom.getPaletteGroup(groupName, idx)  // Get palette group by name

// Overworld Debugging
window.yazeDebug.overworld.getMapInfo(mapId)          // Map properties (0-159)
window.yazeDebug.overworld.getTileInfo(mapId, x, y)   // Tile data at coordinates

// Arena (Graphics) Debugging
window.yazeDebug.arena.getStatus()        // Texture queue size, active sheets
window.yazeDebug.arena.getSheetInfo(idx)  // Details for specific graphics sheet

// Timeline Analysis
window.yazeDebug.timeline.get()           // Ordered event timeline

// AI Analysis Helpers
window.yazeDebug.analysis.getSummary()    // Diagnostic summary
window.yazeDebug.analysis.getHypothesis() // AI hypothesis analysis
window.yazeDebug.analysis.getFullState()  // Combined full state

// Utility Functions
window.yazeDebug.dumpAll()                // Complete state dump (JSON)
window.yazeDebug.formatForAI()            // Human-readable format for AI

C++ EMSCRIPTEN_BINDINGS

EMSCRIPTEN_BINDINGS(yaze_debug_inspector) {
  // Palette debug functions
  function("getDungeonPaletteEvents", &getDungeonPaletteEvents);
  function("getColorComparisons", &getColorComparisons);
  function("samplePixelAt", &samplePixelAt);
  function("clearPaletteDebugEvents", &clearPaletteDebugEvents);
  function("getFullPaletteState", &getFullPaletteState);
  function("getPaletteData", &getPaletteData);
  function("getEventTimeline", &getEventTimeline);
  function("getDiagnosticSummary", &getDiagnosticSummary);
  function("getHypothesisAnalysis", &getHypothesisAnalysis);

  // Arena debug functions
  function("getArenaStatus", &getArenaStatus);
  function("getGfxSheetInfo", &getGfxSheetInfo);

  // ROM debug functions
  function("getRomStatus", &getRomStatus);
  function("readRomBytes", &readRomBytes);
  function("getRomPaletteGroup", &getRomPaletteGroup);

  // Overworld debug functions
  function("getOverworldMapInfo", &getOverworldMapInfo);
  function("getOverworldTileInfo", &getOverworldTileInfo);

  // Emulator debug functions
  function("getEmulatorStatus", &getEmulatorStatus);
  function("readEmulatorMemory", &readEmulatorMemory);
  function("getEmulatorVideoState", &getEmulatorVideoState);

  // Combined state
  function("getFullDebugState", &getFullDebugState);
}

File System Issues & Fixes

Problem: Silent File Opening Failure

Symptoms:

  • Clicking "Open ROM" did nothing
  • No error messages shown to user
  • Console showed FS not ready yet; still initializing even after IDBFS synced successfully

Root Cause: The application had two separate IDBFS initialization paths:

  1. C++ runtime (main.ccMountFilesystems()) - Initializes IDBFS and logs IDBFS synced successfully
  2. JavaScript (app.jsinitPersistentFS()) - Tried to mount IDBFS again, failed silently

The JavaScript code never set fsReady = true because:

  • It waited for IDBFS to be available
  • C++ already mounted IDBFS
  • The JS FS.syncfs() callback never fired (already synced)
  • fsReady stayed false, blocking all file operations

Fix Applied:

function initPersistentFS() {
  // ... existing code ...

  // Check if /roms already exists (C++ may have already set up the FS)
  var romsExists = false;
  try {
    FS.stat('/roms');
    romsExists = true;
  } catch (e) {
    // Directory doesn't exist
  }

  if (romsExists) {
    // C++ already mounted IDBFS, just mark as ready
    console.log('[WASM] FS already initialized by C++ runtime');
    fsReady = true;
    resolve();
    return;
  }

  // ... continue with JS mounting if needed ...
}

Problem: No User Feedback During FS Init

Symptoms:

  • User clicked "Open ROM" during initialization
  • Nothing happened, no error shown
  • Only console warning logged

Fix Applied:

function ensureFSReady(showAlert = true) {
  if (fsReady && typeof FS !== 'undefined') return true;
  if (fsInitPromise) {
    console.warn('FS not ready yet; still initializing.');
    if (showAlert) {
      // Show status message in header
      var status = document.getElementById('header-status');
      if (status) {
        status.textContent = 'File system initializing... please wait';
        status.style.color = '#ffaa00';
        setTimeout(function() {
          status.textContent = 'Ready';
          status.style.color = '';
        }, 3000);
      }
    }
    return false;
  }
  // ... rest of function
}

Problem: JSON Parse Errors in Problems Panel

Symptoms:

  • Console error: Failed to parse palette events JSON: unexpected character at line 1 column 2
  • Problems panel showed errors when no palette events existed

Root Cause:

  • Module.getDungeonPaletteEvents() returned empty string "" instead of "[]"
  • JSON.parse failed on empty string

Fix Applied:

// Handle empty or invalid responses
if (!eventsStr || eventsStr.length === 0 || eventsStr === '[]') {
  var list = document.getElementById('problems-list');
  if (list) {
    list.innerHTML = '<div class="problems-empty">No palette events yet.</div>';
  }
  return;
}

Valid Palette Group Names

For getRomPaletteGroup(groupName, paletteIndex):

Group Name Description
ow_main Overworld main palettes
ow_aux Overworld auxiliary palettes
ow_animated Overworld animated palettes
hud HUD/UI palettes
global_sprites Global sprite palettes
armors Link armor palettes
swords Sword palettes
shields Shield palettes
sprites_aux1 Sprite auxiliary 1
sprites_aux2 Sprite auxiliary 2
sprites_aux3 Sprite auxiliary 3
dungeon_main Dungeon main palettes
grass Grass palettes
3d_object 3D object palettes
ow_mini_map Overworld minimap palettes

Building

# Build WASM with debug infrastructure
./scripts/build-wasm.sh debug

# Serve locally (sets COOP/COEP headers for SharedArrayBuffer)
./scripts/serve-wasm.sh 8080

Important: The dev server must set COOP/COEP headers for SharedArrayBuffer support. Use ./scripts/serve-wasm.sh which handles this automatically.

Testing the API

Open browser console after loading the application:

// Verify API is loaded
window.yazeDebug.isReady()

// Get ROM status (after loading a ROM)
window.yazeDebug.rom.getStatus()

// Read bytes from ROM address 0x10000
window.yazeDebug.rom.readBytes(0x10000, 32)

// Get dungeon palette group
window.yazeDebug.rom.getPaletteGroup('dungeon_main', 0)

// Get overworld map info for Light World map 0
window.yazeDebug.overworld.getMapInfo(0)

// Full debug dump for AI analysis
window.yazeDebug.dumpAll()

Known Limitations

  1. Emulator debug functions require emulator to be initialized and running
  2. Overworld tile info requires overworld to be loaded in editor
  3. Palette sampling works on the visible canvas area only
  4. ROM byte reading limited to 256 bytes per call to prevent large responses
  5. Memory reading from emulator limited to 256 bytes per call
  6. Loading indicator managed by C++ WasmLoadingManager - don't create separate JS indicators

Quick Start for AI Agents

  1. Load a ROM: Use the file picker or drag-and-drop a .sfc file
  2. Wait for loading: Monitor progress via loading overlay or window.yaze.control.getRomStatus()
  3. Verify ready state: window.yaze.control.isReady() should return true
  4. Start debugging: Use window.yazeDebug.dumpAll() for full state or specific APIs
// Complete verification sequence
if (window.yaze.control.isReady()) {
  const status = window.yaze.control.getRomStatus();
  if (status.loaded) {
    console.log('ROM loaded:', status.filename);
    console.log('AI-ready dump:', window.yazeDebug.formatForAI());
  }
}

Gemini Antigravity AI Integration

The web interface includes dedicated tools for AI assistants that struggle to discover ImGui elements.

window.aiTools API

High-level helper functions with console output for AI readability:

// Get full application state (ROM, editor, cards, layouts)
window.aiTools.getAppState()

// Get current editor snapshot
window.aiTools.getEditorState()

// Card management
window.aiTools.getVisibleCards()
window.aiTools.getAvailableCards()
window.aiTools.showCard('Room Selector')
window.aiTools.hideCard('Object Editor')

// Navigation
window.aiTools.navigateTo('room:0')    // Go to dungeon room
window.aiTools.navigateTo('map:5')     // Go to overworld map
window.aiTools.navigateTo('Dungeon')   // Switch editor

// Data access
window.aiTools.getRoomData(0)          // Dungeon room data
window.aiTools.getMapData(0)           // Overworld map data

// Documentation
window.aiTools.dumpAPIReference()      // Complete API reference

Nav Bar Dropdowns

The web UI includes four dedicated dropdown menus:

Dropdown Purpose
Editor Quick switch between all 13 editors
Emulator Show/Run/Pause/Step/Reset + Memory Viewer
Layouts Preset card configurations
AI Tools All window.aiTools functions via UI

Command Palette (Ctrl+K)

All AI tools accessible via palette:

  • Editor: <name> - Switch editors
  • Emulator: <action> - Control emulator
  • AI: Get App State - Application state
  • AI: API Reference - Full API documentation

Future Enhancements

  • Add dungeon room state debugging
  • Add sprite debugging
  • Add memory watch points
  • Add breakpoint support for emulator
  • Add texture atlas visualization
  • Add palette history tracking