425 lines
14 KiB
Markdown
425 lines
14 KiB
Markdown
# 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
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```javascript
|
|
// 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`)
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```cpp
|
|
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.cc` → `MountFilesystems()`) - Initializes IDBFS and logs `IDBFS synced successfully`
|
|
2. **JavaScript** (`app.js` → `initPersistentFS()`) - 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:**
|
|
|
|
```javascript
|
|
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:**
|
|
|
|
```javascript
|
|
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:**
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```javascript
|
|
// 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:
|
|
|
|
```javascript
|
|
// 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
|