backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)
This commit is contained in:
@@ -1,328 +0,0 @@
|
||||
# Claude Test Handoff Document
|
||||
|
||||
**Date**: 2024-11-22
|
||||
**Prepared by**: Claude (Sonnet 4.5)
|
||||
**Previous agents**: Gemini 3, Claude 4.5 (build fixes)
|
||||
**Status**: Build passing, ready for testing
|
||||
|
||||
## TL;DR
|
||||
|
||||
All 6 feature branches from Gemini3's work have been merged to master and build issues are resolved. The codebase needs comprehensive testing across multiple areas: Overworld fixes, Dungeon E2E tests, Agent UI improvements, CI infrastructure, and debugger/disassembler features.
|
||||
|
||||
## Current State
|
||||
|
||||
```
|
||||
Commit: ed980625d7 fix: resolve build errors from Gemini3 handoff
|
||||
Branch: master (13 commits ahead of origin)
|
||||
Build: PASSING (mac-dbg preset)
|
||||
```
|
||||
|
||||
### Merged Branches (in order)
|
||||
1. `infra/ci-test-overhaul` - CI/CD and test infrastructure
|
||||
2. `test/e2e-dungeon-coverage` - Dungeon editor E2E tests
|
||||
3. `feature/agent-ui-improvements` - Agent UI and dev tools
|
||||
4. `fix/overworld-logic` - Overworld test fixes
|
||||
5. `chore/misc-cleanup` - Documentation and cleanup
|
||||
6. `feature/debugger-disassembler` - Debugger and disassembler support
|
||||
|
||||
### Build Fixes Applied
|
||||
- Added `memory_inspector_tool.cc` to `agent.cmake` (was missing, caused vtable linker errors)
|
||||
- Fixed API mismatches in `memory_inspector_tool.cc`:
|
||||
- `GetArg()` → `GetString().value_or()`
|
||||
- `OutputMap()`/`OutputTable()` → `BeginObject()`/`AddField()`/`EndObject()` pattern
|
||||
|
||||
---
|
||||
|
||||
## Testing Areas
|
||||
|
||||
### 1. Overworld Fixes (`fix/overworld-logic`)
|
||||
|
||||
**Files Changed**:
|
||||
- `test/integration/zelda3/overworld_integration_test.cc`
|
||||
- `test/unit/zelda3/overworld_test.cc`
|
||||
|
||||
**Test Commands**:
|
||||
```bash
|
||||
# Run overworld tests
|
||||
ctest --test-dir build -R "overworld" --output-on-failure
|
||||
|
||||
# Specific test binaries
|
||||
./build/bin/Debug/yaze_test_stable --gtest_filter="*Overworld*"
|
||||
```
|
||||
|
||||
**What to Verify**:
|
||||
- [ ] Overworld unit tests pass
|
||||
- [ ] Overworld integration tests pass
|
||||
- [ ] No regressions in overworld map loading
|
||||
- [ ] Multi-area map configuration works correctly
|
||||
|
||||
**Manual Testing**:
|
||||
```bash
|
||||
./build/bin/Debug/yaze.app/Contents/MacOS/yaze --rom_file=<path_to_rom> --editor=Overworld
|
||||
```
|
||||
- Load a ROM and verify overworld renders correctly
|
||||
- Test map switching between Light World, Dark World, Special areas
|
||||
- Verify entity visibility (entrances, exits, items, sprites)
|
||||
|
||||
---
|
||||
|
||||
### 2. Dungeon E2E Tests (`test/e2e-dungeon-coverage`)
|
||||
|
||||
**New Test Files**:
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `dungeon_canvas_interaction_test.cc/.h` | Canvas click/drag tests |
|
||||
| `dungeon_e2e_tests.cc/.h` | Full workflow E2E tests |
|
||||
| `dungeon_layer_rendering_test.cc/.h` | Layer visibility tests |
|
||||
| `dungeon_object_drawing_test.cc/.h` | Object rendering tests |
|
||||
| `dungeon_visual_verification_test.cc/.h` | Visual regression tests |
|
||||
|
||||
**Test Commands**:
|
||||
```bash
|
||||
# Run all dungeon tests
|
||||
ctest --test-dir build -R "dungeon" -L stable --output-on-failure
|
||||
|
||||
# Run dungeon E2E specifically
|
||||
ctest --test-dir build -R "dungeon_e2e" --output-on-failure
|
||||
|
||||
# GUI tests (requires display)
|
||||
./build/bin/Debug/yaze_test_gui --gtest_filter="*Dungeon*"
|
||||
```
|
||||
|
||||
**What to Verify**:
|
||||
- [ ] All new dungeon test files compile
|
||||
- [ ] Canvas interaction tests pass
|
||||
- [ ] Layer rendering tests pass
|
||||
- [ ] Object drawing tests pass
|
||||
- [ ] Visual verification tests pass (may need baseline images)
|
||||
- [ ] Integration tests with ROM pass (if ROM available)
|
||||
|
||||
**Manual Testing**:
|
||||
```bash
|
||||
./build/bin/Debug/yaze.app/Contents/MacOS/yaze --rom_file=<path_to_rom> --editor=Dungeon
|
||||
```
|
||||
- Load dungeon rooms and verify rendering
|
||||
- Test object selection and manipulation
|
||||
- Verify layer toggling works
|
||||
- Check room switching
|
||||
|
||||
---
|
||||
|
||||
### 3. Agent UI Improvements (`feature/agent-ui-improvements`)
|
||||
|
||||
**Key Files**:
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `src/cli/service/agent/dev_assist_agent.cc/.h` | Dev assistance agent |
|
||||
| `src/cli/service/agent/tools/build_tool.cc/.h` | Build system integration |
|
||||
| `src/cli/service/agent/tools/filesystem_tool.cc/.h` | File operations |
|
||||
| `src/cli/service/agent/tools/memory_inspector_tool.cc/.h` | Memory debugging |
|
||||
| `src/app/editor/agent/agent_editor.cc` | Agent editor UI |
|
||||
|
||||
**Test Commands**:
|
||||
```bash
|
||||
# Run agent-related tests
|
||||
ctest --test-dir build -R "tool_dispatcher" --output-on-failure
|
||||
ctest --test-dir build -R "agent" --output-on-failure
|
||||
|
||||
# Test z3ed CLI
|
||||
./build/bin/Debug/z3ed --help
|
||||
./build/bin/Debug/z3ed memory regions
|
||||
./build/bin/Debug/z3ed memory analyze 0x7E0000
|
||||
```
|
||||
|
||||
**What to Verify**:
|
||||
- [ ] Tool dispatcher tests pass
|
||||
- [ ] Memory inspector tools work:
|
||||
- `memory regions` - lists known ALTTP memory regions
|
||||
- `memory analyze <addr>` - analyzes memory at address
|
||||
- `memory search <pattern>` - searches for patterns
|
||||
- `memory compare <addr>` - compares memory values
|
||||
- `memory check [region]` - checks for anomalies
|
||||
- [ ] Build tool integration works
|
||||
- [ ] Filesystem tool operations work
|
||||
- [ ] Agent editor UI renders correctly
|
||||
|
||||
**Manual Testing**:
|
||||
```bash
|
||||
./build/bin/Debug/yaze.app/Contents/MacOS/yaze --rom_file=<path_to_rom> --editor=Agent
|
||||
```
|
||||
- Open Agent editor and verify chat UI
|
||||
- Test proposal drawer functionality
|
||||
- Verify theme colors are consistent (no hardcoded colors)
|
||||
|
||||
---
|
||||
|
||||
### 4. CI Infrastructure (`infra/ci-test-overhaul`)
|
||||
|
||||
**Key Files**:
|
||||
- `.github/workflows/ci.yml` - Main CI workflow
|
||||
- `.github/workflows/release.yml` - Release workflow
|
||||
- `.github/workflows/nightly.yml` - Nightly builds (NEW)
|
||||
- `test/test.cmake` - Test configuration
|
||||
- `test/README.md` - Test documentation
|
||||
|
||||
**What to Verify**:
|
||||
- [ ] CI workflow YAML is valid:
|
||||
```bash
|
||||
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/ci.yml'))"
|
||||
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/nightly.yml'))"
|
||||
```
|
||||
- [ ] Test labels work correctly:
|
||||
```bash
|
||||
ctest --test-dir build -L stable -N # List stable tests
|
||||
ctest --test-dir build -L unit -N # List unit tests
|
||||
```
|
||||
- [ ] Documentation is accurate in `test/README.md`
|
||||
|
||||
---
|
||||
|
||||
### 5. Debugger/Disassembler (`feature/debugger-disassembler`)
|
||||
|
||||
**Key Files**:
|
||||
- `src/cli/service/agent/disassembler_65816.cc`
|
||||
- `src/cli/service/agent/rom_debug_agent.cc`
|
||||
- `src/app/emu/debug/` - Emulator debug components
|
||||
|
||||
**Test Commands**:
|
||||
```bash
|
||||
# Test disassembler
|
||||
ctest --test-dir build -R "disassembler" --output-on-failure
|
||||
|
||||
# Manual disassembly test (requires ROM)
|
||||
./build/bin/Debug/z3ed disasm <rom_file> 0x008000 20
|
||||
```
|
||||
|
||||
**What to Verify**:
|
||||
- [ ] 65816 disassembler produces correct output
|
||||
- [ ] ROM debug agent works
|
||||
- [ ] Emulator stepping (if integrated)
|
||||
|
||||
---
|
||||
|
||||
## Quick Test Matrix
|
||||
|
||||
| Area | Unit Tests | Integration | E2E/GUI | Manual |
|
||||
|------|------------|-------------|---------|--------|
|
||||
| Overworld | `overworld_test` | `overworld_integration_test` | - | Open editor |
|
||||
| Dungeon | `object_rendering_test` | `dungeon_room_test` | `dungeon_e2e_tests` | Open editor |
|
||||
| Agent Tools | `tool_dispatcher_test` | - | - | z3ed CLI |
|
||||
| Memory Inspector | - | - | - | z3ed memory * |
|
||||
| Disassembler | `disassembler_test` | - | - | z3ed disasm |
|
||||
|
||||
---
|
||||
|
||||
## Full Test Suite
|
||||
|
||||
```bash
|
||||
# Quick smoke test (stable only, ~2 min)
|
||||
ctest --test-dir build -L stable -j4 --output-on-failure
|
||||
|
||||
# All tests (may take longer)
|
||||
ctest --test-dir build --output-on-failure
|
||||
|
||||
# ROM-dependent tests (if ROM available)
|
||||
cmake --preset mac-dbg -DYAZE_ENABLE_ROM_TESTS=ON -DYAZE_TEST_ROM_PATH=~/zelda3.sfc
|
||||
ctest --test-dir build -L rom_dependent --output-on-failure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Known Issues / Watch For
|
||||
|
||||
1. **Linker warnings**: You may see warnings about duplicate libraries during linking - these are benign warnings, not errors.
|
||||
|
||||
2. **third_party/ directory**: There's an untracked `third_party/` directory that needs a decision:
|
||||
- Should it be added to `.gitignore`?
|
||||
- Should it be a git submodule?
|
||||
- For now, leave it untracked.
|
||||
|
||||
3. **Visual tests**: Some dungeon visual verification tests may fail if baseline images don't exist yet. These tests should generate baselines on first run.
|
||||
|
||||
4. **GUI tests**: Tests with `-L gui` require a display. On headless CI, these may need to be skipped or run with Xvfb.
|
||||
|
||||
5. **gRPC tests**: Some agent features require gRPC. Ensure `YAZE_ENABLE_REMOTE_AUTOMATION` is ON if testing those.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Test Order
|
||||
|
||||
1. **First**: Run stable unit tests to catch obvious issues
|
||||
```bash
|
||||
ctest --test-dir build -L stable -L unit -j4
|
||||
```
|
||||
|
||||
2. **Second**: Run integration tests
|
||||
```bash
|
||||
ctest --test-dir build -L stable -L integration -j4
|
||||
```
|
||||
|
||||
3. **Third**: Manual testing of key editors (Overworld, Dungeon, Agent)
|
||||
|
||||
4. **Fourth**: E2E/GUI tests if display available
|
||||
```bash
|
||||
./build/bin/Debug/yaze_test_gui
|
||||
```
|
||||
|
||||
5. **Fifth**: Full test suite
|
||||
```bash
|
||||
ctest --test-dir build --output-on-failure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build Commands Reference
|
||||
|
||||
```bash
|
||||
# Configure (if needed)
|
||||
cmake --preset mac-dbg
|
||||
|
||||
# Build main executable
|
||||
cmake --build build --target yaze -j4
|
||||
|
||||
# Build all (including tests)
|
||||
cmake --build build -j4
|
||||
|
||||
# Build specific test binary
|
||||
cmake --build build --target yaze_test_stable -j4
|
||||
cmake --build build --target yaze_test_gui -j4
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files Modified in Final Fix Commit
|
||||
|
||||
For reference, these files were modified in `ed980625d7`:
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `assets/asm/usdasm` | Submodule pointer update |
|
||||
| `src/app/editor/agent/agent_editor.cc` | Gemini3's UI changes |
|
||||
| `src/app/gui/style/theme.h` | Theme additions |
|
||||
| `src/cli/agent.cmake` | Added memory_inspector_tool.cc |
|
||||
| `src/cli/service/agent/emulator_service_impl.h` | Gemini3's changes |
|
||||
| `src/cli/service/agent/rom_debug_agent.cc` | Gemini3's changes |
|
||||
| `src/cli/service/agent/tools/memory_inspector_tool.cc` | API fixes |
|
||||
| `src/protos/emulator_service.proto` | Gemini3's proto changes |
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Testing is complete when:
|
||||
- [ ] All stable tests pass (`ctest -L stable`)
|
||||
- [ ] No regressions in Overworld editor
|
||||
- [ ] No regressions in Dungeon editor
|
||||
- [ ] Agent tools respond correctly to CLI commands
|
||||
- [ ] Build succeeds on all platforms (via CI)
|
||||
|
||||
---
|
||||
|
||||
## Contact / Escalation
|
||||
|
||||
If you encounter issues:
|
||||
1. Check `docs/BUILD-TROUBLESHOOTING.md` for common fixes
|
||||
2. Review `GEMINI3_HANDOFF.md` for context on the original work
|
||||
3. Check git log for related commits: `git log --oneline -20`
|
||||
|
||||
Good luck with testing!
|
||||
@@ -1,752 +0,0 @@
|
||||
# Editor Development Roadmaps - November 2025
|
||||
|
||||
**Generated**: 2025-11-21 by Claude Code
|
||||
**Source**: Multi-agent analysis (5 specialized agents)
|
||||
**Scope**: Dungeon Editor, Overworld Editor, Message Editor, Testing Infrastructure
|
||||
|
||||
---
|
||||
|
||||
## 📊 Executive Summary
|
||||
|
||||
Based on comprehensive analysis by specialized agents, here are the strategic priorities for editor development:
|
||||
|
||||
### Current State Assessment
|
||||
|
||||
| Editor | Completion | Primary Gap | Est. Effort |
|
||||
|--------|-----------|-------------|-------------|
|
||||
| **Dungeon Editor** | 80% | Interaction wiring | 22-30 hours |
|
||||
| **Overworld Editor** | 95% | Theme compliance & undo/redo | 14-18 hours |
|
||||
| **Message Editor** | 70% | Translation features | 21 dev days |
|
||||
| **Testing Coverage** | 34% | Editor-specific tests | 4-6 weeks |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Dungeon Editor Roadmap
|
||||
|
||||
**Analysis**: imgui-frontend-engineer agent
|
||||
**Current State**: Solid architecture, component-based design, just needs interaction wiring
|
||||
|
||||
### Top 5 Milestones
|
||||
|
||||
#### **Milestone 1: Object Interaction Foundation** (4-6 hours)
|
||||
**Priority**: HIGHEST - Unlocks actual editing capability
|
||||
|
||||
**Tasks**:
|
||||
1. Wire object placement system
|
||||
- Complete `DrawObjectSelector()` with working preview
|
||||
- Connect `object_placed_callback_` in `DungeonObjectInteraction`
|
||||
- Implement `PlaceObjectAtPosition()` to write to room data
|
||||
- Add ghost preview when hovering with object selected
|
||||
|
||||
2. Complete object selection
|
||||
- Implement `CheckForObjectSelection()` with click/drag rectangle
|
||||
- Wire `DrawSelectionHighlights()` (high-contrast outline at 0.85f alpha)
|
||||
- Connect context menu to `HandleDeleteSelected()`
|
||||
- Add multi-select with Shift/Ctrl modifiers
|
||||
|
||||
3. Object drawing integration
|
||||
- Ensure `ObjectDrawer::DrawObjectList()` called during room rendering
|
||||
- Verify object outlines render with proper filtering
|
||||
- Add object info tooltip on hover (ID, size, coordinates)
|
||||
|
||||
4. Theme compliance audit
|
||||
- Replace all `IM_COL32()` calls with `AgentUI::GetTheme()` colors
|
||||
- Audit all dungeon editor files for hardcoded colors
|
||||
|
||||
**Files to Modify**:
|
||||
- `src/app/editor/dungeon/dungeon_object_selector.cc`
|
||||
- `src/app/editor/dungeon/dungeon_object_interaction.cc`
|
||||
- `src/app/editor/dungeon/dungeon_canvas_viewer.cc`
|
||||
- `src/app/editor/dungeon/dungeon_editor_v2.cc`
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] User can select object from selector panel
|
||||
- [ ] User can place object in room with mouse click
|
||||
- [ ] User can select placed objects (single + multi)
|
||||
- [ ] User can delete selected objects via context menu or Del key
|
||||
- [ ] Object tooltips show useful info on hover
|
||||
- [ ] No hardcoded colors remain
|
||||
|
||||
---
|
||||
|
||||
#### **Milestone 2: Clipboard Operations** (3-4 hours)
|
||||
**Priority**: Medium - Big productivity boost
|
||||
|
||||
**Tasks**:
|
||||
1. Implement copy/cut
|
||||
- Store selected objects in `clipboard_` vector
|
||||
- Serialize object properties (ID, position, size, layer)
|
||||
- Add "Copy" and "Cut" to context menu
|
||||
- Update status bar to show clipboard count
|
||||
|
||||
2. Implement paste
|
||||
- Deserialize clipboard data
|
||||
- Place objects at mouse cursor position (offset from original)
|
||||
- Support paste-with-drag for precise placement
|
||||
- Add "Paste" to context menu + Ctrl+V shortcut
|
||||
|
||||
3. Cross-room clipboard
|
||||
- Enable copying objects from one room and pasting into another
|
||||
- Handle blockset differences gracefully (warn if incompatible)
|
||||
- Persist clipboard across room switches
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] User can copy selected objects (Ctrl+C or context menu)
|
||||
- [ ] User can cut selected objects (Ctrl+X)
|
||||
- [ ] User can paste objects at cursor (Ctrl+V)
|
||||
- [ ] Paste works across different rooms
|
||||
- [ ] Clipboard persists across room tabs
|
||||
|
||||
---
|
||||
|
||||
#### **Milestone 3: Undo/Redo System** (5-7 hours)
|
||||
**Priority**: Medium - Professional editing experience
|
||||
|
||||
**Tasks**:
|
||||
1. Design command pattern
|
||||
- Create `DungeonEditorCommand` base class with `Execute()` / `Undo()` methods
|
||||
- Implement commands: `PlaceObjectCommand`, `DeleteObjectCommand`, `MoveObjectCommand`, `ModifyObjectCommand`
|
||||
- Add command stack (max 50 actions) with pruning
|
||||
|
||||
2. Integrate with object operations
|
||||
- Wrap all object modifications in commands
|
||||
- Push commands to history stack in `DungeonEditorV2`
|
||||
- Update UI to show "Undo: [action]" / "Redo: [action]" tooltips
|
||||
|
||||
3. Property edit undo
|
||||
- Track room property changes (blockset, palette, floor graphics)
|
||||
- Create `ModifyRoomPropertiesCommand` for batch edits
|
||||
- Handle graphics refresh on undo/redo
|
||||
|
||||
4. UI indicators
|
||||
- Gray out Undo/Redo menu items when unavailable
|
||||
- Add Ctrl+Z / Ctrl+Shift+Z keyboard shortcuts
|
||||
- Display undo history in optional panel (10 recent actions)
|
||||
|
||||
**Files to Create**:
|
||||
- `src/app/editor/dungeon/dungeon_command_history.h` (new file)
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] All object operations support undo/redo
|
||||
- [ ] Room property changes support undo/redo
|
||||
- [ ] Keyboard shortcuts work (Ctrl+Z, Ctrl+Shift+Z)
|
||||
- [ ] Undo history visible in debug panel
|
||||
- [ ] No memory leaks (command cleanup after stack pruning)
|
||||
|
||||
---
|
||||
|
||||
#### **Milestone 4: Object Properties Panel** (4-5 hours)
|
||||
**Priority**: Medium - Fine-tuned object customization
|
||||
|
||||
**Tasks**:
|
||||
1. Properties UI design
|
||||
- Create `ObjectPropertiesCard` (dockable, 300×400 default size)
|
||||
- Display selected object ID, coordinates, size, layer
|
||||
- Editable fields: X/Y position (hex input), size/length (numeric), layer (dropdown)
|
||||
- Show object preview thumbnail (64×64 pixels)
|
||||
|
||||
2. Live property updates
|
||||
- Changes to X/Y immediately move object on canvas
|
||||
- Changes to size/length trigger re-render via `ObjectDrawer`
|
||||
- Layer changes update object's BG assignment
|
||||
- Add "Apply" vs "Live Update" toggle for performance
|
||||
|
||||
3. Multi-selection properties
|
||||
- Show common properties when multiple objects selected
|
||||
- Support batch edit (move all selected by offset, change layer for all)
|
||||
- Display "Mixed" for differing values
|
||||
|
||||
4. Integration with ObjectEditorCard
|
||||
- Merge or coordinate with existing `ObjectEditorCard`
|
||||
- Decide if properties should be tab in unified card or separate panel
|
||||
- Follow OverworldEditor's pattern (separate MapPropertiesSystem)
|
||||
|
||||
**Files to Create**:
|
||||
- `src/app/editor/dungeon/object_properties_card.h` (new file)
|
||||
- `src/app/editor/dungeon/object_properties_card.cc` (new file)
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Properties panel shows when object selected
|
||||
- [ ] All object properties editable (X, Y, size, layer)
|
||||
- [ ] Changes reflected immediately on canvas
|
||||
- [ ] Multi-selection batch edit works
|
||||
- [ ] Panel follows AgentUITheme standards
|
||||
|
||||
---
|
||||
|
||||
#### **Milestone 5: Enhanced Canvas Features** (6-8 hours)
|
||||
**Priority**: Lower - Quality-of-life improvements
|
||||
|
||||
**Tasks**:
|
||||
1. Object snapping
|
||||
- Snap to 8×8 grid when placing/moving objects
|
||||
- Snap to other objects' edges (magnetic guides)
|
||||
- Toggle snapping with Shift key
|
||||
- Visual guides (dotted lines) when snapping
|
||||
|
||||
2. Canvas navigation improvements
|
||||
- Minimap overlay (128×128 px) showing full room with viewport indicator
|
||||
- "Fit to Window" button to reset zoom/pan
|
||||
- Zoom to selection (fit selected objects in view)
|
||||
- Remember pan/zoom per room tab
|
||||
|
||||
3. Object filtering UI
|
||||
- Checkboxes for object type visibility (Type1, Type2, Type3)
|
||||
- Layer filter (show only BG1 objects, only BG2, etc.)
|
||||
- "Show All" / "Hide All" quick toggles
|
||||
- Filter state persists across rooms
|
||||
|
||||
4. Ruler/measurement tool
|
||||
- Click-drag to measure distance between two points
|
||||
- Display pixel distance + tile distance
|
||||
- Show angle for diagonal measurements
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Object snapping works (grid + magnetic)
|
||||
- [ ] Minimap overlay functional
|
||||
- [ ] Object type/layer filtering works
|
||||
- [ ] Measurement tool usable
|
||||
- [ ] Canvas navigation smooth and intuitive
|
||||
|
||||
---
|
||||
|
||||
### Quick Wins (4 hours total)
|
||||
For immediate visible progress:
|
||||
1. **Theme compliance fixes** (1h) - Remove hardcoded colors
|
||||
2. **Object placement wiring** (2h) - Enable basic object placement
|
||||
3. **Object deletion** (1h) - Complete the basic edit loop
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Overworld Editor Roadmap
|
||||
|
||||
**Analysis**: imgui-frontend-engineer agent
|
||||
**Current State**: Feature-complete but needs critical polish
|
||||
|
||||
### Top 5 Critical Fixes
|
||||
|
||||
#### **1. Eliminate All Hardcoded Colors** (4-6 hours)
|
||||
**Priority**: CRITICAL - Theme system violation
|
||||
|
||||
**Problem**: 22+ hardcoded `ImVec4` color instances, zero usage of `AgentUI::GetTheme()`
|
||||
|
||||
**Files Affected**:
|
||||
- `src/app/editor/overworld/map_properties.cc` (22 instances)
|
||||
- `src/app/editor/overworld/overworld_entity_renderer.cc` (entity colors)
|
||||
- `src/app/editor/overworld/overworld_editor.cc` (selector highlight)
|
||||
|
||||
**Required Fix**:
|
||||
```cpp
|
||||
// Add to AgentUITheme:
|
||||
ImVec4 entity_entrance_color; // Bright yellow-gold (0.85f alpha)
|
||||
ImVec4 entity_exit_color; // Cyan-white (0.85f alpha)
|
||||
ImVec4 entity_item_color; // Bright red (0.85f alpha)
|
||||
ImVec4 entity_sprite_color; // Bright magenta (0.85f alpha)
|
||||
ImVec4 status_info; // Info messages
|
||||
ImVec4 status_warning; // Warnings
|
||||
ImVec4 status_success; // Success messages
|
||||
|
||||
// Refactor all entity_renderer colors:
|
||||
const auto& theme = AgentUI::GetTheme();
|
||||
ImVec4 GetEntranceColor() { return theme.entity_entrance_color; }
|
||||
```
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] All hardcoded colors replaced with theme system
|
||||
- [ ] Entity colors follow visibility standards (0.85f alpha)
|
||||
- [ ] No `ImVec4` literals remain in overworld editor files
|
||||
|
||||
---
|
||||
|
||||
#### **2. Implement Undo/Redo System for Tile Editing** (6-8 hours)
|
||||
**Priority**: HIGH - #1 user frustration point
|
||||
|
||||
**Current State**:
|
||||
```cpp
|
||||
absl::Status Undo() override { return absl::UnimplementedError("Undo"); }
|
||||
absl::Status Redo() override { return absl::UnimplementedError("Redo"); }
|
||||
```
|
||||
|
||||
**Implementation Approach**:
|
||||
- Create command pattern stack for tile modifications
|
||||
- Track: `{map_id, x, y, old_tile16_id, new_tile16_id}`
|
||||
- Store up to 100 undo steps (configurable)
|
||||
- Batch consecutive paint strokes into single undo operation
|
||||
- Hook into existing `RenderUpdatedMapBitmap()` call sites
|
||||
- Add Ctrl+Z/Ctrl+Shift+Z keyboard shortcuts
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Tile painting supports undo/redo
|
||||
- [ ] Keyboard shortcuts work (Ctrl+Z, Ctrl+Shift+Z)
|
||||
- [ ] Consecutive paint strokes batched into single undo
|
||||
- [ ] Undo stack limited to 100 actions
|
||||
- [ ] Graphics refresh correctly on undo/redo
|
||||
|
||||
---
|
||||
|
||||
#### **3. Complete OverworldItem Deletion Implementation** (2-3 hours)
|
||||
**Priority**: Medium - Data integrity issue
|
||||
|
||||
**Current Issue**:
|
||||
```cpp
|
||||
// entity.cc:319
|
||||
// TODO: Implement deleting OverworldItem objects, currently only hides them
|
||||
bool DrawItemEditorPopup(zelda3::OverworldItem& item) {
|
||||
```
|
||||
|
||||
**Problem**: Items marked as `deleted = true` but not actually removed from ROM data structures
|
||||
|
||||
**Required Fix**:
|
||||
- Implement proper deletion in `zelda3::Overworld::SaveItems()`
|
||||
- Compact the item array after deletion (remove deleted entries)
|
||||
- Update item indices for all remaining items
|
||||
- Add "Permanently Delete" vs "Hide" option in UI
|
||||
|
||||
**Files to Modify**:
|
||||
- `src/app/editor/overworld/entity.cc`
|
||||
- `src/zelda3/overworld/overworld.cc` (SaveItems method)
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Deleted items removed from ROM data
|
||||
- [ ] Item array compacted after deletion
|
||||
- [ ] No ID conflicts when inserting new items
|
||||
- [ ] UI clearly distinguishes "Hide" vs "Delete"
|
||||
|
||||
---
|
||||
|
||||
#### **4. Remove TODO Comments for Deferred Texture Rendering** (30 minutes)
|
||||
**Priority**: Low - Code cleanliness
|
||||
|
||||
**Found 9 instances**:
|
||||
```cpp
|
||||
// TODO: Queue texture for later rendering.
|
||||
// Renderer::Get().UpdateBitmap(&tile16_blockset_.atlas);
|
||||
```
|
||||
|
||||
**Files Affected**:
|
||||
- `overworld_editor.cc` (6 instances)
|
||||
- `tile16_editor.cc` (3 instances)
|
||||
|
||||
**Required Fix**:
|
||||
- Remove all 9 TODO comments
|
||||
- Verify that `gfx::Arena` is handling these textures properly
|
||||
- If not, use: `gfx::Arena::Get().QueueDeferredTexture(bitmap, priority)`
|
||||
- Add documentation explaining why direct `UpdateBitmap()` calls were removed
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] All texture TODO comments removed
|
||||
- [ ] Texture queuing verified functional
|
||||
- [ ] Documentation added for future developers
|
||||
|
||||
---
|
||||
|
||||
#### **5. Polish Exit Editor - Implement Door Type Controls** (1 hour)
|
||||
**Priority**: Low - UX clarity
|
||||
|
||||
**Current State**:
|
||||
```cpp
|
||||
// entity.cc:216
|
||||
gui::TextWithSeparators("Unimplemented below");
|
||||
ImGui::RadioButton("None", &doorType, 0);
|
||||
ImGui::RadioButton("Wooden", &doorType, 1);
|
||||
ImGui::RadioButton("Bombable", &doorType, 2);
|
||||
```
|
||||
|
||||
**Problem**: Door type controls shown but marked "Unimplemented" - misleading to users
|
||||
|
||||
**Recommended Fix**: Remove the unimplemented door controls entirely
|
||||
```cpp
|
||||
ImGui::TextDisabled(ICON_MD_INFO " Door types are controlled by dungeon room properties");
|
||||
ImGui::TextWrapped("To configure entrance doors, use the Dungeon Editor.");
|
||||
```
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Misleading unimplemented UI removed
|
||||
- [ ] Clear message explaining where door types are configured
|
||||
|
||||
---
|
||||
|
||||
## 💬 Message Editor Roadmap
|
||||
|
||||
**Analysis**: imgui-frontend-engineer agent
|
||||
**Current State**: Solid foundation, needs translation features
|
||||
|
||||
### Phased Implementation Plan
|
||||
|
||||
#### **Phase 1: JSON Export/Import** (Weeks 1-2, 6 dev days)
|
||||
**Priority**: HIGHEST - Foundation for all translation workflows
|
||||
|
||||
**Tasks**:
|
||||
1. Implement `SerializeMessages()` and `DeserializeMessages()`
|
||||
2. Add UI buttons for export/import
|
||||
3. Add CLI import support
|
||||
4. Write comprehensive tests
|
||||
|
||||
**Proposed JSON Schema**:
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"rom_name": "Zelda3 US",
|
||||
"messages": [
|
||||
{
|
||||
"id": "0x01",
|
||||
"address": "0xE0000",
|
||||
"text": "Link rescued Zelda from Ganon.",
|
||||
"context": "Opening narration",
|
||||
"notes": "Translator: Keep under 40 characters",
|
||||
"modified": false
|
||||
}
|
||||
],
|
||||
"dictionary": [
|
||||
{"index": "0x00", "phrase": "Link"},
|
||||
{"index": "0x01", "phrase": "Zelda"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Files to Modify**:
|
||||
- `src/app/editor/message/message_editor.h`
|
||||
- `src/app/editor/message/message_editor.cc`
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] JSON export creates valid schema
|
||||
- [ ] JSON import loads messages correctly
|
||||
- [ ] CLI supports `z3ed message export --format json`
|
||||
- [ ] Tests cover serialization/deserialization
|
||||
|
||||
---
|
||||
|
||||
#### **Phase 2: Translation Workspace** (Weeks 3-5, 9 dev days)
|
||||
**Priority**: High - Unlocks localization capability
|
||||
|
||||
**Tasks**:
|
||||
1. Create `TranslationWorkspace` class
|
||||
2. Side-by-side reference/translation view
|
||||
3. Progress tracking (X/396 completed)
|
||||
4. Context notes field for translators
|
||||
|
||||
**UI Mockup**:
|
||||
```
|
||||
┌────────────────────────────────────────────────────┐
|
||||
│ Translation Progress: 123/396 (31%) │
|
||||
├────────────────────────────────────────────────────┤
|
||||
│ Reference (English) │ Translation (Spanish) │
|
||||
├───────────────────────┼───────────────────────────┤
|
||||
│ Link rescued Zelda │ Link rescató a Zelda │
|
||||
│ from Ganon. │ de Ganon. │
|
||||
│ │ │
|
||||
│ Context: Opening │ Notes: Keep dramatic tone │
|
||||
├───────────────────────┴───────────────────────────┤
|
||||
│ [Previous] [Mark Complete] [Save] [Next] │
|
||||
└────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Files to Create**:
|
||||
- `src/app/editor/message/translation_workspace.h` (new file)
|
||||
- `src/app/editor/message/translation_workspace.cc` (new file)
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Side-by-side view displays reference and translation
|
||||
- [ ] Progress tracker updates as messages marked complete
|
||||
- [ ] Context notes persist with message data
|
||||
- [ ] Navigation between messages smooth
|
||||
|
||||
---
|
||||
|
||||
#### **Phase 3: Search & Replace** (Week 6, 4 dev days)
|
||||
**Priority**: Medium - QoL improvement
|
||||
|
||||
**Tasks**:
|
||||
1. Complete the Find/Replace implementation
|
||||
2. Add batch operations
|
||||
3. Optional: Add regex support
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Global search across all messages
|
||||
- [ ] Batch replace (e.g., "Hyrule" → "Lorule")
|
||||
- [ ] Search highlights matches in message list
|
||||
- [ ] Replace confirms before applying
|
||||
|
||||
---
|
||||
|
||||
#### **Phase 4: UI Polish** (Week 7, 2 dev days)
|
||||
**Priority**: Low - Final polish
|
||||
|
||||
**Tasks**:
|
||||
1. Integrate `AgentUITheme` (if not already done)
|
||||
2. Add keyboard shortcuts
|
||||
3. Improve accessibility
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] All colors use theme system
|
||||
- [ ] Keyboard shortcuts documented
|
||||
- [ ] Tooltips on all major controls
|
||||
|
||||
---
|
||||
|
||||
### Architectural Decisions Needed
|
||||
|
||||
1. **JSON Schema**: Proposed schema includes context notes and metadata - needs review
|
||||
2. **Translation Layout**: Side-by-side vs. top-bottom layout - needs user feedback
|
||||
3. **Dictionary Auto-Optimization**: Complex NP-hard problem - may need background threads
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Infrastructure Roadmap
|
||||
|
||||
**Analysis**: test-infrastructure-expert agent
|
||||
**Current State**: Well-architected (34% test-to-code ratio), uneven coverage
|
||||
|
||||
### Top 5 Priorities
|
||||
|
||||
#### **Priority 1: Editor Lifecycle Test Framework** (Week 1, 1-2 dev days)
|
||||
**Why**: Every editor needs basic lifecycle testing
|
||||
|
||||
**What to Build**:
|
||||
- `test/unit/editor/editor_lifecycle_test.cc`
|
||||
- Parameterized test for all editor types
|
||||
- Validates initialization, ROM binding, error handling
|
||||
|
||||
**Implementation**:
|
||||
```cpp
|
||||
class EditorLifecycleTest : public ::testing::TestWithParam<editor::EditorType> {
|
||||
// Test: InitializeWithoutRom_Succeeds
|
||||
// Test: LoadWithoutRom_ReturnsError
|
||||
// Test: FullLifecycle_Succeeds
|
||||
// Test: UpdateBeforeLoad_ReturnsError
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AllEditors,
|
||||
EditorLifecycleTest,
|
||||
::testing::Values(
|
||||
editor::EditorType::kOverworld,
|
||||
editor::EditorType::kDungeon,
|
||||
editor::EditorType::kMessage,
|
||||
editor::EditorType::kGraphics,
|
||||
editor::EditorType::kPalette,
|
||||
editor::EditorType::kSprite
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
**Impact**: Catches 80% of editor regressions with minimal effort
|
||||
|
||||
---
|
||||
|
||||
#### **Priority 2: OverworldEditor Entity Operations Tests** (Week 2, 2-3 dev days)
|
||||
**Why**: OverworldEditor is 118KB with complex entity management
|
||||
|
||||
**What to Build**:
|
||||
- `test/unit/editor/overworld/entity_operations_test.cc`
|
||||
- Tests for add/remove/modify entrances, exits, items, sprites
|
||||
- Validation of entity constraints and error handling
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Add entity with valid position succeeds
|
||||
- [ ] Add entity with invalid position returns error
|
||||
- [ ] Remove entity by ID succeeds
|
||||
- [ ] Modify entity updates graphics
|
||||
- [ ] Delete all entities in region works
|
||||
|
||||
---
|
||||
|
||||
#### **Priority 3: Graphics Refresh Verification Tests** (Week 3, 2-3 dev days)
|
||||
**Why**: Graphics refresh bugs are common (UpdateBitmap vs RenderBitmap, data/surface sync)
|
||||
|
||||
**What to Build**:
|
||||
- `test/integration/editor/graphics_refresh_test.cc`
|
||||
- Validates Update property → Load → Force render pipeline
|
||||
- Tests Bitmap/surface synchronization
|
||||
- Verifies Arena texture queue processing
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Change map palette triggers graphics reload
|
||||
- [ ] Bitmap data and surface stay synced
|
||||
- [ ] WriteToPixel updates surface
|
||||
- [ ] Arena texture queue processes correctly
|
||||
- [ ] Graphics sheet modification notifies Arena
|
||||
|
||||
---
|
||||
|
||||
#### **Priority 4: Message Editor Workflow Tests** (Week 4, 1-2 dev days)
|
||||
**Why**: Message editor has good data parsing tests but no editor UI/workflow tests
|
||||
|
||||
**What to Build**:
|
||||
- `test/integration/editor/message_editor_test.cc`
|
||||
- E2E test for message editing workflow
|
||||
- Tests for dictionary optimization
|
||||
- Command parsing validation
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] Load all messages succeeds
|
||||
- [ ] Edit message updates ROM
|
||||
- [ ] Add dictionary word optimizes message
|
||||
- [ ] Insert command validates syntax
|
||||
- [ ] Invalid command returns error
|
||||
|
||||
---
|
||||
|
||||
#### **Priority 5: Canvas Interaction Test Utilities** (Week 5-6, 2-3 dev days)
|
||||
**Why**: Multiple editors use Canvas - need reusable test helpers
|
||||
|
||||
**What to Build**:
|
||||
- `test/test_utils_canvas.h` / `test/test_utils_canvas.cc`
|
||||
- Semantic helpers: Click tile, select rectangle, drag entity
|
||||
- Bitmap comparison utilities
|
||||
|
||||
**API Design**:
|
||||
```cpp
|
||||
namespace yaze::test::canvas {
|
||||
void ClickTile(ImGuiTestContext* ctx, const std::string& canvas_name, int tile_x, int tile_y);
|
||||
void SelectRectangle(ImGuiTestContext* ctx, const std::string& canvas_name, int x1, int y1, int x2, int y2);
|
||||
void DragEntity(ImGuiTestContext* ctx, const std::string& canvas_name, int from_x, int from_y, int to_x, int to_y);
|
||||
uint32_t CaptureBitmapChecksum(const gfx::Bitmap& bitmap);
|
||||
int CompareBitmaps(const gfx::Bitmap& bitmap1, const gfx::Bitmap& bitmap2, bool log_differences = false);
|
||||
}
|
||||
```
|
||||
|
||||
**Impact**: Makes E2E tests easier to write, more maintainable, reduces duplication
|
||||
|
||||
---
|
||||
|
||||
### Testing Strategy
|
||||
|
||||
**ROM-Independent Tests** (Primary CI Target):
|
||||
- Use `MockRom` with minimal test data
|
||||
- Fast execution (< 5s total)
|
||||
- No external dependencies
|
||||
- Ideal for: Logic, calculations, data structures, error handling
|
||||
|
||||
**ROM-Dependent Tests** (Secondary/Manual):
|
||||
- Require actual Zelda3 ROM file
|
||||
- Slower execution (< 60s total)
|
||||
- Test real-world data parsing
|
||||
- Ideal for: Graphics rendering, full map loading, ROM patching
|
||||
|
||||
**Developer Workflow**:
|
||||
```bash
|
||||
# During development: Run fast unit tests frequently
|
||||
./build/bin/yaze_test --unit "*OverworldEntity*"
|
||||
|
||||
# Before commit: Run integration tests for changed editor
|
||||
./build/bin/yaze_test --integration "*Overworld*"
|
||||
|
||||
# Pre-PR: Run E2E tests for critical workflows
|
||||
./build/bin/yaze_test --e2e --show-gui
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Success Metrics
|
||||
|
||||
**After 4 Weeks**:
|
||||
- ✅ Dungeon editor functional for basic editing
|
||||
- ✅ Overworld editor theme-compliant with undo/redo
|
||||
- ✅ Message editor supports JSON export/import
|
||||
- ✅ Test coverage increased from 10% → 40% for editors
|
||||
- ✅ All editors have lifecycle tests
|
||||
|
||||
---
|
||||
|
||||
## 🎬 Recommended Development Order
|
||||
|
||||
### Week 1: Quick Wins
|
||||
**Goal**: Immediate visible progress (8 hours)
|
||||
|
||||
```bash
|
||||
# Dungeon Editor (4 hours)
|
||||
1. Fix theme violations (1h)
|
||||
2. Wire object placement (2h)
|
||||
3. Enable object deletion (1h)
|
||||
|
||||
# Overworld Editor (4 hours)
|
||||
4. Start theme system refactor (4h)
|
||||
```
|
||||
|
||||
### Week 2: Core Functionality
|
||||
**Goal**: Unlock basic editing workflows (18 hours)
|
||||
|
||||
```bash
|
||||
# Dungeon Editor (10 hours)
|
||||
1. Complete object selection system (3h)
|
||||
2. Implement clipboard operations (4h)
|
||||
3. Add object properties panel (3h)
|
||||
|
||||
# Overworld Editor (8 hours)
|
||||
4. Finish theme system refactor (4h)
|
||||
5. Implement undo/redo foundation (4h)
|
||||
```
|
||||
|
||||
### Week 3: Testing Foundation
|
||||
**Goal**: Prevent regressions (15 hours)
|
||||
|
||||
```bash
|
||||
# Testing Infrastructure
|
||||
1. Create editor lifecycle test framework (5h)
|
||||
2. Add overworld entity operation tests (5h)
|
||||
3. Implement canvas interaction utilities (5h)
|
||||
```
|
||||
|
||||
### Week 4: Message Editor Phase 1
|
||||
**Goal**: Unlock translation workflows (15 hours)
|
||||
|
||||
```bash
|
||||
# Message Editor
|
||||
1. Implement JSON serialization (6h)
|
||||
2. Add export/import UI (4h)
|
||||
3. Add CLI import support (2h)
|
||||
4. Write comprehensive tests (3h)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Key File Locations
|
||||
|
||||
### Dungeon Editor
|
||||
- **Primary**: `src/app/editor/dungeon/dungeon_editor_v2.{h,cc}`
|
||||
- **Components**: `dungeon_canvas_viewer`, `dungeon_object_selector`, `dungeon_object_interaction`, `dungeon_room_loader`
|
||||
- **Core Data**: `src/zelda3/dungeon/room.{h,cc}`, `object_drawer.{h,cc}`
|
||||
- **Tests**: `test/integration/dungeon_editor_v2_test.cc`, `test/e2e/dungeon_editor_smoke_test.cc`
|
||||
|
||||
### Overworld Editor
|
||||
- **Primary**: `src/app/editor/overworld/overworld_editor.{h,cc}`
|
||||
- **Modules**: `map_properties.cc`, `overworld_entity_renderer.cc`, `entity.cc`
|
||||
- **Core Data**: `src/zelda3/overworld/overworld.{h,cc}`
|
||||
- **Tests**: `test/unit/editor/overworld/overworld_editor_test.cc`
|
||||
|
||||
### Message Editor
|
||||
- **Primary**: `src/app/editor/message/message_editor.{h,cc}`
|
||||
- **Tests**: `test/integration/message/message_editor_test.cc`
|
||||
|
||||
### Testing Infrastructure
|
||||
- **Main Runner**: `test/yaze_test.cc`
|
||||
- **Utilities**: `test/test_utils.{h,cc}`, `test/mocks/mock_rom.h`
|
||||
- **Fixtures**: `test/unit/editor/editor_test_fixtures.h` (to be created)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes
|
||||
|
||||
**Architecture Strengths**:
|
||||
- Modular editor design with clear separation of concerns
|
||||
- Progressive loading via gfx::Arena
|
||||
- ImGuiTestEngine integration for E2E tests
|
||||
- Card-based UI system
|
||||
|
||||
**Critical Issues**:
|
||||
- Overworld Editor: 22 hardcoded colors violate theme system
|
||||
- All Editors: Missing undo/redo (user frustration #1)
|
||||
- Testing: 67 editor headers, only 6 have tests
|
||||
|
||||
**Strategic Recommendations**:
|
||||
1. Start with dungeon editor - quickest path to "working" state
|
||||
2. Fix overworld theme violations - visible polish, affects UX
|
||||
3. Implement message JSON export - foundation for translation
|
||||
4. Add lifecycle tests - catches 80% of regressions
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Last Updated**: 2025-11-21
|
||||
**Next Review**: After completing Week 1 priorities
|
||||
@@ -1,326 +0,0 @@
|
||||
# Gemini 3 Handoff Document
|
||||
|
||||
**Date**: 2024-11-22
|
||||
**Prepared by**: Claude (Sonnet 4.5)
|
||||
**Previous agents**: Gemini 3 (interrupted), Claude 4.5, GPT-OSS 120
|
||||
|
||||
## TL;DR
|
||||
|
||||
Your work was interrupted and left ~112 uncommitted files scattered across the workspace. I've organized everything into 5 logical branches based on your original `branch_organization.md` plan. All branches are ready for review and merging.
|
||||
|
||||
## What Happened
|
||||
|
||||
1. You (Gemini 3) started work on multiple features simultaneously
|
||||
2. You created `docs/internal/plans/branch_organization.md` outlining how to split the work
|
||||
3. You were interrupted before completing the organization
|
||||
4. Claude 4.5 and GPT-OSS 120 attempted to help but left things partially done
|
||||
5. I (Claude Sonnet 4.5) completed the reorganization
|
||||
|
||||
## Current Branch State
|
||||
|
||||
```
|
||||
master (0d18c521a1) ─┬─► feature/agent-ui-improvements (29931139f5)
|
||||
├─► infra/ci-test-overhaul (aa411a5d1b)
|
||||
├─► test/e2e-dungeon-coverage (28147624a3)
|
||||
├─► chore/misc-cleanup (ed396f7498)
|
||||
├─► fix/overworld-logic (00fef1169d)
|
||||
└─► backup/all-uncommitted-work-2024-11-22 (5e32a8983f)
|
||||
```
|
||||
|
||||
Also preserved:
|
||||
- `feature/debugger-disassembler` (2a88785e25) - Your original debugger work
|
||||
|
||||
---
|
||||
|
||||
## Branch Details
|
||||
|
||||
### 1. `feature/agent-ui-improvements` (19 files, +5183/-141 lines)
|
||||
|
||||
**Purpose**: Agent UI enhancements and new dev assist tooling
|
||||
|
||||
**Key Changes**:
|
||||
| File | Change Type | Description |
|
||||
|------|-------------|-------------|
|
||||
| `agent_chat_widget.cc` | Modified | Enhanced chat UI with better UX |
|
||||
| `agent_editor.cc` | Modified | Editor improvements |
|
||||
| `proposal_drawer.cc` | Modified | Better proposal display |
|
||||
| `dev_assist_agent.cc/.h` | **New** | Development assistance agent |
|
||||
| `tool_dispatcher.cc/.h` | Modified | New tool dispatch capabilities |
|
||||
| `tools/build_tool.cc/.h` | **New** | Build system integration tool |
|
||||
| `tools/filesystem_tool.cc/.h` | **New** | File operations tool |
|
||||
| `tools/memory_inspector_tool.cc/.h` | **New** | Memory debugging tool |
|
||||
| `emulator_service_impl.cc/.h` | Modified | Enhanced emulator integration |
|
||||
| `prompt_builder.cc` | Modified | AI prompt improvements |
|
||||
| `tool_dispatcher_test.cc` | **New** | Integration tests |
|
||||
|
||||
**Dependencies**: None - can be merged independently
|
||||
|
||||
**Testing needed**:
|
||||
```bash
|
||||
cmake --preset mac-dbg
|
||||
ctest --test-dir build -R "tool_dispatcher"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. `infra/ci-test-overhaul` (23 files, +3644/-263 lines)
|
||||
|
||||
**Purpose**: CI/CD and test infrastructure modernization
|
||||
|
||||
**Key Changes**:
|
||||
| File | Change Type | Description |
|
||||
|------|-------------|-------------|
|
||||
| `ci.yml` | Modified | Improved CI workflow |
|
||||
| `release.yml` | Modified | Better release process |
|
||||
| `nightly.yml` | **New** | Scheduled nightly builds |
|
||||
| `AGENTS.md` | Modified | Agent coordination updates |
|
||||
| `CLAUDE.md` | Modified | Build/test guidance |
|
||||
| `CI-TEST-STRATEGY.md` | **New** | Test strategy documentation |
|
||||
| `CI-TEST-AUDIT-REPORT.md` | **New** | Audit findings |
|
||||
| `ci-and-testing.md` | **New** | Comprehensive CI guide |
|
||||
| `test-suite-configuration.md` | **New** | Test config documentation |
|
||||
| `coordination-board.md` | **New** | Agent coordination board |
|
||||
| `test/README.md` | Modified | Test organization guide |
|
||||
| `test/test.cmake` | Modified | CMake test configuration |
|
||||
|
||||
**Dependencies**: None - should be merged FIRST
|
||||
|
||||
**Testing needed**:
|
||||
```bash
|
||||
# Verify workflows are valid YAML
|
||||
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/ci.yml'))"
|
||||
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/nightly.yml'))"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. `test/e2e-dungeon-coverage` (18 files, +3379/-39 lines)
|
||||
|
||||
**Purpose**: Comprehensive dungeon editor test coverage
|
||||
|
||||
**Key Changes**:
|
||||
| File | Change Type | Description |
|
||||
|------|-------------|-------------|
|
||||
| `dungeon_canvas_interaction_test.cc/.h` | **New** | Canvas click/drag tests |
|
||||
| `dungeon_e2e_tests.cc/.h` | **New** | Full workflow E2E tests |
|
||||
| `dungeon_layer_rendering_test.cc/.h` | **New** | Layer visibility tests |
|
||||
| `dungeon_object_drawing_test.cc/.h` | **New** | Object rendering tests |
|
||||
| `dungeon_visual_verification_test.cc/.h` | **New** | Visual regression tests |
|
||||
| `dungeon_editor_system_integration_test.cc` | Modified | System integration |
|
||||
| `dungeon_object_rendering_tests.cc` | Modified | Object render validation |
|
||||
| `dungeon_rendering_test.cc` | Modified | Rendering pipeline |
|
||||
| `dungeon_room_test.cc` | Modified | Room data validation |
|
||||
| `object_rendering_test.cc` | Modified | Unit test updates |
|
||||
| `room.cc` | Modified | Minor bug fix |
|
||||
| `dungeon-gui-test-design.md` | **New** | Test design document |
|
||||
|
||||
**Dependencies**: Merge after `infra/ci-test-overhaul` for test config
|
||||
|
||||
**Testing needed**:
|
||||
```bash
|
||||
cmake --preset mac-dbg
|
||||
ctest --test-dir build -R "dungeon" -L stable
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. `chore/misc-cleanup` (39 files, +7924/-127 lines)
|
||||
|
||||
**Purpose**: Documentation, architecture docs, misc cleanup
|
||||
|
||||
**Key Changes**:
|
||||
| Category | Files | Description |
|
||||
|----------|-------|-------------|
|
||||
| Architecture Docs | `docs/internal/architecture/*` | dungeon_editor_system, message_system, music_system |
|
||||
| Plan Docs | `docs/internal/plans/*` | Various roadmaps and plans |
|
||||
| Dev Guides | `GEMINI_DEV_GUIDE.md`, `ai-asm-debugging-guide.md` | Developer guides |
|
||||
| Build System | `src/CMakeLists.txt`, `editor_library.cmake` | Build config updates |
|
||||
| App Core | `controller.cc`, `main.cc` | Application updates |
|
||||
| Style System | `src/app/gui/style/theme.h` | **New** UI theming |
|
||||
| Unit Tests | `test/unit/*` | Various test updates |
|
||||
|
||||
**Dependencies**: Merge LAST - may need rebasing
|
||||
|
||||
**Testing needed**:
|
||||
```bash
|
||||
cmake --preset mac-dbg
|
||||
ctest --test-dir build -L stable
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. `fix/overworld-logic` (2 files, +10/-5 lines)
|
||||
|
||||
**Purpose**: Small fixes to overworld tests
|
||||
|
||||
**Key Changes**:
|
||||
- `overworld_integration_test.cc` - Integration test fixes
|
||||
- `overworld_test.cc` - Unit test fixes
|
||||
|
||||
**Dependencies**: None
|
||||
|
||||
**Testing needed**:
|
||||
```bash
|
||||
ctest --test-dir build -R "overworld"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recommended Merge Order
|
||||
|
||||
```
|
||||
1. infra/ci-test-overhaul # Sets up CI/test infrastructure
|
||||
↓
|
||||
2. test/e2e-dungeon-coverage # Uses new test config
|
||||
↓
|
||||
3. feature/agent-ui-improvements # Independent feature
|
||||
↓
|
||||
4. fix/overworld-logic # Small fix
|
||||
↓
|
||||
5. chore/misc-cleanup # Docs and misc (rebase first)
|
||||
```
|
||||
|
||||
### Merge Commands
|
||||
|
||||
```bash
|
||||
# 1. Merge CI infrastructure
|
||||
git checkout master
|
||||
git merge --no-ff infra/ci-test-overhaul -m "Merge infra/ci-test-overhaul: CI/CD and test infrastructure"
|
||||
|
||||
# 2. Merge dungeon tests
|
||||
git merge --no-ff test/e2e-dungeon-coverage -m "Merge test/e2e-dungeon-coverage: Dungeon E2E test suite"
|
||||
|
||||
# 3. Merge agent UI
|
||||
git merge --no-ff feature/agent-ui-improvements -m "Merge feature/agent-ui-improvements: Agent UI and tools"
|
||||
|
||||
# 4. Merge overworld fix
|
||||
git merge --no-ff fix/overworld-logic -m "Merge fix/overworld-logic: Overworld test fixes"
|
||||
|
||||
# 5. Rebase and merge cleanup (may have conflicts)
|
||||
git checkout chore/misc-cleanup
|
||||
git rebase master
|
||||
# Resolve any conflicts
|
||||
git checkout master
|
||||
git merge --no-ff chore/misc-cleanup -m "Merge chore/misc-cleanup: Documentation and cleanup"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Potential Conflicts
|
||||
|
||||
### Between branches:
|
||||
- `chore/misc-cleanup` touches `src/CMakeLists.txt` which other branches may also modify
|
||||
- Both `infra/ci-test-overhaul` and `chore/misc-cleanup` touch documentation
|
||||
|
||||
### With master:
|
||||
- If master advances, all branches may need rebasing
|
||||
- The `CLAUDE.md` changes in `infra/ci-test-overhaul` should be reviewed carefully
|
||||
|
||||
---
|
||||
|
||||
## Untracked Files (Need Manual Decision)
|
||||
|
||||
These were NOT committed to any branch:
|
||||
|
||||
| File/Directory | Recommendation |
|
||||
|----------------|----------------|
|
||||
| `.tmp/` | **Delete** - Contains ZScreamDungeon embedded repo |
|
||||
| `third_party/bloaty` | **Decide** - Should be submodule or in .gitignore |
|
||||
| `CIRCULAR_DEPENDENCY_ANALYSIS.md` | **Delete** - Temporary analysis |
|
||||
| `CIRCULAR_DEPENDENCY_FIX_REPORT.md` | **Delete** - Temporary report |
|
||||
| `FIX_CIRCULAR_DEPS.patch` | **Delete** - Temporary patch |
|
||||
| `debug_crash.lldb` | **Delete** - Debug artifact |
|
||||
| `fix_dungeon_colors.py` | **Delete** - One-off script |
|
||||
| `test_grpc_server.sh` | **Keep?** - Test utility |
|
||||
|
||||
### Cleanup Commands
|
||||
```bash
|
||||
# Remove temporary files
|
||||
rm -f CIRCULAR_DEPENDENCY_ANALYSIS.md CIRCULAR_DEPENDENCY_FIX_REPORT.md
|
||||
rm -f FIX_CIRCULAR_DEPS.patch debug_crash.lldb fix_dungeon_colors.py
|
||||
|
||||
# Remove embedded repos (careful!)
|
||||
rm -rf .tmp/
|
||||
|
||||
# Add to .gitignore if needed
|
||||
echo ".tmp/" >> .gitignore
|
||||
echo "third_party/bloaty/" >> .gitignore
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stash Contents (For Reference)
|
||||
|
||||
```bash
|
||||
$ git stash list
|
||||
stash@{0}: WIP on feature/ai-test-infrastructure
|
||||
stash@{1}: WIP on feature/ai-infra-improvements
|
||||
stash@{2}: Release workflow artifact path fix
|
||||
stash@{3}: WIP on develop (Windows OpenSSL)
|
||||
stash@{4}: WIP on feat/gemini-unified-fix
|
||||
```
|
||||
|
||||
To view a stash:
|
||||
```bash
|
||||
git stash show -p stash@{0}
|
||||
```
|
||||
|
||||
These may contain work that was already incorporated into the branches, or may have unique changes. Review before dropping.
|
||||
|
||||
---
|
||||
|
||||
## The Original Plan (For Reference)
|
||||
|
||||
Your original plan from `branch_organization.md` was:
|
||||
|
||||
1. `feature/debugger-disassembler` - ✅ Already had commit
|
||||
2. `infra/ci-test-overhaul` - ✅ Now populated
|
||||
3. `test/e2e-dungeon-coverage` - ✅ Now populated
|
||||
4. `feature/agent-ui-improvements` - ✅ Now populated
|
||||
5. `fix/overworld-logic` - ✅ Now populated
|
||||
6. `chore/misc-cleanup` - ✅ Now populated
|
||||
|
||||
---
|
||||
|
||||
## UI Modernization Context
|
||||
|
||||
You also had `ui_modernization.md` which outlines the component-based architecture pattern. Key points:
|
||||
|
||||
- New editors should follow `DungeonEditorV2` pattern
|
||||
- Use `EditorDependencies` struct for dependency injection
|
||||
- Use `ImGuiWindowClass` for docking groups
|
||||
- Use `EditorCardRegistry` for tool windows
|
||||
- `UICoordinator` is the central hub for app-level UI
|
||||
|
||||
The agent UI improvements in `feature/agent-ui-improvements` should align with these patterns.
|
||||
|
||||
---
|
||||
|
||||
## Safety Net
|
||||
|
||||
If anything goes wrong, the backup branch has EVERYTHING:
|
||||
|
||||
```bash
|
||||
# Restore everything from backup
|
||||
git checkout backup/all-uncommitted-work-2024-11-22
|
||||
|
||||
# Or cherry-pick specific files
|
||||
git checkout backup/all-uncommitted-work-2024-11-22 -- path/to/file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Questions for You
|
||||
|
||||
1. Should `third_party/bloaty` be a git submodule?
|
||||
2. Should `.tmp/` be added to `.gitignore`?
|
||||
3. Are the stashed changes still needed, or can they be dropped?
|
||||
4. Do you want PRs created for review, or direct merges?
|
||||
|
||||
---
|
||||
|
||||
## Contact
|
||||
|
||||
This document is in `docs/internal/plans/GEMINI3_HANDOFF.md` on the `chore/misc-cleanup` branch.
|
||||
|
||||
Good luck! 🚀
|
||||
22
docs/internal/plans/README.md
Normal file
22
docs/internal/plans/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Plan Directory Guide
|
||||
|
||||
Purpose: keep plan/spec documents centralized and up to date.
|
||||
|
||||
## How to use this directory
|
||||
- One plan per initiative. If a spec exists elsewhere (e.g., `agents/initiative-*.md`), link to it instead of duplicating.
|
||||
- Add a header to each plan: `Status`, `Owner (Agent ID)`, `Created`, `Last Reviewed`, `Next Review` (≤14 days), and link to the coordination-board entry.
|
||||
- Keep plans short: Summary, Decisions/Constraints, Deliverables, Exit Criteria, and Validation.
|
||||
- Archive completed/idle (>14 days) plans to `archive/` with a dated filename. Avoid keeping multiple revisions at the root.
|
||||
|
||||
## Staying in sync
|
||||
- Every plan should reference the coordination board entry that tracks the same work.
|
||||
- When scope or status changes, update the plan in place—do not create a new Markdown file.
|
||||
- If a plan is superseded by an initiative doc, add a pointer and move the older plan to `archive/`.
|
||||
|
||||
## Current priorities
|
||||
- Active release/initiative specs live under `docs/internal/agents/` (e.g., `initiative-v040.md`). Start there before drafting a new plan here.
|
||||
- Active plans in this directory: `web_port_strategy.md`, `ai-infra-improvements.md`.
|
||||
- Archived plans (partially implemented or completed reference documents): see `archive/plans-2025-11/` for historical context.
|
||||
|
||||
## Naming
|
||||
- Avoid ALL-CAPS filenames except established anchors (README, AGENTS, GEMINI, CLAUDE, CONTRIBUTING, etc.). Use kebab-case for new plans.
|
||||
@@ -1,585 +0,0 @@
|
||||
# AI-Assisted Development Workflow Plan
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document outlines a practical AI-assisted development workflow for the yaze project, enabling AI agents to help developers during both yaze development and ROM hack debugging. The system leverages existing infrastructure (gRPC services, tool dispatcher, emulator integration) to deliver immediate value with minimal new development.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Core Components
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ z3ed CLI │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ AI Service Factory │ │
|
||||
│ │ (Ollama/Gemini/Mock Providers) │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ Agent Orchestrator │ │
|
||||
│ │ (Conversational + Tool Dispatcher) │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌────────────┴────────────┐ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ Dev Mode │ │ Debug Mode │ │
|
||||
│ │ Agent │ │ Agent │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ Tool Dispatcher │ │
|
||||
│ │ • FileSystemTool • EmulatorTool │ │
|
||||
│ │ • BuildTool • DisassemblyTool │ │
|
||||
│ │ • TestRunner • MemoryInspector │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
│
|
||||
┌────────────────┼────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│Build System │ │ Emulator │ │ ROM Editor │
|
||||
│(CMake/Ninja) │ │ (via gRPC) │ │ (via Tools) │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
### Existing Infrastructure (Ready to Use)
|
||||
|
||||
1. **EmulatorServiceImpl** (`src/cli/service/agent/emulator_service_impl.cc`)
|
||||
- Full debugger control via gRPC
|
||||
- Breakpoints, watchpoints, memory inspection
|
||||
- Execution control (step, run, pause)
|
||||
- Disassembly and trace capabilities
|
||||
|
||||
2. **ToolDispatcher** (`src/cli/service/agent/tool_dispatcher.h`)
|
||||
- Extensible tool system
|
||||
- Already supports ROM operations, GUI automation
|
||||
- Easy to add new tools (FileSystem, Build, etc.)
|
||||
|
||||
3. **Disassembler65816** (`src/cli/service/agent/disassembler_65816.h`)
|
||||
- Full 65816 instruction decoding
|
||||
- Execution trace buffer
|
||||
- CPU state snapshots
|
||||
|
||||
4. **AI Service Integration**
|
||||
- Ollama and Gemini providers implemented
|
||||
- Conversational agent with tool calling
|
||||
- Prompt builder with context management
|
||||
|
||||
5. **FileSystemTool** (Just implemented by CLAUDE_AIINF)
|
||||
- Safe read-only filesystem exploration
|
||||
- Project directory restriction
|
||||
- Binary file detection
|
||||
|
||||
## Mode 1: App Development Agent
|
||||
|
||||
### Purpose
|
||||
Help developers while coding yaze itself - catch errors, run tests, analyze crashes, suggest improvements.
|
||||
|
||||
### Key Features
|
||||
|
||||
#### 1.1 Build Monitoring & Error Resolution
|
||||
```yaml
|
||||
Triggers:
|
||||
- Compilation error detected
|
||||
- Link failure
|
||||
- CMake configuration issue
|
||||
|
||||
Agent Actions:
|
||||
- Parse error messages
|
||||
- Analyze include paths and dependencies
|
||||
- Suggest fixes with code snippets
|
||||
- Check for common pitfalls (circular deps, missing headers)
|
||||
|
||||
Tools Used:
|
||||
- BuildTool (configure, compile, status)
|
||||
- FileSystemTool (read source files)
|
||||
- TestRunner (verify fixes)
|
||||
```
|
||||
|
||||
#### 1.2 Crash Analysis
|
||||
```yaml
|
||||
Triggers:
|
||||
- Segmentation fault
|
||||
- Assertion failure
|
||||
- Stack overflow
|
||||
|
||||
Agent Actions:
|
||||
- Parse stack trace
|
||||
- Read relevant source files
|
||||
- Analyze call chain
|
||||
- Suggest root cause and fix
|
||||
- Check for similar patterns in codebase
|
||||
|
||||
Tools Used:
|
||||
- FileSystemTool (read crash context)
|
||||
- BuildTool (recompile with debug symbols)
|
||||
- TestRunner (reproduce crash)
|
||||
```
|
||||
|
||||
#### 1.3 Test Automation
|
||||
```yaml
|
||||
Triggers:
|
||||
- Code changes detected
|
||||
- Manual test request
|
||||
- Pre-commit hook
|
||||
|
||||
Agent Actions:
|
||||
- Identify affected test suites
|
||||
- Run relevant tests
|
||||
- Parse test output
|
||||
- Suggest test additions for uncovered code
|
||||
- Generate test cases for new functions
|
||||
|
||||
Tools Used:
|
||||
- TestRunner (execute tests)
|
||||
- FileSystemTool (analyze coverage)
|
||||
- BuildTool (compile test targets)
|
||||
```
|
||||
|
||||
#### 1.4 Performance Analysis
|
||||
```yaml
|
||||
Triggers:
|
||||
- Performance regression detected
|
||||
- Manual profiling request
|
||||
- CI benchmark failure
|
||||
|
||||
Agent Actions:
|
||||
- Run performance benchmarks
|
||||
- Compare with baseline
|
||||
- Identify hot spots
|
||||
- Suggest optimization strategies
|
||||
- Check for common inefficiencies
|
||||
|
||||
Tools Used:
|
||||
- TestRunner (run benchmarks)
|
||||
- FileSystemTool (analyze code)
|
||||
- BuildTool (compile with profiling)
|
||||
```
|
||||
|
||||
### Example Workflow: Compilation Error
|
||||
|
||||
```bash
|
||||
# Developer encounters error
|
||||
$ cmake --build build_ai
|
||||
[ERROR] snes_color.cc:45: 'gfx::Arena' has not been declared
|
||||
|
||||
# Agent automatically kicks in
|
||||
$ z3ed agent dev-assist --monitor-build
|
||||
|
||||
AI: I detected a compilation error. Let me analyze...
|
||||
|
||||
[Reading src/app/gfx/snes_color.cc]
|
||||
[Checking include paths]
|
||||
[Searching for gfx::Arena definition]
|
||||
|
||||
Found the issue! The file is missing:
|
||||
#include "app/gfx/arena.h"
|
||||
|
||||
The Arena class is defined in app/gfx/arena.h but not included.
|
||||
Here's the fix:
|
||||
|
||||
--- a/src/app/gfx/snes_color.cc
|
||||
+++ b/src/app/gfx/snes_color.cc
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "app/gfx/bitmap.h"
|
||||
+#include "app/gfx/arena.h"
|
||||
|
||||
Would you like me to:
|
||||
1. Apply this fix and rebuild?
|
||||
2. Check for similar missing includes?
|
||||
3. Run tests after fixing?
|
||||
```
|
||||
|
||||
## Mode 2: Zelda Hack Debugging Agent
|
||||
|
||||
### Purpose
|
||||
Help ROM hackers debug ASM patches, understand crashes, analyze game state during development.
|
||||
|
||||
### Key Features
|
||||
|
||||
#### 2.1 Breakpoint Analysis
|
||||
```yaml
|
||||
Triggers:
|
||||
- Breakpoint hit in emulator
|
||||
- Manual disassembly request
|
||||
- Crash during ROM execution
|
||||
|
||||
Agent Actions:
|
||||
- Disassemble current location
|
||||
- Explain instruction sequence
|
||||
- Show call stack
|
||||
- Analyze register values
|
||||
- Suggest what the code is doing
|
||||
|
||||
Tools Used:
|
||||
- EmulatorTool (control execution)
|
||||
- DisassemblyTool (decode instructions)
|
||||
- MemoryInspector (read RAM/ROM)
|
||||
```
|
||||
|
||||
#### 2.2 Memory State Analysis
|
||||
```yaml
|
||||
Triggers:
|
||||
- Watchpoint triggered
|
||||
- Manual memory inspection
|
||||
- Corruption detected
|
||||
|
||||
Agent Actions:
|
||||
- Read memory regions
|
||||
- Compare with known structures
|
||||
- Identify data types (sprites, tiles, etc.)
|
||||
- Track memory modifications
|
||||
- Suggest corruption sources
|
||||
|
||||
Tools Used:
|
||||
- MemoryInspector (read/monitor memory)
|
||||
- EmulatorTool (set watchpoints)
|
||||
- ResourceTool (correlate with ROM data)
|
||||
```
|
||||
|
||||
#### 2.3 ASM Patch Debugging
|
||||
```yaml
|
||||
Triggers:
|
||||
- Patch causes crash
|
||||
- Unexpected behavior after patch
|
||||
- Hook not executing
|
||||
|
||||
Agent Actions:
|
||||
- Compare patched vs original code
|
||||
- Trace execution flow
|
||||
- Verify jump targets
|
||||
- Check for stack imbalance
|
||||
- Validate addressing modes
|
||||
|
||||
Tools Used:
|
||||
- DisassemblyTool (analyze patches)
|
||||
- EmulatorTool (trace execution)
|
||||
- DiffTool (compare ROM regions)
|
||||
```
|
||||
|
||||
#### 2.4 Routine Tracing
|
||||
```yaml
|
||||
Triggers:
|
||||
- Need to understand game routine
|
||||
- Reverse engineering request
|
||||
- Finding hook points
|
||||
|
||||
Agent Actions:
|
||||
- Trace routine execution
|
||||
- Document register usage
|
||||
- Map memory accesses
|
||||
- Identify subroutine calls
|
||||
- Generate routine documentation
|
||||
|
||||
Tools Used:
|
||||
- EmulatorTool (step through code)
|
||||
- DisassemblyTool (decode instructions)
|
||||
- SymbolProvider (resolve addresses)
|
||||
```
|
||||
|
||||
### Example Workflow: Debugging ROM Crash
|
||||
|
||||
```bash
|
||||
# ROM hacker experiences crash
|
||||
$ z3ed agent debug-rom --rom=my_hack.sfc --emulator-port=50051
|
||||
|
||||
AI: Connected to emulator. Setting up debugging session...
|
||||
|
||||
[Emulator paused at crash point]
|
||||
Address: $0A:8234
|
||||
Instruction: STA $7E2000,X
|
||||
Registers: A=$FFFF X=$8000 Y=$0000
|
||||
|
||||
AI: I see the crash! You're writing to $7E:A000 (WRAM mirror + $8000).
|
||||
This is out of bounds for WRAM ($7E0000-$7FFFFF).
|
||||
|
||||
Let me trace back to see how X got this value...
|
||||
|
||||
[Analyzing execution trace]
|
||||
5 instructions ago at $0A:8220:
|
||||
LDX $1A ; Loaded X from $1A (value was $8000)
|
||||
|
||||
The issue is $1A contains $8000 when it should be < $2000.
|
||||
This variable appears to be an index into the sprite table.
|
||||
|
||||
Possible causes:
|
||||
1. Sprite index overflow (too many sprites)
|
||||
2. Uninitialized memory at $1A
|
||||
3. Calculation error in previous routine
|
||||
|
||||
Would you like me to:
|
||||
1. Set a watchpoint on $1A to find what's setting it?
|
||||
2. Analyze the routine that calculates sprite indices?
|
||||
3. Check for similar boundary issues in your patches?
|
||||
```
|
||||
|
||||
## Required New Components
|
||||
|
||||
### Phase 1: Core Tools (1-2 days)
|
||||
1. **BuildTool** - CMake/Ninja integration
|
||||
- Configure, compile, test commands
|
||||
- Parse build output for errors
|
||||
- Status monitoring
|
||||
|
||||
2. **TestRunner** - CTest integration
|
||||
- Run specific test suites
|
||||
- Parse test results
|
||||
- Coverage analysis
|
||||
|
||||
3. **MemoryInspector** - Enhanced memory tools
|
||||
- Structured memory reads
|
||||
- Pattern matching
|
||||
- Corruption detection
|
||||
|
||||
### Phase 2: Agent Modes (2-3 days)
|
||||
1. **DevAssistAgent** - Development helper
|
||||
- Build monitoring loop
|
||||
- Error pattern matching
|
||||
- Solution suggestion engine
|
||||
|
||||
2. **RomDebugAgent** - ROM hacking assistant
|
||||
- Emulator connection manager
|
||||
- Crash analysis engine
|
||||
- Patch verification system
|
||||
|
||||
### Phase 3: Enhanced Integration (3-5 days)
|
||||
1. **Continuous Monitoring**
|
||||
- File watcher for auto-rebuild
|
||||
- Test runner on file changes
|
||||
- Performance regression detection
|
||||
|
||||
2. **Context Management**
|
||||
- Project state tracking
|
||||
- History of issues and fixes
|
||||
- Learning from past solutions
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Foundation (Week 1)
|
||||
**Goal**: Basic tool infrastructure
|
||||
**Deliverables**:
|
||||
- BuildTool implementation
|
||||
- TestRunner implementation
|
||||
- Basic DevAssistAgent with build monitoring
|
||||
- Command: `z3ed agent dev-assist --monitor`
|
||||
|
||||
### Phase 2: Debugging (Week 2)
|
||||
**Goal**: ROM debugging capabilities
|
||||
**Deliverables**:
|
||||
- MemoryInspector enhancements
|
||||
- RomDebugAgent implementation
|
||||
- Emulator integration improvements
|
||||
- Command: `z3ed agent debug-rom --rom=<file>`
|
||||
|
||||
### Phase 3: Intelligence (Week 3)
|
||||
**Goal**: Smart analysis and suggestions
|
||||
**Deliverables**:
|
||||
- Error pattern database
|
||||
- Solution suggestion engine
|
||||
- Context-aware responses
|
||||
- Test generation capabilities
|
||||
|
||||
### Phase 4: Polish (Week 4)
|
||||
**Goal**: Production readiness
|
||||
**Deliverables**:
|
||||
- Performance optimization
|
||||
- Documentation and tutorials
|
||||
- Example workflows
|
||||
- Integration tests
|
||||
|
||||
## Integration Points
|
||||
|
||||
### With Existing Code
|
||||
|
||||
1. **ToolDispatcher** (`tool_dispatcher.h`)
|
||||
```cpp
|
||||
// Add new tool types
|
||||
enum class ToolCallType {
|
||||
// ... existing ...
|
||||
kBuildConfigure,
|
||||
kBuildCompile,
|
||||
kBuildTest,
|
||||
kMemoryRead,
|
||||
kMemoryWatch,
|
||||
kTestRun,
|
||||
kTestCoverage,
|
||||
};
|
||||
```
|
||||
|
||||
2. **ConversationalAgentService**
|
||||
```cpp
|
||||
// Add agent modes
|
||||
class DevAssistAgent : public AgentMode {
|
||||
void MonitorBuild();
|
||||
void AnalyzeCrash(const StackTrace& trace);
|
||||
void SuggestFix(const CompileError& error);
|
||||
};
|
||||
```
|
||||
|
||||
3. **EmulatorService**
|
||||
```cpp
|
||||
// Enhance debugging APIs
|
||||
class DebugSession {
|
||||
void SetAutomaticAnalysis(bool enabled);
|
||||
void RegisterCrashHandler(CrashCallback cb);
|
||||
void EnableInstructionTrace(size_t buffer_size);
|
||||
};
|
||||
```
|
||||
|
||||
### With CI/CD Pipeline
|
||||
|
||||
1. **GitHub Actions Integration**
|
||||
```yaml
|
||||
- name: AI-Assisted Build Check
|
||||
run: |
|
||||
z3ed agent dev-assist --ci-mode \
|
||||
--analyze-errors \
|
||||
--suggest-fixes \
|
||||
--output=ai-analysis.md
|
||||
```
|
||||
|
||||
2. **Pre-commit Hooks**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# .git/hooks/pre-commit
|
||||
z3ed agent dev-assist --check-changes \
|
||||
--run-affected-tests \
|
||||
--verify-no-regressions
|
||||
```
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Workflow 1: AI-Assisted TDD
|
||||
```bash
|
||||
# Developer writes test first
|
||||
$ cat > test/unit/my_feature_test.cc << EOF
|
||||
TEST(MyFeature, ShouldDoSomething) {
|
||||
MyClass obj;
|
||||
EXPECT_EQ(obj.Process(5), 10);
|
||||
}
|
||||
EOF
|
||||
|
||||
# AI generates implementation
|
||||
$ z3ed agent generate --from-test=test/unit/my_feature_test.cc
|
||||
|
||||
AI: Based on your test, here's a suggested implementation:
|
||||
|
||||
class MyClass {
|
||||
public:
|
||||
int Process(int input) {
|
||||
return input * 2; // Doubles the input based on test expectation
|
||||
}
|
||||
};
|
||||
|
||||
Shall I create src/app/my_class.h with this implementation?
|
||||
```
|
||||
|
||||
### Workflow 2: Crash During ROM Testing
|
||||
```bash
|
||||
# Developer testing ROM modifications
|
||||
$ z3ed agent debug-rom --rom=hack.sfc --auto-debug
|
||||
|
||||
AI: Monitoring emulator for issues...
|
||||
|
||||
[CRASH DETECTED at $15:A0F2]
|
||||
Illegal instruction: $42 (WDM - disabled on SNES)
|
||||
|
||||
This appears to be data executed as code. Analyzing...
|
||||
|
||||
The jump at $15:A0E0 uses indirect addressing: JMP ($0234)
|
||||
The value at $0234 is $A0F2, which points to sprite data, not code.
|
||||
|
||||
Likely cause: Corrupted pointer table at $0234.
|
||||
|
||||
Suggested fix:
|
||||
1. Check your modifications to pointer tables
|
||||
2. The original value at $0234 should be $8CF2
|
||||
3. Look for code that writes to $0234-$0235
|
||||
|
||||
Would you like me to trace what modified this address?
|
||||
```
|
||||
|
||||
### Workflow 3: Performance Regression
|
||||
```bash
|
||||
# CI detects performance issue
|
||||
$ z3ed agent analyze-perf --baseline=main --current=HEAD
|
||||
|
||||
AI: Performance regression detected in gfx::Arena::LoadTile16
|
||||
|
||||
Baseline: 1.2ms average
|
||||
Current: 4.5ms average (275% slower)
|
||||
|
||||
Analyzing changes... Found the issue:
|
||||
|
||||
commit abc123: "Add texture validation"
|
||||
+ for (auto& pixel : tile.data()) {
|
||||
+ ValidatePixel(pixel); // This is called 256 times per tile
|
||||
+ }
|
||||
|
||||
The validation is happening in the hot path. Suggestions:
|
||||
1. Move validation to debug builds only
|
||||
2. Batch validation instead of per-pixel
|
||||
3. Use SIMD for validation if keeping it
|
||||
|
||||
Here's an optimized version:
|
||||
#ifdef DEBUG
|
||||
ValidateTileData(tile.data()); // Batch validation
|
||||
#endif
|
||||
```
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Immediate (Week 1)
|
||||
- Build error resolution time < 30 seconds
|
||||
- Basic test automation working
|
||||
- 5+ common error patterns recognized
|
||||
|
||||
### Short-term (Month 1)
|
||||
- 50% reduction in debugging time
|
||||
- 80% of build errors auto-resolved
|
||||
- 10+ developers using the tool
|
||||
|
||||
### Long-term (Quarter 1)
|
||||
- Comprehensive error pattern database
|
||||
- Integration with all major workflows
|
||||
- Measurable improvement in development velocity
|
||||
- Community contributions to agent capabilities
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
### Technical Risks
|
||||
1. **AI Model Limitations**
|
||||
- Mitigation: Fallback to pattern matching when AI unavailable
|
||||
- Use local models (Ollama) for offline capability
|
||||
|
||||
2. **Performance Impact**
|
||||
- Mitigation: Async processing, optional features
|
||||
- Configurable resource limits
|
||||
|
||||
3. **False Positives**
|
||||
- Mitigation: Confidence scoring, user confirmation
|
||||
- Learning from corrections
|
||||
|
||||
### Adoption Risks
|
||||
1. **Learning Curve**
|
||||
- Mitigation: Progressive disclosure, good defaults
|
||||
- Comprehensive examples and documentation
|
||||
|
||||
2. **Trust Issues**
|
||||
- Mitigation: Explainable suggestions, show reasoning
|
||||
- Allow manual override always
|
||||
|
||||
## Conclusion
|
||||
|
||||
This AI-assisted development workflow leverages yaze's existing infrastructure to provide immediate value with minimal new development. The phased approach ensures quick wins while building toward comprehensive AI assistance for both yaze development and ROM hacking workflows.
|
||||
|
||||
The system is designed to be:
|
||||
- **Practical**: Uses existing components, minimal new code
|
||||
- **Incremental**: Each phase delivers working features
|
||||
- **Extensible**: Easy to add new capabilities
|
||||
- **Reliable**: Fallbacks for when AI is unavailable
|
||||
|
||||
With just 1-2 weeks of development, we can have a working system that significantly improves developer productivity and ROM hacking debugging capabilities.
|
||||
@@ -1,8 +1,12 @@
|
||||
# AI Infrastructure Improvements Plan
|
||||
|
||||
**Branch:** `feature/ai-infra-improvements`
|
||||
**Created:** 2025-11-21
|
||||
**Status:** Planning
|
||||
**Status:** Active
|
||||
**Owner (Agent ID):** ai-infra-architect
|
||||
**Branch:** `feature/ai-infra-improvements`
|
||||
**Created:** 2025-11-21
|
||||
**Last Updated:** 2025-11-25
|
||||
**Next Review:** 2025-12-02
|
||||
**Coordination Board Entry:** link when claimed
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,818 +0,0 @@
|
||||
# App Development Agent Tools Specification
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Date**: 2025-11-22
|
||||
**Author**: CLAUDE_AIINF
|
||||
**Purpose**: Define tools that enable AI agents to assist with yaze C++ development
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document specifies new tools for the yaze AI agent system that enable agents to assist with C++ application development. These tools complement existing ROM manipulation and editor tools by providing build system interaction, code analysis, debugging assistance, and editor integration capabilities.
|
||||
|
||||
## Tool Architecture Overview
|
||||
|
||||
### Integration Points
|
||||
- **ToolDispatcher**: Central routing via `src/cli/service/agent/tool_dispatcher.cc`
|
||||
- **CommandHandler Pattern**: All tools inherit from `resources::CommandHandler`
|
||||
- **Output Formatting**: JSON and text formats via `resources::OutputFormatter`
|
||||
- **Security Model**: Sandboxed execution, project-restricted access
|
||||
- **Async Support**: Long-running operations use background execution
|
||||
|
||||
## Tool Specifications
|
||||
|
||||
### 1. Build System Tools
|
||||
|
||||
#### 1.1 build_configure
|
||||
**Purpose**: Configure CMake build with appropriate presets and options
|
||||
**Priority**: P0 (Critical for MVP)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct BuildConfigureParams {
|
||||
std::string preset; // e.g., "mac-dbg", "lin-ai", "win-rel"
|
||||
std::string build_dir; // e.g., "build_ai" (default: "build")
|
||||
bool clean_build; // Remove existing build directory first
|
||||
std::vector<std::string> options; // Additional CMake options
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"preset": "mac-dbg",
|
||||
"build_directory": "/Users/scawful/Code/yaze/build_ai",
|
||||
"cmake_version": "3.28.0",
|
||||
"compiler": "AppleClang 15.0.0.15000100",
|
||||
"options_applied": ["YAZE_ENABLE_AI=ON", "YAZE_ENABLE_GRPC=ON"]
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation Approach**:
|
||||
- Execute `cmake --preset <preset>` via subprocess
|
||||
- Parse CMakeCache.txt for configuration details
|
||||
- Validate preset exists in CMakePresets.json
|
||||
- Support parallel build directories for agent isolation
|
||||
|
||||
---
|
||||
|
||||
#### 1.2 build_compile
|
||||
**Purpose**: Trigger compilation of specific targets or entire project
|
||||
**Priority**: P0 (Critical for MVP)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct BuildCompileParams {
|
||||
std::string build_dir; // Build directory (default: "build")
|
||||
std::string target; // Specific target or "all"
|
||||
int jobs; // Parallel jobs (default: CPU count)
|
||||
bool verbose; // Show detailed compiler output
|
||||
bool continue_on_error; // Continue building after errors
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"status": "failed",
|
||||
"target": "yaze",
|
||||
"errors": [
|
||||
{
|
||||
"file": "src/app/editor/overworld_editor.cc",
|
||||
"line": 234,
|
||||
"column": 15,
|
||||
"severity": "error",
|
||||
"message": "use of undeclared identifier 'LoadGraphics'",
|
||||
"context": " LoadGraphics();"
|
||||
}
|
||||
],
|
||||
"warnings_count": 12,
|
||||
"build_time_seconds": 45.3,
|
||||
"artifacts": ["bin/yaze", "bin/z3ed"]
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation Approach**:
|
||||
- Execute `cmake --build <dir> --target <target> -j<jobs>`
|
||||
- Parse compiler output with regex patterns for errors/warnings
|
||||
- Track build timing and resource usage
|
||||
- Support incremental builds and error recovery
|
||||
|
||||
---
|
||||
|
||||
#### 1.3 build_test
|
||||
**Purpose**: Execute test suites with filtering and result parsing
|
||||
**Priority**: P0 (Critical for MVP)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct BuildTestParams {
|
||||
std::string build_dir; // Build directory
|
||||
std::string suite; // Test suite: "unit", "integration", "e2e", "all"
|
||||
std::string filter; // Test name filter (gtest pattern)
|
||||
bool rom_dependent; // Include ROM-dependent tests
|
||||
std::string rom_path; // Path to ROM file (if rom_dependent)
|
||||
bool show_output; // Display test output
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"status": "failed",
|
||||
"suite": "unit",
|
||||
"tests_run": 156,
|
||||
"tests_passed": 154,
|
||||
"tests_failed": 2,
|
||||
"failures": [
|
||||
{
|
||||
"test_name": "SnesColorTest.ConvertRgbToSnes",
|
||||
"file": "test/unit/gfx/snes_color_test.cc",
|
||||
"line": 45,
|
||||
"failure_message": "Expected: 0x7FFF\n Actual: 0x7FFE"
|
||||
}
|
||||
],
|
||||
"execution_time_seconds": 12.4,
|
||||
"coverage_percent": 78.3
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation Approach**:
|
||||
- Execute ctest with appropriate labels and filters
|
||||
- Parse test output XML (if available) or stdout
|
||||
- Support test discovery and listing
|
||||
- Handle timeouts and crashes gracefully
|
||||
|
||||
---
|
||||
|
||||
#### 1.4 build_status
|
||||
**Purpose**: Query current build system state and configuration
|
||||
**Priority**: P1 (Important for debugging)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct BuildStatusParams {
|
||||
std::string build_dir; // Build directory to inspect
|
||||
bool show_cache; // Include CMakeCache variables
|
||||
bool show_targets; // List available build targets
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"configured": true,
|
||||
"preset": "mac-dbg",
|
||||
"last_build": "2025-11-22T10:30:00Z",
|
||||
"targets_available": ["yaze", "z3ed", "yaze_test", "format"],
|
||||
"configuration": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"YAZE_ENABLE_AI": "ON",
|
||||
"YAZE_ENABLE_GRPC": "ON"
|
||||
},
|
||||
"dirty_files": ["src/app/editor/overworld_editor.cc"],
|
||||
"build_dependencies_outdated": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Code Analysis Tools
|
||||
|
||||
#### 2.1 find_symbol
|
||||
**Purpose**: Locate class, function, or variable definitions in codebase
|
||||
**Priority**: P0 (Critical for navigation)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct FindSymbolParams {
|
||||
std::string symbol_name; // Name to search for
|
||||
std::string symbol_type; // "class", "function", "variable", "any"
|
||||
std::string scope; // Directory scope (default: "src/")
|
||||
bool include_declarations; // Include forward declarations
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"symbol": "OverworldEditor",
|
||||
"type": "class",
|
||||
"locations": [
|
||||
{
|
||||
"file": "src/app/editor/overworld/overworld_editor.h",
|
||||
"line": 45,
|
||||
"kind": "definition",
|
||||
"context": "class OverworldEditor : public Editor {"
|
||||
},
|
||||
{
|
||||
"file": "src/app/editor/overworld/overworld_editor.cc",
|
||||
"line": 23,
|
||||
"kind": "implementation",
|
||||
"context": "OverworldEditor::OverworldEditor() {"
|
||||
}
|
||||
],
|
||||
"base_classes": ["Editor"],
|
||||
"derived_classes": [],
|
||||
"namespace": "yaze::app::editor"
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation Approach**:
|
||||
- Use ctags/cscope database if available
|
||||
- Fall back to intelligent grep patterns
|
||||
- Parse include guards and namespace blocks
|
||||
- Cache symbol database for performance
|
||||
|
||||
---
|
||||
|
||||
#### 2.2 get_call_hierarchy
|
||||
**Purpose**: Analyze function call relationships
|
||||
**Priority**: P1 (Important for refactoring)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct CallHierarchyParams {
|
||||
std::string function_name; // Function to analyze
|
||||
std::string direction; // "callers", "callees", "both"
|
||||
int max_depth; // Recursion depth (default: 3)
|
||||
bool include_virtual; // Track virtual function calls
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"function": "Rom::LoadFromFile",
|
||||
"callers": [
|
||||
{
|
||||
"function": "EditorManager::OpenRom",
|
||||
"file": "src/app/editor/editor_manager.cc",
|
||||
"line": 156,
|
||||
"call_sites": [{"line": 162, "context": "rom_->LoadFromFile(path)"}]
|
||||
}
|
||||
],
|
||||
"callees": [
|
||||
{
|
||||
"function": "Rom::ReadAllGraphicsData",
|
||||
"file": "src/app/rom.cc",
|
||||
"line": 234,
|
||||
"is_virtual": false
|
||||
}
|
||||
],
|
||||
"complexity_score": 12
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 2.3 get_class_members
|
||||
**Purpose**: List all methods and fields of a class
|
||||
**Priority**: P1 (Important for understanding)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct ClassMembersParams {
|
||||
std::string class_name; // Class to analyze
|
||||
bool include_inherited; // Include base class members
|
||||
bool include_private; // Include private members
|
||||
std::string filter; // Filter by member name pattern
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"class": "OverworldEditor",
|
||||
"namespace": "yaze::app::editor",
|
||||
"members": {
|
||||
"methods": [
|
||||
{
|
||||
"name": "Update",
|
||||
"signature": "absl::Status Update() override",
|
||||
"visibility": "public",
|
||||
"is_virtual": true,
|
||||
"line": 67
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"name": "current_map_",
|
||||
"type": "int",
|
||||
"visibility": "private",
|
||||
"line": 234,
|
||||
"has_getter": true,
|
||||
"has_setter": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_classes": ["Editor"],
|
||||
"total_methods": 42,
|
||||
"total_fields": 18
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 2.4 analyze_includes
|
||||
**Purpose**: Show include dependency graph
|
||||
**Priority**: P2 (Useful for optimization)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct AnalyzeIncludesParams {
|
||||
std::string file_path; // File to analyze
|
||||
std::string direction; // "includes", "included_by", "both"
|
||||
bool show_system; // Include system headers
|
||||
int max_depth; // Recursion depth
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"file": "src/app/editor/overworld_editor.cc",
|
||||
"direct_includes": [
|
||||
{"file": "overworld_editor.h", "is_system": false},
|
||||
{"file": "app/rom.h", "is_system": false},
|
||||
{"file": <vector>", "is_system": true}
|
||||
],
|
||||
"included_by": [
|
||||
"src/app/editor/editor_manager.cc"
|
||||
],
|
||||
"include_depth": 3,
|
||||
"circular_dependencies": [],
|
||||
"suggestions": ["Consider forward declaration for 'Rom' class"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Debug Tools
|
||||
|
||||
#### 3.1 parse_crash_log
|
||||
**Purpose**: Extract actionable information from crash dumps
|
||||
**Priority**: P0 (Critical for debugging)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct ParseCrashLogParams {
|
||||
std::string log_path; // Path to crash log or stdin
|
||||
std::string platform; // "macos", "linux", "windows", "auto"
|
||||
bool symbolicate; // Attempt to resolve symbols
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"crash_type": "SIGSEGV",
|
||||
"crash_address": "0x00000000",
|
||||
"crashed_thread": 0,
|
||||
"stack_trace": [
|
||||
{
|
||||
"frame": 0,
|
||||
"address": "0x10234abcd",
|
||||
"symbol": "yaze::app::editor::OverworldEditor::RenderMap",
|
||||
"file": "src/app/editor/overworld_editor.cc",
|
||||
"line": 456,
|
||||
"is_user_code": true
|
||||
}
|
||||
],
|
||||
"likely_cause": "Null pointer dereference in RenderMap",
|
||||
"suggested_fixes": [
|
||||
"Check if 'current_map_data_' is initialized before use",
|
||||
"Add null check at line 456"
|
||||
],
|
||||
"similar_crashes": ["#1234 - Fixed in commit abc123"]
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation Approach**:
|
||||
- Parse platform-specific crash formats (lldb, gdb, Windows dumps)
|
||||
- Symbolicate addresses using debug symbols
|
||||
- Identify patterns (null deref, stack overflow, etc.)
|
||||
- Search issue tracker for similar crashes
|
||||
|
||||
---
|
||||
|
||||
#### 3.2 get_memory_profile
|
||||
**Purpose**: Analyze memory usage and detect leaks
|
||||
**Priority**: P2 (Useful for optimization)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct MemoryProfileParams {
|
||||
std::string process_name; // Process to analyze or PID
|
||||
std::string profile_type; // "snapshot", "leaks", "allocations"
|
||||
int duration_seconds; // For allocation profiling
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"total_memory_mb": 234.5,
|
||||
"heap_size_mb": 180.2,
|
||||
"largest_allocations": [
|
||||
{
|
||||
"size_mb": 45.6,
|
||||
"location": "gfx::Arena::LoadAllGraphics",
|
||||
"count": 223,
|
||||
"type": "gfx::Bitmap"
|
||||
}
|
||||
],
|
||||
"potential_leaks": [
|
||||
{
|
||||
"size_bytes": 1024,
|
||||
"allocation_site": "CreateTempBuffer at editor.cc:123",
|
||||
"leak_confidence": 0.85
|
||||
}
|
||||
],
|
||||
"memory_growth_rate_mb_per_min": 2.3
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 3.3 analyze_performance
|
||||
**Purpose**: Profile performance hotspots
|
||||
**Priority**: P2 (Useful for optimization)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct PerformanceAnalysisParams {
|
||||
std::string target; // Binary or test to profile
|
||||
std::string scenario; // Specific scenario to profile
|
||||
int duration_seconds; // Profiling duration
|
||||
std::string metric; // "cpu", "memory", "io", "all"
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"hotspots": [
|
||||
{
|
||||
"function": "gfx::Bitmap::ApplyPalette",
|
||||
"cpu_percent": 23.4,
|
||||
"call_count": 1000000,
|
||||
"avg_duration_us": 12.3,
|
||||
"file": "src/app/gfx/bitmap.cc",
|
||||
"line": 234
|
||||
}
|
||||
],
|
||||
"bottlenecks": [
|
||||
"Graphics rendering taking 65% of frame time",
|
||||
"Excessive allocations in tile loading"
|
||||
],
|
||||
"optimization_suggestions": [
|
||||
"Cache palette conversions",
|
||||
"Use SIMD for pixel operations"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Editor Integration Tools
|
||||
|
||||
#### 4.1 get_canvas_state
|
||||
**Purpose**: Query current canvas/editor state for context
|
||||
**Priority**: P1 (Important for automation)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct CanvasStateParams {
|
||||
std::string editor_type; // "overworld", "dungeon", "graphics"
|
||||
bool include_selection; // Include selected entities
|
||||
bool include_viewport; // Include camera/zoom info
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"editor": "overworld",
|
||||
"current_map": 0x00,
|
||||
"map_name": "Hyrule Field",
|
||||
"viewport": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"zoom": 2.0
|
||||
},
|
||||
"selection": {
|
||||
"type": "entrance",
|
||||
"id": 0x03,
|
||||
"position": {"x": 256, "y": 128}
|
||||
},
|
||||
"tool": "select",
|
||||
"modified": true,
|
||||
"undo_stack_size": 15
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation Approach**:
|
||||
- Query EditorManager for active editor
|
||||
- Use Canvas automation API for state extraction
|
||||
- Serialize entity selections and properties
|
||||
- Include modification tracking
|
||||
|
||||
---
|
||||
|
||||
#### 4.2 simulate_user_action
|
||||
**Purpose**: Trigger UI actions programmatically
|
||||
**Priority**: P1 (Important for automation)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct SimulateActionParams {
|
||||
std::string action_type; // "click", "drag", "key", "menu"
|
||||
nlohmann::json parameters; // Action-specific parameters
|
||||
std::string editor_context; // Which editor to target
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"action": "click",
|
||||
"target": "tile_palette",
|
||||
"position": {"x": 100, "y": 50},
|
||||
"result": "success",
|
||||
"new_selection": {
|
||||
"tile_id": 0x42,
|
||||
"tile_type": "grass"
|
||||
},
|
||||
"side_effects": ["Tool changed to 'paint'"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 4.3 capture_screenshot
|
||||
**Purpose**: Capture editor visuals for verification or documentation
|
||||
**Priority**: P2 (Useful for testing)
|
||||
|
||||
**Parameters**:
|
||||
```cpp
|
||||
struct ScreenshotParams {
|
||||
std::string output_path; // Where to save screenshot
|
||||
std::string target; // "full", "canvas", "window"
|
||||
std::string format; // "png", "jpg", "bmp"
|
||||
bool include_ui; // Include UI overlays
|
||||
};
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"file_path": "/tmp/screenshot_2025_11_22_103045.png",
|
||||
"dimensions": {"width": 1920, "height": 1080},
|
||||
"file_size_kb": 234,
|
||||
"metadata": {
|
||||
"editor": "overworld",
|
||||
"map_id": "0x00",
|
||||
"timestamp": "2025-11-22T10:30:45Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Roadmap
|
||||
|
||||
### Phase 1: MVP (Week 1)
|
||||
**Priority P0 tools only**
|
||||
1. `build_compile` - Essential for development iteration
|
||||
2. `build_test` - Required for validation
|
||||
3. `find_symbol` - Core navigation capability
|
||||
4. `parse_crash_log` - Critical debugging tool
|
||||
|
||||
### Phase 2: Enhanced (Week 2)
|
||||
**Priority P1 tools**
|
||||
1. `build_configure` - Build system management
|
||||
2. `build_status` - State inspection
|
||||
3. `get_call_hierarchy` - Code understanding
|
||||
4. `get_class_members` - API exploration
|
||||
5. `get_canvas_state` - Editor integration
|
||||
6. `simulate_user_action` - Automation capability
|
||||
|
||||
### Phase 3: Complete (Week 3)
|
||||
**Priority P2 tools**
|
||||
1. `analyze_includes` - Optimization support
|
||||
2. `get_memory_profile` - Memory debugging
|
||||
3. `analyze_performance` - Performance tuning
|
||||
4. `capture_screenshot` - Visual verification
|
||||
|
||||
## Integration with Existing Infrastructure
|
||||
|
||||
### ToolDispatcher Integration
|
||||
|
||||
Add to `tool_dispatcher.h`:
|
||||
```cpp
|
||||
enum class ToolCallType {
|
||||
// ... existing types ...
|
||||
|
||||
// Build Tools
|
||||
kBuildConfigure,
|
||||
kBuildCompile,
|
||||
kBuildTest,
|
||||
kBuildStatus,
|
||||
|
||||
// Code Analysis
|
||||
kCodeFindSymbol,
|
||||
kCodeGetCallHierarchy,
|
||||
kCodeGetClassMembers,
|
||||
kCodeAnalyzeIncludes,
|
||||
|
||||
// Debug Tools
|
||||
kDebugParseCrashLog,
|
||||
kDebugGetMemoryProfile,
|
||||
kDebugAnalyzePerformance,
|
||||
|
||||
// Editor Integration
|
||||
kEditorGetCanvasState,
|
||||
kEditorSimulateAction,
|
||||
kEditorCaptureScreenshot,
|
||||
};
|
||||
```
|
||||
|
||||
### Handler Implementation Pattern
|
||||
|
||||
Each tool follows the CommandHandler pattern:
|
||||
|
||||
```cpp
|
||||
class BuildCompileCommandHandler : public resources::CommandHandler {
|
||||
public:
|
||||
std::string GetName() const override { return "build-compile"; }
|
||||
|
||||
std::string GetUsage() const override {
|
||||
return "build-compile --build-dir <dir> [--target <name>] "
|
||||
"[--jobs <n>] [--verbose] [--format <json|text>]";
|
||||
}
|
||||
|
||||
protected:
|
||||
absl::Status ValidateArgs(const resources::ArgumentParser& parser) override {
|
||||
// Validate required arguments
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Execute(Rom* rom, const resources::ArgumentParser& parser,
|
||||
resources::OutputFormatter& formatter) override {
|
||||
// Implementation
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
bool RequiresLabels() const override { return false; }
|
||||
};
|
||||
```
|
||||
|
||||
### Security Considerations
|
||||
|
||||
1. **Build System Tools**:
|
||||
- Restrict to project directory
|
||||
- Validate presets against CMakePresets.json
|
||||
- Sanitize compiler flags
|
||||
- Limit parallel jobs to prevent DoS
|
||||
|
||||
2. **Code Analysis Tools**:
|
||||
- Read-only operations only
|
||||
- Cache results to prevent excessive parsing
|
||||
- Timeout long-running analyses
|
||||
|
||||
3. **Debug Tools**:
|
||||
- Sanitize crash log paths
|
||||
- Limit profiling duration
|
||||
- Prevent access to system processes
|
||||
|
||||
4. **Editor Integration**:
|
||||
- Rate limit UI actions
|
||||
- Validate action parameters
|
||||
- Prevent infinite loops in automation
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- Mock subprocess execution for build tools
|
||||
- Test error parsing with known compiler outputs
|
||||
- Verify security restrictions (path traversal, etc.)
|
||||
|
||||
### Integration Tests
|
||||
- Test with real CMake builds (small test projects)
|
||||
- Verify symbol finding with known codebase structure
|
||||
- Test crash parsing with sample logs
|
||||
|
||||
### End-to-End Tests
|
||||
- Full development workflow automation
|
||||
- Build → Test → Debug cycle
|
||||
- Editor automation scenarios
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
1. **Caching**:
|
||||
- Symbol database caching (5-minute TTL)
|
||||
- Build status caching (invalidate on file changes)
|
||||
- Compiler error pattern cache
|
||||
|
||||
2. **Async Operations**:
|
||||
- Long builds run in background
|
||||
- Profiling operations are async
|
||||
- Support streaming output for progress
|
||||
|
||||
3. **Resource Limits**:
|
||||
- Max parallel build jobs = CPU count
|
||||
- Profiling duration cap = 5 minutes
|
||||
- Screenshot size limit = 10MB
|
||||
|
||||
## Success Metrics
|
||||
|
||||
1. **Developer Productivity**:
|
||||
- Reduce build debugging time by 50%
|
||||
- Enable AI agents to fix 80% of simple compilation errors
|
||||
- Automate 60% of test failure investigations
|
||||
|
||||
2. **Code Quality**:
|
||||
- Increase test coverage by 20% through AI-generated tests
|
||||
- Identify 90% of memory leaks before release
|
||||
- Reduce performance regressions by 40%
|
||||
|
||||
3. **Agent Capabilities**:
|
||||
- Agents can complete full edit-compile-test cycles
|
||||
- Agents can diagnose and suggest fixes for crashes
|
||||
- Agents can navigate and understand codebase structure
|
||||
|
||||
## Appendix A: Error Pattern Database
|
||||
|
||||
Common compilation error patterns for parsing:
|
||||
|
||||
```regex
|
||||
# GCC/Clang error
|
||||
^([^:]+):(\d+):(\d+):\s+(error|warning):\s+(.+)$
|
||||
|
||||
# MSVC error
|
||||
^([^(]+)\((\d+)\):\s+(error|warning)\s+(\w+):\s+(.+)$
|
||||
|
||||
# Linker error
|
||||
^(ld|link):\s+(error|warning):\s+(.+)$
|
||||
```
|
||||
|
||||
## Appendix B: Platform-Specific Considerations
|
||||
|
||||
### macOS
|
||||
- Use `xcrun` for toolchain discovery
|
||||
- Parse `.crash` files from `~/Library/Logs/DiagnosticReports/`
|
||||
- Support both x86_64 and arm64 architectures
|
||||
|
||||
### Linux
|
||||
- Check for gcc/g++ and clang/clang++
|
||||
- Parse core dumps with gdb
|
||||
- Use `perf` for profiling when available
|
||||
|
||||
### Windows
|
||||
- Handle both MSVC and MinGW toolchains
|
||||
- Parse `.dmp` files for crash analysis
|
||||
- Use Windows Performance Toolkit for profiling
|
||||
|
||||
## Appendix C: AI Agent Use Cases
|
||||
|
||||
### Use Case 1: Compilation Error Resolution
|
||||
```
|
||||
Agent: I see you have a compilation error in overworld_editor.cc
|
||||
Agent: Let me analyze the error...
|
||||
[Executes: build_compile --verbose]
|
||||
[Executes: find_symbol --symbol LoadGraphics]
|
||||
Agent: The function LoadGraphics was renamed to LoadAreaGraphics in commit abc123
|
||||
Agent: I'll update the call site...
|
||||
[Modifies file]
|
||||
[Executes: build_compile --target yaze]
|
||||
Agent: Build successful! The error is resolved.
|
||||
```
|
||||
|
||||
### Use Case 2: Test Failure Investigation
|
||||
```
|
||||
Agent: The SnesColorTest is failing. Let me investigate...
|
||||
[Executes: build_test --filter "*SnesColor*" --show-output]
|
||||
[Executes: get_class_members --class SnesColor]
|
||||
Agent: The test expects 0x7FFF but gets 0x7FFE
|
||||
Agent: This is a rounding error in the conversion function
|
||||
[Analyzes implementation]
|
||||
Agent: The issue is at line 45 - we need to round instead of truncate
|
||||
```
|
||||
|
||||
### Use Case 3: Performance Optimization
|
||||
```
|
||||
Agent: Let me profile the slow rendering...
|
||||
[Executes: analyze_performance --scenario "load_overworld"]
|
||||
Agent: I found that ApplyPalette takes 23% of CPU time
|
||||
[Executes: get_call_hierarchy --function ApplyPalette]
|
||||
Agent: It's called 1M times per frame - that's excessive
|
||||
Agent: I suggest caching the palette conversions...
|
||||
```
|
||||
|
||||
## Document History
|
||||
|
||||
- 2025-11-22: Initial specification (v1.0) - CLAUDE_AIINF
|
||||
121
docs/internal/plans/architecture_refactor_v1.md
Normal file
121
docs/internal/plans/architecture_refactor_v1.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# B7 - Architecture Refactoring Plan
|
||||
|
||||
**Date**: October 15, 2025
|
||||
**Status**: Proposed
|
||||
**Author**: Gemini AI Assistant
|
||||
|
||||
## 1. Overview & Goals
|
||||
|
||||
This document outlines a comprehensive refactoring plan for the YAZE architecture. The current structure has resulted in tight coupling between components, slow incremental build times, and architectural inconsistencies (e.g., shared libraries located within the `app/` directory).
|
||||
|
||||
The primary goals of this refactoring are:
|
||||
|
||||
1. **Establish a Clear, Layered Architecture**: Separate foundational libraries (`core`, `gfx`, `zelda3`) from the applications that consume them (`app`, `cli`).
|
||||
2. **Improve Modularity & Maintainability**: Decompose large, monolithic libraries into smaller, single-responsibility modules.
|
||||
3. **Drastically Reduce Build Times**: Minimize rebuild cascades by ensuring changes in one module do not trigger unnecessary rebuilds in unrelated components.
|
||||
4. **Enable Future Development**: Create a flexible foundation for new features like alternative rendering backends (SDL3, Metal, Vulkan) and a fully-featured CLI.
|
||||
|
||||
## 2. Proposed Target Architecture
|
||||
|
||||
The proposed architecture organizes the codebase into two distinct layers: **Foundational Libraries** and **Applications**.
|
||||
|
||||
```
|
||||
/src
|
||||
├── core/ (NEW) 📖 Project model, Asar wrapper, etc.
|
||||
├── gfx/ (MOVED) 🎨 Graphics engine, backends, resource management
|
||||
├── zelda3/ (MOVED) Game Game-specific data models and logic
|
||||
├── util/ (EXISTING) Low-level utilities (logging, file I/O)
|
||||
│
|
||||
├── app/ (REFACTORED) Main GUI Application
|
||||
│ ├── controller.cc (MOVED) Main application controller
|
||||
│ ├── platform/ (MOVED) Windowing, input, platform abstractions
|
||||
│ ├── service/ (MOVED) AI gRPC services for automation
|
||||
│ ├── editor/ (EXISTING) 🎨 Editor implementations
|
||||
│ └── gui/ (EXISTING) Shared ImGui widgets
|
||||
│
|
||||
└── cli/ (EXISTING) z3ed Command-Line Tool
|
||||
```
|
||||
|
||||
## 3. Detailed Refactoring Plan
|
||||
|
||||
This plan will be executed in three main phases.
|
||||
|
||||
### Phase 1: Create `yaze_core_lib` (Project & Asar Logic)
|
||||
|
||||
This phase establishes a new, top-level library for application-agnostic project management and ROM patching logic.
|
||||
|
||||
1. **Create New Directory**: Create `src/core/`.
|
||||
2. **Move Files**:
|
||||
* Move `src/app/core/{project.h, project.cc}` → `src/core/` (pending)
|
||||
* Move `src/app/core/{asar_wrapper.h, asar_wrapper.cc}` → `src/core/` (done)
|
||||
* Move `src/app/core/features.h` → `src/core/` (pending)
|
||||
3. **Update Namespace**: In the moved files, change the namespace from `yaze::core` to `yaze::project` for clarity.
|
||||
4. **Create CMake Target**: In a new `src/core/CMakeLists.txt`, define the `yaze_core_lib` static library containing the moved files. This library should have minimal dependencies (e.g., `yaze_util`, `absl`).
|
||||
|
||||
### Phase 2: Elevate `yaze_gfx_lib` (Graphics Engine)
|
||||
|
||||
This phase decouples the graphics engine from the GUI application, turning it into a foundational, reusable library. This is critical for supporting multiple rendering backends as outlined in `docs/G2-renderer-migration-plan.md`.
|
||||
|
||||
1. **Move Directory**: Move the entire `src/app/gfx/` directory to `src/gfx/`.
|
||||
2. **Create CMake Target**: In a new `src/gfx/CMakeLists.txt`, define the `yaze_gfx_lib` static library. This will aggregate all graphics components (`backend`, `core`, `resource`, etc.).
|
||||
3. **Update Dependencies**: The `yaze` application target will now explicitly depend on `yaze_gfx_lib`.
|
||||
|
||||
### Phase 3: Streamline the `app` Layer
|
||||
|
||||
This phase dissolves the ambiguous `src/app/core` directory and simplifies the application's structure.
|
||||
|
||||
1. **Move Service Layer**: Move the `src/app/core/service/` directory to `src/app/service/`. This creates a clear, top-level service layer for gRPC implementations.
|
||||
2. **Move Platform Code**: Move `src/app/core/{window.cc, window.h, timing.h}` into the existing `src/app/platform/` directory. This consolidates all platform-specific windowing and input code.
|
||||
3. **Elevate Main Controller**: Move `src/app/core/{controller.cc, controller.h}` to `src/app/`. This highlights its role as the primary orchestrator of the GUI application.
|
||||
4. **Update CMake**:
|
||||
* Eliminate the `yaze_app_core_lib` target.
|
||||
* Add the source files from the moved directories (`app/controller.cc`, `app/platform/window.cc`, `app/service/*.cc`, etc.) directly to the main `yaze` executable target.
|
||||
|
||||
## 4. Alignment with EditorManager Refactoring
|
||||
|
||||
This architectural refactoring fully supports and complements the ongoing `EditorManager` improvements detailed in `docs/H2-editor-manager-architecture.md`.
|
||||
|
||||
- The `EditorManager` and its new coordinators (`UICoordinator`, `PopupManager`, `SessionCoordinator`) are clearly components of the **Application Layer**.
|
||||
- By moving the foundational libraries (`core`, `gfx`) out of `src/app`, we create a clean boundary. The `EditorManager` and its helpers will reside within `src/app/editor/` and `src/app/editor/system/`, and will consume the new `yaze_core_lib` and `yaze_gfx_lib` as dependencies.
|
||||
- This separation makes the `EditorManager`'s role as a UI and session coordinator even clearer, as it no longer lives alongside low-level libraries.
|
||||
|
||||
## 5. Migration Checklist
|
||||
|
||||
1. [x] **Phase 1**: Create `src/core/` and move `project`, `asar_wrapper`, and `features` files.
|
||||
2. [x] **Phase 1**: Create the `yaze_core_lib` CMake target.
|
||||
3. [ ] **Phase 2**: Move `src/app/gfx/` to `src/gfx/`. (DEFERRED - app-specific)
|
||||
4. [ ] **Phase 2**: Create the `yaze_gfx_lib` CMake target. (DEFERRED - app-specific)
|
||||
5. [x] **Phase 3**: Move `src/app/core/service/` to `src/app/service/`.
|
||||
6. [x] **Phase 3**: Move `src/app/core/testing/` to `src/app/test/` (merged with existing test/).
|
||||
7. [x] **Phase 3**: Move `window.cc`, `timing.h` to `src/app/platform/`.
|
||||
8. [x] **Phase 3**: Move `controller.cc` to `src/app/`.
|
||||
9. [x] **Phase 3**: Update CMake targets - renamed `yaze_core_lib` to `yaze_app_core_lib` to distinguish from foundational `yaze_core_lib`.
|
||||
10. [x] **Phase 3**: `src/app/core/` now only contains `core_library.cmake` for app-level functionality.
|
||||
11. [x] **Cleanup**: All `#include "app/core/..."` directives updated to new paths.
|
||||
|
||||
## 6. Completed Changes (October 15, 2025)
|
||||
|
||||
### Phase 1: Foundational Core Library ✅
|
||||
- Created `src/core/` with `project.{h,cc}`, `features.h`, and `asar_wrapper.{h,cc}`
|
||||
- Changed namespace from `yaze::core` to `yaze::project` for project management types
|
||||
- Created new `yaze_core_lib` in `src/core/CMakeLists.txt` with minimal dependencies
|
||||
- Updated all 32+ files to use `#include "core/project.h"` and `#include "core/features.h"`
|
||||
|
||||
### Phase 3: Application Layer Streamlining ✅
|
||||
- Moved `src/app/core/service/` → `src/app/service/` (gRPC services)
|
||||
- Moved `src/app/core/testing/` → `src/app/test/` (merged with existing test infrastructure)
|
||||
- Moved `src/app/core/window.{cc,h}`, `timing.h` → `src/app/platform/`
|
||||
- Moved `src/app/core/controller.{cc,h}` → `src/app/`
|
||||
- Renamed old `yaze_core_lib` to `yaze_app_core_lib` to avoid naming conflict
|
||||
- Updated all CMake dependencies in editor, emulator, agent, and test libraries
|
||||
- Removed duplicate source files from `src/app/core/`
|
||||
|
||||
### Deferred (Phase 2)
|
||||
Graphics refactoring (`src/app/gfx/` → `src/gfx/`) deferred as it's app-specific and requires careful consideration of rendering backends.
|
||||
|
||||
## 6. Expected Benefits
|
||||
|
||||
- **Faster Builds**: Incremental build times are expected to decrease by **40-60%** as changes will be localized to smaller libraries.
|
||||
- **Improved Maintainability**: A clear, layered architecture makes the codebase easier to understand, navigate, and extend.
|
||||
- **True CLI Decoupling**: The `z3ed` CLI can link against `yaze_core_lib` and `yaze_zelda3_lib` without pulling in any GUI or rendering dependencies, resulting in a smaller, more portable executable.
|
||||
- **Future-Proofing**: The abstracted `gfx` library paves the way for supporting SDL3, Metal, or Vulkan backends with minimal disruption to the rest of the application.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +0,0 @@
|
||||
# Branch Organization Plan
|
||||
|
||||
The current workspace has a significant number of unstaged changes covering multiple distinct areas of work. To maintain a clean history and facilitate parallel development, these should be split into the following branches:
|
||||
|
||||
## 1. `feature/debugger-disassembler`
|
||||
**Purpose**: Implementation of the new debugging and disassembly tools.
|
||||
**Files**:
|
||||
- `src/app/emu/debug/disassembler.cc` / `.h`
|
||||
- `src/app/emu/debug/step_controller.cc` / `.h`
|
||||
- `src/app/emu/debug/symbol_provider.cc` / `.h`
|
||||
- `src/cli/service/agent/disassembler_65816.cc` / `.h`
|
||||
- `src/cli/service/agent/rom_debug_agent.cc` / `.h`
|
||||
- `src/cli/service/agent/memory_debugging_example.cc`
|
||||
- `test/unit/emu/disassembler_test.cc`
|
||||
- `test/unit/emu/step_controller_test.cc`
|
||||
- `test/unit/cli/rom_debug_agent_test.cc`
|
||||
- `test/integration/memory_debugging_test.cc`
|
||||
|
||||
## 2. `infra/ci-test-overhaul`
|
||||
**Purpose**: Updates to CI workflows, test configuration, and agent documentation.
|
||||
**Files**:
|
||||
- `.github/actions/run-tests/action.yml`
|
||||
- `.github/workflows/ci.yml`
|
||||
- `.github/workflows/release.yml`
|
||||
- `.github/workflows/nightly.yml`
|
||||
- `AGENTS.md`
|
||||
- `CLAUDE.md`
|
||||
- `docs/internal/agents/*`
|
||||
- `cmake/options.cmake`
|
||||
- `cmake/packaging/cpack.cmake`
|
||||
- `src/app/test/test.cmake`
|
||||
- `test/test.cmake`
|
||||
- `test/README.md`
|
||||
|
||||
## 3. `test/e2e-dungeon-coverage`
|
||||
**Purpose**: Extensive additions to E2E and integration tests for the Dungeon Editor.
|
||||
**Files**:
|
||||
- `test/e2e/dungeon_*`
|
||||
- `test/integration/zelda3/dungeon_*`
|
||||
- `test/unit/zelda3/dungeon/object_rendering_test.cc`
|
||||
|
||||
## 4. `feature/agent-ui-improvements`
|
||||
**Purpose**: Enhancements to the Agent Chat Widget and Proposal Drawer.
|
||||
**Files**:
|
||||
- `src/app/editor/agent/agent_chat_widget.cc`
|
||||
- `src/app/editor/system/proposal_drawer.cc`
|
||||
- `src/cli/service/agent/tool_dispatcher.cc` / `.h`
|
||||
- `src/cli/service/ai/prompt_builder.cc`
|
||||
|
||||
## 5. `fix/overworld-logic`
|
||||
**Purpose**: Fixes or modifications to Overworld logic (possibly related to the other agent's work).
|
||||
**Files**:
|
||||
- `src/zelda3/overworld/overworld.cc`
|
||||
- `src/zelda3/overworld/overworld.h`
|
||||
- `test/e2e/overworld/overworld_e2e_test.cc`
|
||||
- `test/integration/zelda3/overworld_integration_test.cc`
|
||||
|
||||
## 6. `chore/misc-cleanup`
|
||||
**Purpose**: Miscellaneous cleanups and minor fixes.
|
||||
**Files**:
|
||||
- `src/CMakeLists.txt`
|
||||
- `src/app/editor/editor_library.cmake`
|
||||
- `test/yaze_test.cc`
|
||||
- `test/test_utils.cc`
|
||||
- `test/test_editor.cc`
|
||||
|
||||
## Action Items
|
||||
1. Review this list with the user (if they were here, but I will assume this is the plan).
|
||||
2. For the current task (UI/UX), I should likely branch off `master` (or the current state if dependencies exist) but be careful not to include unrelated changes in my commits if I were to commit.
|
||||
3. Since I am in an agentic mode, I will proceed by assuming these changes are "work in progress" and I should try to touch only what is necessary for UI/UX, or if I need to clean up, I should be aware of these boundaries.
|
||||
@@ -1,112 +0,0 @@
|
||||
# Branch Recovery Plan
|
||||
|
||||
**Date**: 2024-11-22
|
||||
**Status**: COMPLETED - All changes organized
|
||||
**Context**: Gemini 3 was interrupted, Claude 4.5 and GPT-OSS 120 attempted to help. Claude (Sonnet 4.5) completed reorganization.
|
||||
|
||||
## Final State Summary
|
||||
|
||||
All ~112 files have been organized into logical branches. Each branch has a clean, focused commit.
|
||||
|
||||
### Branch Status
|
||||
|
||||
| Branch | Commit | Files | Description |
|
||||
|--------|--------|-------|-------------|
|
||||
| `feature/agent-ui-improvements` | `29931139f5` | 19 files | Agent UI, tool dispatcher, dev assist tools |
|
||||
| `infra/ci-test-overhaul` | `aa411a5d1b` | 23 files | CI/CD workflows, test infrastructure, docs |
|
||||
| `test/e2e-dungeon-coverage` | `28147624a3` | 18 files | Dungeon E2E and integration tests |
|
||||
| `chore/misc-cleanup` | `a01a630c7f` | 39 files | Misc cleanup, docs, unit tests, style |
|
||||
| `fix/overworld-logic` | `00fef1169d` | 2 files | Overworld test fixes |
|
||||
| `backup/all-uncommitted-work-2024-11-22` | `5e32a8983f` | 112 files | Full backup (safety net) |
|
||||
|
||||
### What's in Each Branch
|
||||
|
||||
**`feature/agent-ui-improvements`** (Ready for review)
|
||||
- `src/app/editor/agent/agent_chat_widget.cc`
|
||||
- `src/app/editor/agent/agent_editor.cc`
|
||||
- `src/app/editor/system/proposal_drawer.cc`
|
||||
- `src/cli/service/agent/tool_dispatcher.cc/.h`
|
||||
- `src/cli/service/agent/dev_assist_agent.cc/.h`
|
||||
- `src/cli/service/agent/tools/*` (new tool modules)
|
||||
- `src/cli/service/agent/emulator_service_impl.cc/.h`
|
||||
- `src/cli/service/ai/prompt_builder.cc`
|
||||
- `src/cli/tui/command_palette.cc`
|
||||
- `test/integration/agent/tool_dispatcher_test.cc`
|
||||
|
||||
**`infra/ci-test-overhaul`** (Ready for review)
|
||||
- `.github/workflows/ci.yml`, `release.yml`, `nightly.yml`
|
||||
- `.github/actions/run-tests/action.yml`
|
||||
- `cmake/options.cmake`, `cmake/packaging/cpack.cmake`
|
||||
- `AGENTS.md`, `CLAUDE.md`
|
||||
- `docs/internal/agents/*` (coordination docs)
|
||||
- `docs/internal/ci-and-testing.md`
|
||||
- `docs/internal/CI-TEST-STRATEGY.md`
|
||||
- `test/test.cmake`, `test/README.md`
|
||||
|
||||
**`test/e2e-dungeon-coverage`** (Ready for review)
|
||||
- `test/e2e/dungeon_canvas_interaction_test.cc/.h`
|
||||
- `test/e2e/dungeon_e2e_tests.cc/.h`
|
||||
- `test/e2e/dungeon_layer_rendering_test.cc/.h`
|
||||
- `test/e2e/dungeon_object_drawing_test.cc/.h`
|
||||
- `test/e2e/dungeon_visual_verification_test.cc/.h`
|
||||
- `test/integration/zelda3/dungeon_*`
|
||||
- `test/unit/zelda3/dungeon/object_rendering_test.cc`
|
||||
- `docs/internal/testing/dungeon-gui-test-design.md`
|
||||
|
||||
**`chore/misc-cleanup`** (Ready for review)
|
||||
- `src/CMakeLists.txt`, `src/app/editor/editor_library.cmake`
|
||||
- `src/app/controller.cc`, `src/app/main.cc`
|
||||
- `src/app/service/canvas_automation_service.cc`
|
||||
- `src/app/gui/style/theme.h`
|
||||
- `docs/internal/architecture/*`
|
||||
- `docs/internal/plans/*` (including this file)
|
||||
- `test/yaze_test.cc`, `test/test_utils.cc`, `test/test_editor.cc`
|
||||
- Various unit tests updates
|
||||
|
||||
**`fix/overworld-logic`** (Ready for review)
|
||||
- `test/integration/zelda3/overworld_integration_test.cc`
|
||||
- `test/unit/zelda3/overworld_test.cc`
|
||||
|
||||
## Items NOT Committed (Still Untracked)
|
||||
|
||||
These items remain untracked and need manual attention:
|
||||
- `.tmp/` - Contains ZScreamDungeon submodule (should be in .gitignore?)
|
||||
- `third_party/bloaty` - Another git repo (should be submodule?)
|
||||
- `CIRCULAR_DEPENDENCY_*.md` - Temporary analysis artifacts (delete?)
|
||||
- `FIX_CIRCULAR_DEPS.patch` - Temporary patch (delete?)
|
||||
- `debug_crash.lldb` - Debug file (delete)
|
||||
- `fix_dungeon_colors.py` - One-off script (delete?)
|
||||
- `test_grpc_server.sh` - Test script (keep or delete?)
|
||||
|
||||
## Recommended Merge Order
|
||||
|
||||
1. **First**: `infra/ci-test-overhaul` - Updates CI and test infrastructure
|
||||
2. **Second**: `test/e2e-dungeon-coverage` - Adds new tests
|
||||
3. **Third**: `feature/agent-ui-improvements` - Agent improvements
|
||||
4. **Fourth**: `fix/overworld-logic` - Small test fix
|
||||
5. **Last**: `chore/misc-cleanup` - Docs and cleanup (may need rebasing)
|
||||
|
||||
## Notes for Gemini 3
|
||||
|
||||
- All branches are based on `master` at commit `0d18c521a1`
|
||||
- The `feature/debugger-disassembler` branch still has its original commit - preserved
|
||||
- Stashes are still available if needed (`git stash list`)
|
||||
- The `backup/all-uncommitted-work-2024-11-22` branch has EVERYTHING as a safety net
|
||||
- Consider creating PRs for review before merging
|
||||
|
||||
## Quick Commands
|
||||
|
||||
```bash
|
||||
# See all organized branches
|
||||
git branch -a | grep -E '(feature|infra|test|chore|fix|backup)/'
|
||||
|
||||
# View commits on a branch
|
||||
git log --oneline master..branch-name
|
||||
|
||||
# Merge a branch (after review)
|
||||
git checkout master
|
||||
git merge --no-ff branch-name
|
||||
|
||||
# Delete backup after all merges confirmed
|
||||
git branch -D backup/all-uncommitted-work-2024-11-22
|
||||
```
|
||||
123
docs/internal/plans/comprehensive-test-and-cli-plan.md
Normal file
123
docs/internal/plans/comprehensive-test-and-cli-plan.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Comprehensive Plan: E2E Testing & z3ed CLI Improvements
|
||||
|
||||
This document outlines the design for ROM-dependent End-to-End (E2E) tests for `yaze` editors and improvements to the `z3ed` CLI tool.
|
||||
|
||||
## 1. E2E Testing Design
|
||||
|
||||
The goal is to ensure stability and correctness of major editors by simulating user actions and verifying the state of the ROM and application.
|
||||
|
||||
### 1.1. Test Infrastructure
|
||||
|
||||
We will extend the existing `RomDependentTestSuite` in `src/app/test/rom_dependent_test_suite.h` or create a new `EditorE2ETestSuite`.
|
||||
|
||||
**Key Components:**
|
||||
- **Test Fixture:** A setup that loads a clean ROM (or a specific test ROM) before each test.
|
||||
- **Action Simulator:** Helper functions to simulate editor actions (e.g., `SelectTile`, `PlaceObject`, `Save`).
|
||||
- **State Verifier:** Helper functions to verify the ROM state matches expectations after actions.
|
||||
|
||||
### 1.2. Overworld Editor Tests
|
||||
|
||||
**Scope:**
|
||||
- **Draw Tile 16:** Select a tile from the blockset and place it on the map. Verify the map data reflects the change.
|
||||
- **Edit Tile 16:** Modify a Tile16 definition (e.g., change sub-tiles, flip, priority). Verify the Tile16 data is updated.
|
||||
- **Multi-select & Draw:** Select a range of tiles and draw them. Verify all tiles are placed correctly.
|
||||
- **Manipulate Entities:** Add, move, and delete sprites/exits/items. Verify their coordinates and properties.
|
||||
- **Change Properties:** Modify map properties (e.g., palette, music, message ID).
|
||||
- **Expanded Features:** Test features specific to ZSCustomOverworld (if applicable).
|
||||
|
||||
**Implementation Strategy:**
|
||||
- Use `OverworldEditor` class directly or via a wrapper to invoke methods like `SetTile`, `UpdateEntity`.
|
||||
- Verify by inspecting `OverworldMap` data and `GameData`.
|
||||
|
||||
### 1.3. Dungeon Editor Tests
|
||||
|
||||
**Scope:**
|
||||
- **Object Manipulation:** Add, delete, move, and resize objects.
|
||||
- **Door Manipulation:** Change door types, toggle open/closed states.
|
||||
- **Items & Sprites:** Add/remove items (chests, pots) and sprites. Verify properties.
|
||||
- **Room Properties:** Change header settings (music, palette, floor).
|
||||
|
||||
**Implementation Strategy:**
|
||||
- Use `DungeonEditor` and `Room` classes.
|
||||
- Simulate mouse/keyboard inputs if possible, or call logical methods directly.
|
||||
- Verify by reloading the room and checking object lists.
|
||||
|
||||
### 1.4. Graphics & Palette Editor Tests
|
||||
|
||||
**Scope:**
|
||||
- **Graphics:** Edit pixel data in a sprite sheet. Save and reload. Verify pixels are preserved and no corruption occurs.
|
||||
- **Palette:** Change color values. Save and reload. Verify colors are preserved.
|
||||
|
||||
**Implementation Strategy:**
|
||||
- Modify `Bitmap` data directly or via editor methods.
|
||||
- Trigger `SaveGraphics` / `SavePalettes`.
|
||||
- Reload and compare byte-for-byte.
|
||||
|
||||
### 1.5. Message Editor Tests
|
||||
|
||||
**Scope:**
|
||||
- **Text Editing:** Modify dialogue text.
|
||||
- **Command Insertion:** Insert control codes (e.g., wait, speed change).
|
||||
- **Save/Reload:** Verify text and commands are preserved.
|
||||
|
||||
**Implementation Strategy:**
|
||||
- Use `MessageEditor` backend.
|
||||
- Verify encoded text data in ROM.
|
||||
|
||||
## 2. z3ed CLI Improvements
|
||||
|
||||
The `z3ed` CLI is a vital tool for ROM hacking workflows. We will improve its "doctor" and "comparison" capabilities and general UX.
|
||||
|
||||
### 2.1. Doctor Command Improvements (`z3ed doctor`)
|
||||
|
||||
**Goal:** Provide deeper insights into ROM health and potential issues.
|
||||
|
||||
**New Features:**
|
||||
- **Deep Scan:** Analyze all rooms, not just a sample (already exists via `--all`, but make it default or more prominent).
|
||||
- **Corruption Heuristics:** Check for common corruption patterns (e.g., invalid pointers, overlapping data).
|
||||
- **Expanded Feature Validation:** Verify integrity of expanded tables (Tile16, Tile32, Monologue).
|
||||
- **Fix Suggestions:** Where possible, offer specific commands or actions to fix issues (e.g., "Run `z3ed fix-checksum`").
|
||||
- **JSON Output:** Ensure comprehensive JSON output for CI/CD integration.
|
||||
|
||||
### 2.2. Comparison Command Improvements (`z3ed compare`)
|
||||
|
||||
**Goal:** Make it easier to track changes and spot unintended regressions.
|
||||
|
||||
**New Features:**
|
||||
- **Smart Diff:** Ignore insignificant changes (e.g., checksum, timestamp) if requested.
|
||||
- **Visual Diff (Text):** Improved hex dump visualization of differences (side-by-side).
|
||||
- **Region Filtering:** Allow comparing only specific regions (e.g., "Overworld", "Dungeon", "Code").
|
||||
- **Summary Mode:** Show high-level summary of changed areas (e.g., "3 Rooms modified, 1 Overworld map modified").
|
||||
|
||||
### 2.3. UX Improvements
|
||||
|
||||
- **Progress Bars:** Add progress indicators for long-running operations (like full ROM scan).
|
||||
- **Interactive Mode:** For `doctor`, allow interactive fixing of simple issues.
|
||||
- **Better Help:** Improve help messages and examples.
|
||||
- **Colorized Output:** Enhance readability with color-coded status (Green=OK, Yellow=Warning, Red=Error).
|
||||
|
||||
## 3. Implementation Roadmap
|
||||
|
||||
1. **Phase 1: Foundation & CLI**
|
||||
- Refactor `z3ed` commands for better extensibility.
|
||||
- Implement improved `doctor` and `compare` logic.
|
||||
- Add UX enhancements (colors, progress).
|
||||
|
||||
2. **Phase 2: Editor Test Framework**
|
||||
- Create `EditorTestBase` class.
|
||||
- Implement helpers for ROM loading/resetting.
|
||||
|
||||
3. **Phase 3: Specific Editor Tests**
|
||||
- Implement Overworld tests.
|
||||
- Implement Dungeon tests.
|
||||
- Implement Graphics/Palette/Message tests.
|
||||
|
||||
4. **Phase 4: Documentation & Integration**
|
||||
- Update docs with usage guides.
|
||||
- Integrate into CI pipeline.
|
||||
|
||||
## 4. Verification Plan
|
||||
|
||||
- **Unit Tests:** Verify individual command logic.
|
||||
- **Integration Tests:** Run `z3ed` against known good and bad ROMs.
|
||||
- **Manual Verification:** Use the improved CLI tools on real projects to verify utility.
|
||||
143
docs/internal/plans/dockbuilder-default-layouts.md
Normal file
143
docs/internal/plans/dockbuilder-default-layouts.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Default DockBuilder Layouts Plan
|
||||
Status: ACTIVE
|
||||
Owner: imgui-frontend-engineer
|
||||
Created: 2025-12-07
|
||||
Last Reviewed: 2025-12-07
|
||||
Next Review: 2025-12-14
|
||||
Board Link: [Coordination Board – 2025-12-05 imgui-frontend-engineer – Panel launch/log filtering UX](../agents/coordination-board.md)
|
||||
|
||||
## Summary
|
||||
- Deliver deterministic default dock layouts per editor using ImGui DockBuilder, aligned with `PanelManager` visibility rules and `LayoutPresets`.
|
||||
- Ensure session-aware window titles, validation hooks, and user-facing reset/apply commands.
|
||||
- Provide a reusable dock-tree builder that only creates the splits needed by each preset, with sensible ratios.
|
||||
|
||||
## Goals
|
||||
- Build DockBuilder layouts directly from `PanelLayoutPreset::panel_positions`, honoring default/optional visibility from `LayoutPresets`.
|
||||
- Keep `PanelManager` as the single source of truth for visibility (pinned/persistent honored on editor switch).
|
||||
- Make layouts robust across sessions via prefixed IDs and stable window titles.
|
||||
- Add validation/logging so missing/mismatched window titles are surfaced immediately.
|
||||
|
||||
## Non-Goals
|
||||
- Full layout serialization/import (use existing ImGui ini paths later).
|
||||
- Redesign of ActivityBar or RightPanelManager.
|
||||
- New panel registrations; focus is layout orchestration of existing panels.
|
||||
|
||||
## Constraints & Context
|
||||
- Docking API is internal (`imgui_internal.h`) and brittle; prefer minimal splits and clear ordering.
|
||||
- `PanelDescriptor::GetWindowTitle()` must match the actual `ImGui::Begin` title. Gaps cause DockBuilder docking failures.
|
||||
- Session prefixing is required when multiple sessions exist (`PanelManager::MakePanelId`).
|
||||
|
||||
## Work Plan
|
||||
1) **Title hygiene & validation**
|
||||
- Require every `PanelDescriptor` to supply `window_title` (or safe icon+name fallback).
|
||||
- Extend `PanelManager::ValidatePanels()` to assert titles resolve and optionally check `ImGui::FindWindowByName` post-dock.
|
||||
2) **Reusable dock-tree builder**
|
||||
- Build only the splits needed by the positions present (Left/Right/Top/Bottom and quadrants), with per-editor ratios in `LayoutPresets`.
|
||||
- Keep center as the default drop zone when a split is absent.
|
||||
3) **Session-aware docking**
|
||||
- When docking, resolve both the prefixed panel ID and its title via `PanelManager::MakePanelId`/`GetPanelDescriptor`.
|
||||
- Guard rebuilds with `DockBuilderGetNode` and re-add nodes when missing.
|
||||
4) **Preset application pipeline**
|
||||
- In `LayoutManager::InitializeEditorLayout`/`RebuildLayout`, call the dock-tree builder, then show default panels from `LayoutPresets`, then `DockBuilderFinish`.
|
||||
- `LayoutOrchestrator` triggers this on first switch and on “Reset Layout.”
|
||||
5) **Named presets & commands**
|
||||
- Add helpers to apply named presets (Minimal/Developer/Designer/etc.) that: show defaults, hide optionals, rebuild the dock tree, and optionally load/save ImGui ini blobs.
|
||||
- Expose commands/buttons in sidebar/menu (Reset to Default, Apply <Preset>).
|
||||
6) **Post-apply validation**
|
||||
- After docking, run the validation pass; log missing titles/panels and surface a toast for user awareness.
|
||||
- Capture failures to telemetry/logs for later fixes.
|
||||
7) **Docs/tests**
|
||||
- Document the builder contract and add a small unit/integration check that `GetWindowTitle` is non-empty for all preset IDs.
|
||||
|
||||
## Code Sketches
|
||||
|
||||
### Dock tree builder with minimal splits
|
||||
```cpp
|
||||
#include "imgui/imgui_internal.h"
|
||||
|
||||
struct BuiltDockTree {
|
||||
ImGuiID center{}, left{}, right{}, top{}, bottom{};
|
||||
ImGuiID left_top{}, left_bottom{}, right_top{}, right_bottom{};
|
||||
};
|
||||
|
||||
static BuiltDockTree BuildDockTree(ImGuiID dockspace_id) {
|
||||
BuiltDockTree ids{};
|
||||
ids.center = dockspace_id;
|
||||
|
||||
// Primary splits
|
||||
ids.left = ImGui::DockBuilderSplitNode(ids.center, ImGuiDir_Left, 0.22f, nullptr, &ids.center);
|
||||
ids.right = ImGui::DockBuilderSplitNode(ids.center, ImGuiDir_Right, 0.25f, nullptr, &ids.center);
|
||||
ids.bottom = ImGui::DockBuilderSplitNode(ids.center, ImGuiDir_Down, 0.25f, nullptr, &ids.center);
|
||||
ids.top = ImGui::DockBuilderSplitNode(ids.center, ImGuiDir_Up, 0.18f, nullptr, &ids.center);
|
||||
|
||||
// Secondary splits (created only if the parent exists)
|
||||
if (ids.left) {
|
||||
ids.left_bottom = ImGui::DockBuilderSplitNode(ids.left, ImGuiDir_Down, 0.50f, nullptr, &ids.left_top);
|
||||
}
|
||||
if (ids.right) {
|
||||
ids.right_bottom = ImGui::DockBuilderSplitNode(ids.right, ImGuiDir_Down, 0.50f, nullptr, &ids.right_top);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
```
|
||||
|
||||
### Dock preset application with title resolution
|
||||
```cpp
|
||||
void ApplyPresetLayout(const PanelLayoutPreset& preset,
|
||||
PanelManager& panels,
|
||||
ImGuiID dockspace_id,
|
||||
size_t session_id = 0) {
|
||||
if (ImGui::DockBuilderGetNode(dockspace_id) == nullptr) {
|
||||
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetMainViewport()->WorkSize);
|
||||
}
|
||||
|
||||
ImGui::DockBuilderRemoveNodeChildNodes(dockspace_id);
|
||||
auto tree = BuildDockTree(dockspace_id);
|
||||
|
||||
auto dock_for = [&](DockPosition pos) -> ImGuiID {
|
||||
switch (pos) {
|
||||
case DockPosition::Left: return tree.left ? tree.left : tree.center;
|
||||
case DockPosition::Right: return tree.right ? tree.right : tree.center;
|
||||
case DockPosition::Top: return tree.top ? tree.top : tree.center;
|
||||
case DockPosition::Bottom: return tree.bottom ? tree.bottom : tree.center;
|
||||
case DockPosition::LeftTop: return tree.left_top ? tree.left_top : (tree.left ? tree.left : tree.center);
|
||||
case DockPosition::LeftBottom: return tree.left_bottom ? tree.left_bottom : (tree.left ? tree.left : tree.center);
|
||||
case DockPosition::RightTop: return tree.right_top ? tree.right_top : (tree.right ? tree.right : tree.center);
|
||||
case DockPosition::RightBottom: return tree.right_bottom ? tree.right_bottom : (tree.right ? tree.right : tree.center);
|
||||
case DockPosition::Center:
|
||||
default: return tree.center;
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& [panel_id, pos] : preset.panel_positions) {
|
||||
const auto* desc = panels.GetPanelDescriptor(session_id, panel_id);
|
||||
if (!desc) continue; // unknown or unregistered panel
|
||||
|
||||
const std::string window_title = desc->GetWindowTitle();
|
||||
if (window_title.empty()) continue; // validation will flag this
|
||||
|
||||
ImGui::DockBuilderDockWindow(window_title.c_str(), dock_for(pos));
|
||||
}
|
||||
|
||||
ImGui::DockBuilderFinish(dockspace_id);
|
||||
}
|
||||
```
|
||||
|
||||
### Integration points
|
||||
- `LayoutManager::InitializeEditorLayout`
|
||||
```cpp
|
||||
ImGui::DockBuilderRemoveNode(dockspace_id);
|
||||
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetMainViewport()->WorkSize);
|
||||
ApplyPresetLayout(LayoutPresets::GetDefaultPreset(type), *panel_manager_, dockspace_id, active_session_);
|
||||
ShowDefaultPanelsForEditor(panel_manager_, type); // existing helper
|
||||
ImGui::DockBuilderFinish(dockspace_id);
|
||||
```
|
||||
- `LayoutOrchestrator::ResetToDefault` calls `LayoutManager::RebuildLayout` with the current dockspace ID.
|
||||
|
||||
## Exit Criteria
|
||||
- DockBuilder helper applied for all editor presets with sensible split ratios.
|
||||
- Validation logs (and optional toast) for any missing window titles or docking failures.
|
||||
- User-visible controls to reset/apply presets; defaults restored correctly after reset.
|
||||
- Session-aware docking verified (no cross-session clashes when multiple sessions open).
|
||||
25
docs/internal/plans/dungeon-geometry-sidecar.md
Normal file
25
docs/internal/plans/dungeon-geometry-sidecar.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Dungeon Geometry Sidecar Plan
|
||||
Status: Draft | Owner: zelda3-hacking-expert | Created: 2025-12-08 | Next Review: 2025-12-15
|
||||
|
||||
## Goal
|
||||
Establish a reusable geometry engine that derives object bounds directly from draw routines so selection/hitboxes/BG2 masks stay in lockstep with rendering.
|
||||
|
||||
## Current State
|
||||
- Sidecar module added: `src/zelda3/dungeon/geometry/object_geometry.{h,cc}`.
|
||||
- Uses draw routine registry to replay routines against a dummy buffer and reports extents in tiles/pixels.
|
||||
- Anchor handling for upward diagonals; size=0 → 32 semantics preserved.
|
||||
- Tests added: `test/unit/zelda3/dungeon/object_geometry_test.cc` (size=0 rightwards/downwards, diagonal acute upward growth).
|
||||
|
||||
## Next Steps (Implementation)
|
||||
1) Expand routine coverage: add metadata/anchors for corner/special routines that move upward/left; add tests for corner routines (e.g., corner BothBG) and Somaria lines (size+1 growth).
|
||||
2) Add helper API on `ObjectGeometry` to return selection bounds + BG2 mask rectangle from measured extents (tile and pixel).
|
||||
3) Create parity tests against `ObjectDimensionTable::GetDimensions` for a sample set; document intentional deltas (selection vs render).
|
||||
4) Add CI guard: lightweight geometry test preset (unit) to catch routine table changes.
|
||||
5) Integration path (not committed yet):
|
||||
- Swap `ObjectDrawer::CalculateObjectDimensions` to call geometry sidecar.
|
||||
- Editor selection (`object_selection`, `dungeon_object_interaction`, `dungeon_canvas_viewer`) to consume geometry API.
|
||||
- Remove duplicated size tables in `object_dimensions` after parity confirmed.
|
||||
|
||||
## References
|
||||
- Disassembly: `~/Code/usdasm/bank_01.asm` (routine table at $018200).
|
||||
- Routine metadata source: `draw_routines/*` registry entries.
|
||||
461
docs/internal/plans/dungeon-layer-compositing-research.md
Normal file
461
docs/internal/plans/dungeon-layer-compositing-research.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# Dungeon Layer Compositing Research & Fix Plan
|
||||
|
||||
**Status:** PHASE 1 COMPLETE
|
||||
**Owner:** Requires multi-phase approach
|
||||
**Created:** 2025-12-07
|
||||
**Updated:** 2025-12-07
|
||||
**Problem:** BG2 content not visible through BG1 in dungeon editor
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The current dungeon rendering has fundamental issues where BG2 content (Layer 1 objects like platforms, statues, overlays) is hidden under BG1 floor tiles. Multiple quick-fix attempts have failed because the underlying architecture doesn't match SNES behavior.
|
||||
|
||||
## Part 1: SNES Dungeon Rendering Architecture
|
||||
|
||||
### 1.1 Tilemap RAM Buffers
|
||||
|
||||
From `bank_01.asm` (lines 930-962):
|
||||
```asm
|
||||
RoomData_TilemapPointers:
|
||||
.upper_layer ; BG1 tilemap at $7E2000
|
||||
dl $7E2000+$000
|
||||
dl $7E2000+$002
|
||||
...
|
||||
.lower_layer ; BG2 tilemap at $7E4000
|
||||
dl $7E4000+$000
|
||||
dl $7E4000+$002
|
||||
...
|
||||
```
|
||||
|
||||
**Key insight:** SNES has exactly TWO tilemap buffers:
|
||||
- `$7E2000` = BG1 (upper/foreground layer)
|
||||
- `$7E4000` = BG2 (lower/background layer)
|
||||
|
||||
All drawing operations (floor, layout, objects) write TILE IDs to these buffers.
|
||||
The PPU then renders these tilemaps to screen.
|
||||
|
||||
### 1.2 Room Build Order (`LoadAndBuildRoom` at $01873A)
|
||||
|
||||
From `bank_01.asm` (lines 965-1157):
|
||||
|
||||
```
|
||||
1. LoadRoomHeader
|
||||
2. STZ $BA (reset stream index)
|
||||
3. RoomDraw_DrawFloors <- Fills BOTH tilemaps with floor tiles
|
||||
4. Layout objects <- Overwrites tilemap entries
|
||||
5. Main room objects <- Overwrites tilemap entries
|
||||
6. INC $BA twice <- Skip 0xFFFF sentinel
|
||||
7. Load lower_layer pointers to $C0
|
||||
8. RoomDraw_DrawAllObjects <- BG2 overlay (writes to $7E4000)
|
||||
9. INC $BA twice <- Skip 0xFFFF sentinel
|
||||
10. Load upper_layer pointers to $C0
|
||||
11. RoomDraw_DrawAllObjects <- BG1 overlay (writes to $7E2000)
|
||||
12. Pushable blocks and torches
|
||||
```
|
||||
|
||||
**Critical finding:** Objects OVERWRITE tilemap entries, they don't draw pixels.
|
||||
Later objects can replace earlier tiles, including setting entries to 0 (transparent).
|
||||
|
||||
### 1.3 Floor Drawing (`RoomDraw_DrawFloors` at $0189DC)
|
||||
|
||||
From `bank_01.asm` (lines 1458-1548):
|
||||
|
||||
```asm
|
||||
RoomDraw_DrawFloors:
|
||||
; First pass: Load lower_layer pointers (BG2)
|
||||
; Draw floor tiles to BG2 tilemap ($7E4000)
|
||||
JSR RoomDraw_FloorChunks
|
||||
|
||||
; Second pass: Load upper_layer pointers (BG1)
|
||||
; Draw floor tiles to BG1 tilemap ($7E2000)
|
||||
JMP RoomDraw_FloorChunks
|
||||
```
|
||||
|
||||
The floor drawing:
|
||||
1. Uses floor graphics from room data (high nibble = BG2, low nibble = BG1)
|
||||
2. Fills the ENTIRE tilemap with floor tile patterns
|
||||
3. Uses `RoomDraw_FloorChunks` to stamp 4x4 "super squares"
|
||||
|
||||
### 1.4 SNES PPU Layer Rendering
|
||||
|
||||
SNES Mode 1 layer priority (from `registers.asm`):
|
||||
- TM ($212C): Main screen layer enable
|
||||
- TS ($212D): Sub screen layer enable
|
||||
- CGWSEL ($2130): Color math control
|
||||
- CGADSUB ($2131): Color addition/subtraction select
|
||||
|
||||
Default priority order: BG1 > BG2 > BG3 (BG1 is always on top)
|
||||
|
||||
**BUT:** Each tile has a priority bit. High-priority BG2 tiles can appear
|
||||
above low-priority BG1 tiles. The PPU sorts per-scanline based on:
|
||||
1. Layer (BG1/BG2)
|
||||
2. Tile priority bit
|
||||
3. BG priority setting in BGMODE
|
||||
|
||||
Transparency: Tile color 0 is ALWAYS transparent in SNES graphics.
|
||||
If a BG1 tile pixel is color 0, BG2 shows through at that pixel.
|
||||
|
||||
### 1.5 Layer Merge Types
|
||||
|
||||
From `room.h` (lines 100-112):
|
||||
```cpp
|
||||
LayerMerge00{0x00, "Off", true, false, false}; // BG2 visible, normal
|
||||
LayerMerge01{0x01, "Parallax", true, false, false}; // BG2 visible, parallax scroll
|
||||
LayerMerge02{0x02, "Dark", true, true, true}; // Dark room effect
|
||||
LayerMerge03{0x03, "On top", false, true, false}; // BG2 hidden?
|
||||
LayerMerge04{0x04, "Translucent", true, true, true}; // Color math blend
|
||||
LayerMerge05{0x05, "Addition", true, true, true}; // Additive blend
|
||||
LayerMerge06{0x06, "Normal", true, false, false}; // Standard
|
||||
LayerMerge07{0x07, "Transparent", true, true, true}; // Transparency
|
||||
LayerMerge08{0x08, "Dark room", true, true, true}; // Unlit room
|
||||
```
|
||||
|
||||
These control PPU register settings (TM/TS/CGWSEL/CGADSUB), NOT draw order.
|
||||
|
||||
## Part 2: Current Editor Architecture
|
||||
|
||||
### 2.1 Four-Buffer Design
|
||||
|
||||
```cpp
|
||||
bg1_buffer_ // Floor + Layout for BG1
|
||||
bg2_buffer_ // Floor + Layout for BG2
|
||||
object_bg1_buffer_ // Room objects for BG1
|
||||
object_bg2_buffer_ // Room objects for BG2
|
||||
```
|
||||
|
||||
### 2.2 Current Rendering Flow
|
||||
|
||||
```
|
||||
1. DrawFloor() fills tile buffer with floor patterns
|
||||
2. DrawBackground() renders tile buffer to BITMAP pixels
|
||||
3. LoadLayoutTilesToBuffer() draws layout objects to BITMAP
|
||||
4. RenderObjectsToBackground() draws room objects to OBJECT BITMAP
|
||||
5. CompositeToOutput() layers: BG2_Layout → BG2_Objects → BG1_Layout → BG1_Objects
|
||||
```
|
||||
|
||||
### 2.3 The Fundamental Problem
|
||||
|
||||
**SNES:** Objects write to TILEMAP BUFFER → PPU renders tilemaps with transparency
|
||||
**Editor:** Objects write to BITMAP → Compositing layers opaque pixels
|
||||
|
||||
In SNES: An object can SET a tilemap entry to tile 0 (transparent), creating a "hole"
|
||||
In Editor: Floor renders to bitmap first, objects can only draw ON TOP
|
||||
|
||||
**Result:** BG1 floor pixels are solid, completely covering BG2 content beneath.
|
||||
|
||||
## Part 3: Specific Issues to Fix
|
||||
|
||||
### Issue 1: BG1 Floor Covers BG2 Content
|
||||
- **Symptom:** Center platform/statues in room 001 invisible with BG1 ON
|
||||
- **Cause:** BG1 floor bitmap has solid pixels everywhere
|
||||
- **SNES behavior:** BG1 tilemap would have transparent tiles in overlay areas
|
||||
|
||||
### Issue 2: Object Drawing Order
|
||||
- **Symptom:** Layout objects may appear wrong relative to room objects
|
||||
- **Cause:** Current code doesn't match SNES four-pass rendering
|
||||
- **SNES behavior:** Strict order - layout → main → BG2 overlay → BG1 overlay
|
||||
|
||||
### Issue 3: Both-BG Routines
|
||||
- **Symptom:** Diagonal walls/corners may not render correctly
|
||||
- **Cause:** _BothBG routines need to write to both buffers simultaneously
|
||||
- **Current:** Handled in DrawObject but may not interact correctly with layers
|
||||
|
||||
### Issue 4: Layer Merge Effects
|
||||
- **Symptom:** Translucent/dark room effects not working
|
||||
- **Cause:** LayerMergeType flags not properly applied
|
||||
- **SNES behavior:** Controls PPU color math registers
|
||||
|
||||
## Part 4: Proposed Solution Architecture
|
||||
|
||||
### Option A: Tilemap-First Rendering (SNES-Accurate)
|
||||
|
||||
Change architecture to match SNES:
|
||||
1. All drawing writes to TILE BUFFER (not bitmap)
|
||||
2. Objects overwrite tile buffer entries
|
||||
3. Single `RenderTilemapToBitmap()` call at end
|
||||
4. Transparency via tile 0 or special tile entries
|
||||
|
||||
**Pros:** Most accurate, handles all edge cases
|
||||
**Cons:** Major refactor, breaks existing layer visibility feature
|
||||
|
||||
### Option B: Mask Buffer System
|
||||
|
||||
Add a mask buffer to track "transparent" areas:
|
||||
1. DrawFloor renders to bitmap
|
||||
2. BG2 objects mark mask buffer in their area
|
||||
3. When drawing BG1 floor, check mask and skip those pixels
|
||||
4. Or: Apply mask after all rendering to "punch holes"
|
||||
|
||||
**Pros:** Moderate changes, keeps 4-buffer design
|
||||
**Cons:** Additional buffer, may not handle all cases
|
||||
|
||||
### Option C: Deferred Floor Rendering
|
||||
|
||||
Change order to allow object interaction:
|
||||
1. Objects draw first (marking occupied areas)
|
||||
2. Floor draws AFTER, skipping marked areas
|
||||
3. Compositing remains same
|
||||
|
||||
**Pros:** Simpler change
|
||||
**Cons:** Doesn't match SNES order, may have edge cases
|
||||
|
||||
### Option D: Hybrid Tile/Pixel System
|
||||
|
||||
Best of both:
|
||||
1. Keep tile buffer for SNES-accurate object placement
|
||||
2. Objects can SET tile buffer entries to 0xFFFF (skip)
|
||||
3. DrawBackground checks for skip markers
|
||||
4. Then render layout/objects to bitmap
|
||||
|
||||
**Pros:** Can match SNES behavior while keeping visibility feature
|
||||
**Cons:** Requires careful coordination
|
||||
|
||||
## Part 5: Recommended Phased Approach
|
||||
|
||||
### Phase 1: Research & Validation (COMPLETE)
|
||||
- [x] Document exact SNES behavior for room 001
|
||||
- [x] Trace through ASM for specific object types (platforms, overlays)
|
||||
- [x] Identify which objects should create "holes" in BG1
|
||||
- [x] Create test case matrix (Room 001 as primary case)
|
||||
|
||||
### Phase 2: Prototype Solution
|
||||
- [ ] Implement Option D (Hybrid) in isolated branch
|
||||
- [ ] Test with room 001 and other known problem rooms
|
||||
- [ ] Validate layer visibility feature still works
|
||||
- [ ] Document any regressions
|
||||
|
||||
### Phase 3: Object Classification
|
||||
- [ ] Identify all objects that need BG1 masking
|
||||
- [ ] Add metadata to draw routines for mask behavior
|
||||
- [ ] Implement proper handling per object type
|
||||
|
||||
### Phase 4: Layer Merge Effects
|
||||
- [ ] Implement proper color math simulation
|
||||
- [ ] Handle dark rooms, translucency, addition
|
||||
- [ ] Test against real game screenshots
|
||||
|
||||
### Phase 5: Integration & Testing
|
||||
- [ ] Merge to main branch
|
||||
- [ ] Full regression testing
|
||||
- [ ] Performance validation
|
||||
- [ ] Documentation update
|
||||
|
||||
## Part 6: Next Immediate Steps
|
||||
|
||||
1. **Examine room 001 object data:**
|
||||
- What objects are on Layer 0 (BG1)?
|
||||
- What objects are on Layer 1 (BG2)?
|
||||
- Are there any "mask" or "pit" objects?
|
||||
|
||||
2. **Trace SNES rendering for room 001:**
|
||||
- What tilemap entries end up in BG1 for center area?
|
||||
- Are they tile 0 or floor tiles?
|
||||
|
||||
3. **Test hypothesis:**
|
||||
- If BG1 center has tile 0, our issue is in tile buffer management
|
||||
- If BG1 center has floor tiles with transparent pixels, issue is in graphics
|
||||
|
||||
## Part 7: Room 001 Case Study
|
||||
|
||||
### 7.1 Header Data
|
||||
|
||||
From `bank_04.asm` line 6123:
|
||||
```asm
|
||||
RoomHeader_Room0001:
|
||||
db $C0, $00, $00, $04, $00, $00, $00, $00, $00, $00, $72, $00, $50, $52
|
||||
```
|
||||
|
||||
Decoded:
|
||||
- **BG2PROP:** 0xC0
|
||||
- Layer2Mode = (0xC0 >> 5) = 6
|
||||
- LayerMerging = kLayerMergeTypeList[(0xC0 & 0x0C) >> 2] = LayerMerge00 "Off"
|
||||
- **PALETTE:** 0x00
|
||||
- **BLKSET:** 0x00
|
||||
- **SPRSET:** 0x04
|
||||
- **Effects:** None
|
||||
|
||||
### 7.2 Layer Merge "Off" Behavior
|
||||
|
||||
LayerMerge00 "Off" = {Layer2Visible=true, Layer2OnTop=false, Layer2Translucent=false}
|
||||
|
||||
This means:
|
||||
- BG2 IS visible on main screen
|
||||
- BG2 does NOT use color math effects
|
||||
- Standard Mode 1 priority: BG1 above BG2
|
||||
|
||||
### 7.3 What This Tells Us
|
||||
|
||||
Room 001 uses standard SNES Mode 1 rendering with no special layer effects.
|
||||
BG2 content SHOULD be visible where BG1 has transparent pixels (color 0) or
|
||||
where BG1 tilemap entries are tile 0 (empty).
|
||||
|
||||
The issue must be in HOW the tiles are written or rendered, not in the layer settings.
|
||||
|
||||
### 7.4 Next Step: Examine Object Data
|
||||
|
||||
Need to parse `bin/rooms/room0001.bin` to see:
|
||||
1. What objects are on Layer 0 (BG1)?
|
||||
2. What objects are on Layer 1 (BG2)?
|
||||
3. Are there any "mask" or "pit" objects?
|
||||
4. What happens at the 0xFFFF sentinels?
|
||||
|
||||
## Part 8: Phase 1 Research Findings (2025-12-07)
|
||||
|
||||
### 8.1 Room 001 Object Stream Analysis
|
||||
|
||||
Parsed room 001 object data from `alttp_vanilla.sfc`:
|
||||
|
||||
**Room Metadata:**
|
||||
- Floor byte: 0x66 → Floor1=6, Floor2=6 (same floor graphic for both layers)
|
||||
- Layout: 4
|
||||
|
||||
**Layer 0 (BG1 Main): 23 objects**
|
||||
- Walls: 0x001 (2x), 0x002 (2x) - horizontal walls
|
||||
- Corners: 0x100-0x103 (concave), 0x108-0x10B (4x4 corners)
|
||||
- Diagonals: 0x003 (2x), 0x004 (2x), 0x063, 0x064
|
||||
- Ceiling: 0x000 (4x)
|
||||
- Other: 0x03A (decor)
|
||||
|
||||
**Layer 1 (BG2 Overlay): 11 objects**
|
||||
- Walls at edges: 0x001 (2x), 0x002 (2x) at positions (1,13), (1,17), (59,13), (59,17)
|
||||
- **Center platform objects:**
|
||||
- 0x13B @ (30,10) - Inter-room staircase
|
||||
- 0x033 @ (22,13) size=4 - `RoomDraw_Rightwards4x4_1to16` (4x4 platform)
|
||||
- 0x034 @ (23,16) size=14 - `RoomDraw_Rightwards1x1Solid_1to16_plus3` (solid tiles)
|
||||
- 0x071 @ (22,13), (41,13) - `RoomDraw_Downwards1x1Solid_1to16_plus3` (vertical solid)
|
||||
- 0x038 @ (24,12), (34,12) - `RoomDraw_RightwardsStatue2x3spaced2_1to16` (statues)
|
||||
|
||||
**Layer 2 (BG1 Priority): 8 objects**
|
||||
- All torches: 0x0C6 (8x) at various positions
|
||||
|
||||
### 8.2 SNES 4-Pass Rendering (Confirmed)
|
||||
|
||||
From `bank_01.asm` analysis:
|
||||
|
||||
1. **Pass 1 (line 1104):** Layout objects drawn with default pointers → BG1
|
||||
2. **Pass 2 (line 1120):** Main room objects (Layer 0) → BG1
|
||||
3. **Pass 3 (lines 1127-1138):** Load `lower_layer` pointers ($7E4000), draw Layer 1 → BG2
|
||||
4. **Pass 4 (lines 1145-1156):** Load `upper_layer` pointers ($7E2000), draw Layer 2 → BG1
|
||||
|
||||
**Key Insight:** After floor drawing, the tilemap pointers remain set to upper_layer (BG1).
|
||||
Layout and Layer 0 objects write to BG1. Only Layer 1 writes to BG2.
|
||||
|
||||
### 8.3 The Transparency Mechanism
|
||||
|
||||
**How BG2 shows through BG1 in SNES:**
|
||||
1. Floor tiles are drawn to BOTH BG1 and BG2 tilemaps (same graphic)
|
||||
2. Layer 1 objects OVERWRITE BG2 tilemap entries with platform graphics
|
||||
3. BG1 tilemap retains floor tiles in the platform area
|
||||
4. **CRITICAL:** Floor tiles have color 0 (transparent) pixels
|
||||
5. PPU composites: where BG1 has color 0 pixels, BG2 shows through
|
||||
|
||||
**Current Editor Code (from `background_buffer.cc` line 161):**
|
||||
```cpp
|
||||
if (pixel != 0) {
|
||||
// Pixel 0 is transparent. Pixel 1 maps to palette index 0.
|
||||
uint8_t final_color = (pixel - 1) + palette_offset;
|
||||
canvas[dest_index] = final_color;
|
||||
}
|
||||
```
|
||||
The editor correctly skips pixel 0 as transparent! The bitmap is initialized to 255 (transparent).
|
||||
|
||||
### 8.4 Root Cause Identified
|
||||
|
||||
The issue is NOT in pixel-level transparency handling - that works correctly.
|
||||
|
||||
**The actual problem:** Floor graphic 6 tiles may be completely solid (no color 0 pixels),
|
||||
OR the compositing order doesn't match SNES behavior.
|
||||
|
||||
**Verification needed:**
|
||||
1. Check if floor graphic 6 tiles have any color 0 pixels
|
||||
2. If they do, verify compositing respects those transparent pixels
|
||||
3. If they don't, need a different mechanism (mask objects)
|
||||
|
||||
### 8.5 BG2MaskFull Object
|
||||
|
||||
Found `RoomDraw_BG2MaskFull` at routine 0x273 (line 6325):
|
||||
```asm
|
||||
RoomDraw_BG2MaskFull:
|
||||
STZ.b $0C
|
||||
LDX.w #obj00E0-RoomDrawObjectData
|
||||
JMP.w RoomDraw_FloorChunks
|
||||
```
|
||||
|
||||
This is an explicit mask object that draws floor tiles to create "holes" in a layer.
|
||||
However, room 001 does NOT use this object type.
|
||||
|
||||
### 8.6 Recommended Fix: Option E (Pixel-Perfect Compositing)
|
||||
|
||||
Based on research, the fix should ensure:
|
||||
|
||||
1. **Floor tile transparency is preserved:** Already working in `DrawTile()`
|
||||
2. **Compositing respects transparency:** `CompositeToOutput()` skips transparent pixels
|
||||
3. **Layer order is correct:** BG2 drawn first, BG1 drawn on top
|
||||
|
||||
**Specific changes needed:**
|
||||
|
||||
1. Verify floor graphic 6 tiles in the graphics data have color 0 pixels
|
||||
2. If floor tiles are solid, implement BG2MaskFull-style approach:
|
||||
- When Layer 1 objects are drawn, also clear corresponding BG1 pixels to transparent (255)
|
||||
- OR: Track Layer 1 object positions and skip those areas when drawing BG1 floor
|
||||
|
||||
3. Alternative: For rooms using LayerMerge00 "Off" with Layer 1 objects:
|
||||
- Draw BG2 floor + Layer 1 objects first
|
||||
- Draw BG1 floor with per-pixel transparency check
|
||||
- Where BG2 has non-transparent content from Layer 1, make BG1 transparent
|
||||
|
||||
### 8.7 Implementation Plan
|
||||
|
||||
**Phase 2 Tasks:**
|
||||
1. Create debug tool to visualize floor tile pixels (check for color 0)
|
||||
2. If floor tiles have transparency, fix compositing order/logic
|
||||
3. If floor tiles are solid, implement mask propagation from Layer 1 to BG1
|
||||
4. Test with room 001 and other known overlay rooms
|
||||
|
||||
**Files to modify:**
|
||||
- `src/app/gfx/render/background_buffer.cc` - Floor tile handling
|
||||
- `src/zelda3/dungeon/room_layer_manager.cc` - Compositing logic
|
||||
- `src/zelda3/dungeon/room.cc` - Layer 1 object tracking
|
||||
|
||||
## Answers to Open Questions
|
||||
|
||||
1. **How does SNES handle overlay areas?** Pixel-level transparency via color 0 in floor tiles.
|
||||
No explicit mask objects needed for standard overlays.
|
||||
|
||||
2. **What determines if BG2 shows through?** Color 0 pixels in BG1 tiles.
|
||||
Layer 1 objects only write to BG2, not BG1.
|
||||
|
||||
3. **Room-level data?** Floor graphics determine which tiles are used.
|
||||
Different floor graphics may have different transparency patterns.
|
||||
|
||||
4. **Per-tile priority bits?** Control BG1 vs BG2 priority per-tile.
|
||||
Not directly related to transparency (handled separately).
|
||||
|
||||
5. **Room 001 platform objects:** 0x033, 0x034, 0x071, 0x038 on Layer 1.
|
||||
|
||||
6. **Floor tile transparency:** Needs verification - check floor graphic 6 in graphics data.
|
||||
|
||||
---
|
||||
|
||||
**Status:** PHASE 1 COMPLETE - Ready for Phase 2 implementation
|
||||
|
||||
*Analysis script: `scripts/analyze_room.py`*
|
||||
|
||||
Usage examples:
|
||||
```bash
|
||||
# Analyze specific room
|
||||
python scripts/analyze_room.py 1
|
||||
|
||||
# Analyze with layer compositing details
|
||||
python scripts/analyze_room.py 1 --compositing
|
||||
|
||||
# List all rooms with BG2 overlay objects (94 total)
|
||||
python scripts/analyze_room.py --list-bg2
|
||||
|
||||
# Analyze range of rooms
|
||||
python scripts/analyze_room.py --range 0 20 --summary
|
||||
|
||||
# Output as JSON for programmatic use
|
||||
python scripts/analyze_room.py 1 --json
|
||||
```
|
||||
|
||||
211
docs/internal/plans/dungeon-object-rendering-master-plan.md
Normal file
211
docs/internal/plans/dungeon-object-rendering-master-plan.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Dungeon Object Rendering - Master Plan
|
||||
|
||||
## Completed Phases
|
||||
|
||||
### Phase 1: BG Layer Draw Order
|
||||
**Completed:** 2025-11-26
|
||||
- Swapped draw order: BG2 first (background), then BG1 (foreground)
|
||||
- Objects on BG1 no longer covered by BG2
|
||||
|
||||
### Phase 2: Wall Rendering Investigation
|
||||
**Completed:** 2025-11-26
|
||||
- Root cause: Bitmap initialization bug (1 byte instead of 262144)
|
||||
- Created ROM-dependent integration tests confirming fix
|
||||
|
||||
### Phase 3: Subtype1 Tile Count Lookup Table
|
||||
**Completed:** 2025-11-26
|
||||
- Added `kSubtype1TileLengths[0xF8]` from ZScream
|
||||
- Objects now load correct tile counts (e.g., 0xC1 = 68 tiles)
|
||||
|
||||
### Phase 4a: Type Detection Fixes
|
||||
**Completed:** 2025-11-26
|
||||
- Fix 1: Type 2/Type 3 decode order (check b1 >= 0xFC before b3 >= 0xF8)
|
||||
- Fix 2: Type 2 index mask 0x7F -> 0xFF
|
||||
- Fix 3: Type 3 threshold 0x200 -> 0xF80
|
||||
|
||||
### Phase 4b: North/South Wall Draw Routines
|
||||
**Completed:** 2025-11-26
|
||||
- Fixed column-major tile ordering in DrawRightwards2x4 routines
|
||||
- Updated routines: DrawRightwards2x4_1to15or26, DrawRightwards2x4spaced4_1to16
|
||||
- Changed tile guard from 4 tiles to 8 tiles (column-major uses full 8 tiles)
|
||||
- Objects 0x01-0x06 now render correctly
|
||||
|
||||
### Phase 4c: Corner Wall Objects (Partial)
|
||||
**Completed:** 2025-11-26
|
||||
- Mapped BothBG diagonal variants (objects 0x0C-0x20) to existing functions
|
||||
- Implemented DrawCorner4x4 for Type 2 corners (objects 0x40-0x4F)
|
||||
- Added routines 17-19 to draw routine registry
|
||||
|
||||
---
|
||||
|
||||
## Pending Phases
|
||||
|
||||
### Phase 4c: Corner Wall Objects (Remaining)
|
||||
**Status:** Deferred
|
||||
**Priority:** Medium
|
||||
|
||||
**Remaining work:**
|
||||
- Kinked corners (3x4 and 4x3) if needed after testing
|
||||
- Deep concave corners (2x2) if needed after testing
|
||||
- Note: Some corner IDs may overlap with diagonal objects; needs ZScream verification
|
||||
|
||||
**Reference - Column-Major Pattern (implemented):**
|
||||
```
|
||||
Column 0 Column 1
|
||||
[tile 0] [tile 4] <- Row 0
|
||||
[tile 1] [tile 5] <- Row 1
|
||||
[tile 2] [tile 6] <- Row 2
|
||||
[tile 3] [tile 7] <- Row 3
|
||||
```
|
||||
|
||||
**Implemented:**
|
||||
- Type 2 Corners (0x40-0x4F): DrawCorner4x4 - 4x4 column-major grid
|
||||
- Diagonal BothBG variants (0x0C-0x20): Mapped to existing diagonal functions
|
||||
|
||||
**Remaining (if needed after testing):**
|
||||
- Kinked N/S corners (0x10-0x13): 3x4 grid
|
||||
- Kinked E/W corners (0x14-0x17): 4x3 grid
|
||||
- Deep Concave corners (0x18-0x1B): 2x2 grid
|
||||
|
||||
**Note:** Objects 0x10-0x1B may be diagonals rather than corners based on ZScream analysis.
|
||||
Verify behavior with visual testing against ZScream output.
|
||||
|
||||
---
|
||||
|
||||
### Phase 4d: Floor Objects
|
||||
**Status:** Not started
|
||||
**Priority:** Medium
|
||||
|
||||
**Problem:** Floor objects not rendering.
|
||||
|
||||
**ZScream Analysis - Floor Object IDs:**
|
||||
|
||||
**Horizontal Floors (Rightwards):**
|
||||
| ID | Tiles | Draw Routine | Description |
|
||||
|----|-------|--------------|-------------|
|
||||
| 0x033 | 16 | RoomDraw_Rightwards4x4_1to16 | Standard 4x4 floor |
|
||||
| 0x034 | 1 | RoomDraw_Rightwards1x1Solid_1to16_plus3 | Solid floor with perimeter |
|
||||
| 0x0B2 | 16 | RoomDraw_Rightwards4x4_1to16 | 4x4 floor variant |
|
||||
| 0x0B3-0x0B4 | 1 | RoomDraw_RightwardsHasEdge1x1_1to16_plus2 | Edge floors |
|
||||
| 0x0BA | 16 | RoomDraw_Rightwards4x4_1to16 | 4x4 floor variant |
|
||||
|
||||
**Vertical Floors (Downwards):**
|
||||
| ID | Tiles | Draw Routine | Description |
|
||||
|----|-------|--------------|-------------|
|
||||
| 0x070 | 16 | RoomDraw_DownwardsFloor4x4_1to16 | Standard 4x4 floor |
|
||||
| 0x071 | 1 | RoomDraw_Downwards1x1Solid_1to16_plus3 | Solid floor with perimeter |
|
||||
| 0x094 | 16 | RoomDraw_DownwardsFloor4x4_1to16 | 4x4 floor variant |
|
||||
| 0x08D-0x08E | 1 | RoomDraw_DownwardsEdge1x1_1to16 | Edge floors |
|
||||
|
||||
**Special Floors (SuperSquare patterns):**
|
||||
| ID | Tiles | Draw Routine | Category |
|
||||
|----|-------|--------------|----------|
|
||||
| 0x0C3 | 9 | RoomDraw_3x3FloorIn4x4SuperSquare | Pits, MetaLayer |
|
||||
| 0x0C4-0x0CA | 16 | RoomDraw_4x4FloorIn4x4SuperSquare | Various |
|
||||
| 0x0DF | 16 | RoomDraw_4x4FloorIn4x4SuperSquare | Spikes |
|
||||
| 0x212 | 9 | RoomDraw_RupeeFloor | Secrets |
|
||||
| 0x247 | 16 | RoomDraw_BombableFloor | Pits, Manipulable |
|
||||
|
||||
**Layer Assignment:**
|
||||
- **Single-layer floors:** Drawn to object's assigned layer only
|
||||
- **Both-layer floors (MetaLayer):** Objects 0x0C3-0x0E8 drawn to BOTH BG1 and BG2
|
||||
- Floors typically on BG1 (background), walls on BG2 (foreground)
|
||||
|
||||
**4x4 Floor Tile Pattern:**
|
||||
```
|
||||
[0 ] [1 ] [2 ] [3 ]
|
||||
[4 ] [5 ] [6 ] [7 ]
|
||||
[8 ] [9 ] [10] [11]
|
||||
[12] [13] [14] [15]
|
||||
```
|
||||
|
||||
**BombableFloor Special Pattern (irregular):**
|
||||
```
|
||||
[0 ] [4 ] [2 ] [6 ]
|
||||
[8 ] [12] [10] [14]
|
||||
[1 ] [5 ] [3 ] [7 ]
|
||||
[9 ] [13] [11] [15]
|
||||
```
|
||||
|
||||
**Files:**
|
||||
- ZScream: `ZeldaFullEditor/Data/Types/DungeonObjectDraw.cs`
|
||||
- ZScream: `ZeldaFullEditor/Data/Types/DungeonObjectTypes.cs`
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: Validation & Lifecycle Fixes
|
||||
**Status:** Deferred
|
||||
**Priority:** Low
|
||||
|
||||
From original analysis:
|
||||
- Object ID validation range (0x3FF -> 0xFFF)
|
||||
- `tile_objects_` not cleared on reload
|
||||
|
||||
---
|
||||
|
||||
### Phase 6: Draw Routine Completion
|
||||
**Status:** Deferred
|
||||
**Priority:** Low
|
||||
|
||||
From original analysis:
|
||||
- Complete draw routine registry (routines 17-34 uninitialized)
|
||||
- Currently reserves 35 routines but only initializes 17
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
**Per-phase testing:**
|
||||
1. Test specific object types affected by the phase
|
||||
2. Compare against ZScream visual output
|
||||
3. Verify no regressions in previously working objects
|
||||
|
||||
**Key test rooms:**
|
||||
- Room 0x00: Basic walls
|
||||
- Rooms with complex wall arrangements
|
||||
- Agahnim's tower rooms (complex objects)
|
||||
|
||||
---
|
||||
|
||||
## Reference Files
|
||||
|
||||
**yaze:**
|
||||
- `src/zelda3/dungeon/object_drawer.cc` - Draw routines
|
||||
- `src/zelda3/dungeon/object_parser.cc` - Tile loading
|
||||
- `src/zelda3/dungeon/room_object.cc` - Object decoding
|
||||
- `docs/internal/plans/dungeon-object-rendering-fix-plan.md` - Original analysis
|
||||
|
||||
**ZScream (authoritative reference):**
|
||||
- `ZeldaFullEditor/Data/Types/DungeonObjectDraw.cs` - All draw routines
|
||||
- `ZeldaFullEditor/Data/Types/DungeonObjectTypes.cs` - Object definitions
|
||||
- `ZeldaFullEditor/Data/DungeonObjectData.cs` - Tile counts, routine mappings
|
||||
- `ZeldaFullEditor/Rooms/Room_Object.cs` - Object class, diagonal methods
|
||||
- `ZeldaFullEditor/Rooms/Object_Draw/Subtype2_Multiple.cs` - Type 2 corners
|
||||
|
||||
---
|
||||
|
||||
## Key ZScream Insights
|
||||
|
||||
### Critical Finding: Column-Major Tile Ordering
|
||||
ZScream's `RoomDraw_RightwardsXbyY` and `RoomDraw_DownwardsXbyY` use **column-major** tile iteration:
|
||||
```csharp
|
||||
for (int x = 0; x < sizex; x++) { // Outer loop: columns
|
||||
for (int y = 0; y < sizey; y++) { // Inner loop: rows
|
||||
draw_tile(tiles[t++], x * 8, y * 8);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This means for a 2x4 wall:
|
||||
- Tiles 0-3 go in column 0 (left)
|
||||
- Tiles 4-7 go in column 1 (right)
|
||||
|
||||
### Rightwards vs Downwards Difference
|
||||
The ONLY difference between horizontal and vertical routines is the increment axis:
|
||||
- **Rightwards:** `inc = sizex * 8` applied to X (repeats horizontally)
|
||||
- **Downwards:** `inc = sizey * 8` applied to Y (repeats vertically)
|
||||
|
||||
### Layer System
|
||||
- BG1 = Layer 1 (background/floor)
|
||||
- BG2 = Layer 2 (foreground/walls)
|
||||
- Some objects draw to BOTH via `allbg` flag
|
||||
256
docs/internal/plans/dungeon-object-rendering-phase4-handoff.md
Normal file
256
docs/internal/plans/dungeon-object-rendering-phase4-handoff.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# Phase 4: Dungeon Object Rendering - 0x80-0xFF Mapping Fixes
|
||||
|
||||
## Status: Steps 1, 2, 3, 4 Complete (2024-12-04)
|
||||
|
||||
### Completed
|
||||
- **Step 1**: Quick mapping fixes (6 corrections using existing routines)
|
||||
- **Step 2**: Simple variant routines (10 new routines, IDs 65-74)
|
||||
- **Step 3**: Diagonal ceiling routines (4 new routines, IDs 75-78, covering 12 objects)
|
||||
- **Step 4**: SuperSquare routines (9 new routines, IDs 56-64)
|
||||
|
||||
### Remaining
|
||||
- **Step 5**: Special/logic-dependent routines (6 new routines)
|
||||
|
||||
### Test Updates Required
|
||||
Some unit tests assert old (incorrect) mappings and need to be updated:
|
||||
- `test/unit/zelda3/dungeon/draw_routine_mapping_test.cc`
|
||||
- `test/unit/zelda3/dungeon/object_drawing_comprehensive_test.cc`
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
This document provides a handoff plan for completing Phase 4 of the dungeon object rendering system fixes. Phases 1-3 have been completed:
|
||||
|
||||
- **Phase 1**: Parser fixes (Type 2 index mask, routine pointer offset, removed fake mappings)
|
||||
- **Phase 2**: Dimension calculation fixes (dual-nibble bug, diagonal wall off-by-one)
|
||||
- **Phase 3**: Routine implementations for 0x40-0x7F range (13 new routines added)
|
||||
|
||||
## Phase 4 Scope
|
||||
|
||||
Fix object-to-routine mappings for the 0x80-0xFF range. The audit identified a **75.8% error rate** (97/128 objects with wrong mappings).
|
||||
|
||||
## Reference Files
|
||||
|
||||
- **Assembly Ground Truth**: `assets/asm/usdasm/bank_01.asm` (lines 397-516 for 0x80-0xF7)
|
||||
- **Implementation File**: `src/zelda3/dungeon/object_drawer.cc` (lines 330-479)
|
||||
- **Header File**: `src/zelda3/dungeon/object_drawer.h`
|
||||
|
||||
## Strategy
|
||||
|
||||
### Tier 1: Easy Fixes (Use Existing Routines)
|
||||
|
||||
These objects can be fixed by simply changing the routine ID to an existing routine:
|
||||
|
||||
| Object | Current | Correct Routine | Assembly Reference |
|
||||
|--------|---------|-----------------|-------------------|
|
||||
| 0x81-0x84 | 30 (4x3) | NEW: DownwardsDecor3x4spaced2 | `RoomDraw_DownwardsDecor3x4spaced2_1to16` |
|
||||
| 0x88 | 30 (4x3) | NEW: DownwardsBigRail3x1_plus5 | `RoomDraw_DownwardsBigRail3x1_1to16plus5` |
|
||||
| 0x89 | 11 | NEW: DownwardsBlock2x2spaced2 | `RoomDraw_DownwardsBlock2x2spaced2_1to16` |
|
||||
| 0x8D-0x8E | 25 (1x1) | 13 (DownwardsEdge1x1) | `RoomDraw_DownwardsEdge1x1_1to16` |
|
||||
| 0x90-0x91 | 8 | 8 (Downwards4x2_1to15or26) | Already correct! |
|
||||
| 0x92-0x93 | 11 | 7 (Downwards2x2_1to15or32) | `RoomDraw_Downwards2x2_1to15or32` |
|
||||
| 0x94 | 16 | 43 (DownwardsFloor4x4) | `RoomDraw_DownwardsFloor4x4_1to16` |
|
||||
| 0xB0-0xB1 | 25 | NEW: RightwardsEdge1x1_plus7 | `RoomDraw_RightwardsEdge1x1_1to16plus7` |
|
||||
| 0xB6-0xB7 | 8 | 1 (Rightwards2x4_1to15or26) | `RoomDraw_Rightwards2x4_1to15or26` |
|
||||
| 0xB8-0xB9 | 11 | 0 (Rightwards2x2_1to15or32) | `RoomDraw_Rightwards2x2_1to15or32` |
|
||||
| 0xBB | 11 | 55 (RightwardsBlock2x2spaced2) | `RoomDraw_RightwardsBlock2x2spaced2_1to16` |
|
||||
|
||||
### Tier 2: New Routine Implementations Required
|
||||
|
||||
These need new draw routines to be implemented:
|
||||
|
||||
#### 2A: Simple Variants (Low Effort)
|
||||
|
||||
| Routine Name | Objects | Pattern | Notes |
|
||||
|-------------|---------|---------|-------|
|
||||
| `DrawDownwardsDecor3x4spaced2_1to16` | 0x81-0x84 | 3x4 tiles, 6-row spacing | Similar to existing `DrawDownwardsDecor4x4spaced2_1to16` |
|
||||
| `DrawDownwardsBigRail3x1_1to16plus5` | 0x88 | 3x1 tiles, +5 modifier | Vertical version of existing `DrawRightwardsBigRail1x3_1to16plus5` |
|
||||
| `DrawDownwardsBlock2x2spaced2_1to16` | 0x89 | 2x2 tiles, 4-row spacing | Vertical version of existing `DrawRightwardsBlock2x2spaced2_1to16` |
|
||||
| `DrawDownwardsCannonHole3x4_1to16` | 0x85-0x86 | 3x4 cannon hole | Vertical version of existing cannon hole |
|
||||
| `DrawDownwardsBar2x5_1to16` | 0x8F | 2x5 bar pattern | New pattern |
|
||||
| `DrawDownwardsPots2x2_1to16` | 0x95 | 2x2 pots | Interactive object |
|
||||
| `DrawDownwardsHammerPegs2x2_1to16` | 0x96 | 2x2 hammer pegs | Interactive object |
|
||||
| `DrawRightwardsEdge1x1_1to16plus7` | 0xB0-0xB1 | 1x1 edge, +7 modifier | Similar to existing edge routines |
|
||||
| `DrawRightwardsPots2x2_1to16` | 0xBC | 2x2 pots | Interactive object |
|
||||
| `DrawRightwardsHammerPegs2x2_1to16` | 0xBD | 2x2 hammer pegs | Interactive object |
|
||||
|
||||
#### 2B: Complex/Special Routines (Higher Effort)
|
||||
|
||||
| Routine Name | Objects | Pattern | Notes |
|
||||
|-------------|---------|---------|-------|
|
||||
| `DrawDiagonalCeilingTopLeftA` | 0xA0 | Diagonal ceiling variant A | Complex diagonal pattern |
|
||||
| `DrawDiagonalCeilingBottomLeftA` | 0xA1 | Diagonal ceiling variant A | Complex diagonal pattern |
|
||||
| `DrawDiagonalCeilingTopRightA` | 0xA2 | Diagonal ceiling variant A | Complex diagonal pattern |
|
||||
| `DrawDiagonalCeilingBottomRightA` | 0xA3 | Diagonal ceiling variant A | Complex diagonal pattern |
|
||||
| `DrawDiagonalCeilingTopLeftB` | 0xA5, 0xA9 | Diagonal ceiling variant B | Complex diagonal pattern |
|
||||
| `DrawDiagonalCeilingBottomLeftB` | 0xA6, 0xAA | Diagonal ceiling variant B | Complex diagonal pattern |
|
||||
| `DrawDiagonalCeilingTopRightB` | 0xA7, 0xAB | Diagonal ceiling variant B | Complex diagonal pattern |
|
||||
| `DrawDiagonalCeilingBottomRightB` | 0xA8, 0xAC | Diagonal ceiling variant B | Complex diagonal pattern |
|
||||
| `DrawBigHole4x4_1to16` | 0xA4 | 4x4 big hole | Special floor cutout |
|
||||
| `Draw4x4BlocksIn4x4SuperSquare` | 0xC0, 0xC2 | 4x4 in 16x16 super square | Large composite object |
|
||||
| `Draw3x3FloorIn4x4SuperSquare` | 0xC3, 0xD7 | 3x3 in 16x16 super square | Large composite object |
|
||||
| `Draw4x4FloorIn4x4SuperSquare` | 0xC5-0xCA, 0xD1-0xD2, 0xD9, 0xDF-0xE8 | 4x4 floor pattern | Most common super square |
|
||||
| `Draw4x4FloorOneIn4x4SuperSquare` | 0xC4 | Single 4x4 in super square | Variant |
|
||||
| `Draw4x4FloorTwoIn4x4SuperSquare` | 0xDB | Two 4x4 in super square | Variant |
|
||||
| `DrawClosedChestPlatform` | 0xC1 | Chest platform (closed) | 68-tile special object |
|
||||
| `DrawOpenChestPlatform` | 0xDC | Chest platform (open) | State-dependent |
|
||||
| `DrawMovingWallWest` | 0xCD | Moving wall (west) | Logic-dependent |
|
||||
| `DrawMovingWallEast` | 0xCE | Moving wall (east) | Logic-dependent |
|
||||
| `DrawCheckIfWallIsMoved` | 0xD3-0xD6 | Wall movement check | Logic-only, no tiles |
|
||||
| `DrawWaterOverlayA8x8_1to16` | 0xD8 | Water overlay A | Semi-transparent overlay |
|
||||
| `DrawWaterOverlayB8x8_1to16` | 0xDA | Water overlay B | Semi-transparent overlay |
|
||||
| `DrawTableRock4x4_1to16` | 0xDD | Table rock pattern | 4x4 repeating |
|
||||
| `DrawSpike2x2In4x4SuperSquare` | 0xDE | Spikes in super square | Hazard object |
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
### Step 1: Quick Wins (30 min)
|
||||
Fix the easy ID corrections that use existing routines:
|
||||
- 0x8D-0x8E: Change from 25 to 13
|
||||
- 0x92-0x93: Change from 11 to 7
|
||||
- 0x94: Change from 16 to 43
|
||||
- 0xB6-0xB7: Change from 8 to 1
|
||||
- 0xB8-0xB9: Change from 11 to 0
|
||||
- 0xBB: Change from 11 to 55
|
||||
|
||||
### Step 2: Add Simple Variant Routines (2-3 hours)
|
||||
Create the Tier 2A routines by copying existing patterns and adjusting for vertical/horizontal orientation:
|
||||
|
||||
```cpp
|
||||
// Example: DrawDownwardsBlock2x2spaced2_1to16 (mirror of existing horizontal routine)
|
||||
void ObjectDrawer::DrawDownwardsBlock2x2spaced2_1to16(
|
||||
const RoomObject& obj, gfx::BackgroundBuffer& bg,
|
||||
std::span<const gfx::TileInfo> tiles, [[maybe_unused]] const DungeonState* state) {
|
||||
int size = obj.size_ & 0x0F;
|
||||
int count = size + 1;
|
||||
|
||||
for (int s = 0; s < count; s++) {
|
||||
if (tiles.size() >= 4) {
|
||||
int base_y = obj.y_ + (s * 4); // 4-tile Y spacing
|
||||
WriteTile8(bg, obj.x_, base_y, tiles[0]);
|
||||
WriteTile8(bg, obj.x_ + 1, base_y, tiles[1]);
|
||||
WriteTile8(bg, obj.x_, base_y + 1, tiles[2]);
|
||||
WriteTile8(bg, obj.x_ + 1, base_y + 1, tiles[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: SuperSquare Routines (4-6 hours)
|
||||
The `4x4FloorIn4x4SuperSquare` pattern is used by ~20 objects. Understanding it unlocks many fixes:
|
||||
|
||||
```
|
||||
SuperSquare = 16x16 tile area (128x128 pixels)
|
||||
- Draws 4x4 tile patterns at each corner position
|
||||
- Some variants fill differently (3x3, single, two, etc.)
|
||||
```
|
||||
|
||||
Analyze the assembly at `RoomDraw_4x4FloorIn4x4SuperSquare` to understand the exact tile placement.
|
||||
|
||||
### Step 4: Diagonal Ceiling Routines (2-3 hours)
|
||||
8 diagonal ceiling variants (A and B × 4 corners). These are similar to existing diagonal wall routines but for ceiling tiles.
|
||||
|
||||
### Step 5: Logic-Dependent Objects (1-2 hours)
|
||||
- `DrawMovingWallWest/East`: Check wall state before drawing
|
||||
- `DrawCheckIfWallIsMoved`: Logic-only, maps to "Nothing" for rendering
|
||||
- `DrawClosedChestPlatform/OpenChestPlatform`: Check chest state
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
1. **Visual Verification**: Load a ROM and visually compare dungeon rooms against screenshots or another editor (ZScream, Hyrule Magic)
|
||||
|
||||
2. **Target Rooms for Testing**:
|
||||
- Hyrule Castle rooms (variety of floor patterns)
|
||||
- Eastern Palace (diagonal ceilings at 0xA0-0xAC)
|
||||
- Thieves' Town (moving walls at 0xCD-0xCE)
|
||||
- Ice Palace (water overlays at 0xD8, 0xDA)
|
||||
|
||||
3. **Object Selection Test**: After rendering fixes, verify objects can be clicked/selected properly
|
||||
|
||||
## Current Routine Registry
|
||||
|
||||
As of Phase 4 Steps 1, 2, 3, 4 completion, we have 79 routines (0-78):
|
||||
|
||||
| ID Range | Description |
|
||||
|----------|-------------|
|
||||
| 0-6 | Rightwards basic patterns |
|
||||
| 7-15 | Downwards basic patterns |
|
||||
| 16 | Rightwards 4x4 |
|
||||
| 17-18 | Diagonal BothBG |
|
||||
| 19-39 | Various patterns (corners, edges, chests, etc.) |
|
||||
| 40-42 | Rightwards 4x2, Decor4x2spaced8, CannonHole4x3 |
|
||||
| 43-50 | New vertical routines (Phase 3.2) |
|
||||
| 51-55 | New horizontal routines (Phase 3.3) |
|
||||
| **56-64** | **Phase 4 SuperSquare routines** |
|
||||
| **65-74** | **Phase 4 Step 2 simple variant routines** |
|
||||
| **75-78** | **Phase 4 Step 3 diagonal ceiling routines** |
|
||||
|
||||
### Phase 4 New Routines (IDs 56-78)
|
||||
|
||||
**SuperSquare Routines (IDs 56-64)**:
|
||||
|
||||
| ID | Routine Name | Objects |
|
||||
|----|--------------|---------|
|
||||
| 56 | Draw4x4BlocksIn4x4SuperSquare | 0xC0, 0xC2 |
|
||||
| 57 | Draw3x3FloorIn4x4SuperSquare | 0xC3, 0xD7 |
|
||||
| 58 | Draw4x4FloorIn4x4SuperSquare | 0xC5-0xCA, 0xD1-0xD2, 0xD9, 0xDF-0xE8 |
|
||||
| 59 | Draw4x4FloorOneIn4x4SuperSquare | 0xC4 |
|
||||
| 60 | Draw4x4FloorTwoIn4x4SuperSquare | 0xDB |
|
||||
| 61 | DrawBigHole4x4_1to16 | 0xA4 |
|
||||
| 62 | DrawSpike2x2In4x4SuperSquare | 0xDE |
|
||||
| 63 | DrawTableRock4x4_1to16 | 0xDD |
|
||||
| 64 | DrawWaterOverlay8x8_1to16 | 0xD8, 0xDA |
|
||||
|
||||
**Step 2 Simple Variant Routines (IDs 65-74)**:
|
||||
|
||||
| ID | Routine Name | Objects |
|
||||
|----|--------------|---------|
|
||||
| 65 | DrawDownwardsDecor3x4spaced2_1to16 | 0x81-0x84 |
|
||||
| 66 | DrawDownwardsBigRail3x1_1to16plus5 | 0x88 |
|
||||
| 67 | DrawDownwardsBlock2x2spaced2_1to16 | 0x89 |
|
||||
| 68 | DrawDownwardsCannonHole3x6_1to16 | 0x85-0x86 |
|
||||
| 69 | DrawDownwardsBar2x3_1to16 | 0x8F |
|
||||
| 70 | DrawDownwardsPots2x2_1to16 | 0x95 |
|
||||
| 71 | DrawDownwardsHammerPegs2x2_1to16 | 0x96 |
|
||||
| 72 | DrawRightwardsEdge1x1_1to16plus7 | 0xB0-0xB1 |
|
||||
| 73 | DrawRightwardsPots2x2_1to16 | 0xBC |
|
||||
| 74 | DrawRightwardsHammerPegs2x2_1to16 | 0xBD |
|
||||
|
||||
**Step 3 Diagonal Ceiling Routines (IDs 75-78)**:
|
||||
|
||||
| ID | Routine Name | Objects |
|
||||
|----|--------------|---------|
|
||||
| 75 | DrawDiagonalCeilingTopLeft | 0xA0, 0xA5, 0xA9 |
|
||||
| 76 | DrawDiagonalCeilingBottomLeft | 0xA1, 0xA6, 0xAA |
|
||||
| 77 | DrawDiagonalCeilingTopRight | 0xA2, 0xA7, 0xAB |
|
||||
| 78 | DrawDiagonalCeilingBottomRight | 0xA3, 0xA8, 0xAC |
|
||||
|
||||
New routines should continue from ID 79.
|
||||
|
||||
## Files to Modify
|
||||
|
||||
1. **`src/zelda3/dungeon/object_drawer.h`**
|
||||
- Add declarations for new draw routines
|
||||
|
||||
2. **`src/zelda3/dungeon/object_drawer.cc`**
|
||||
- Update `object_to_routine_map_` entries (lines 330-479)
|
||||
- Add new routine implementations
|
||||
- Register new routines in `InitializeDrawRoutines()` (update reserve count)
|
||||
|
||||
3. **`src/zelda3/dungeon/object_dimensions.cc`** (optional)
|
||||
- Update dimension calculations if needed for new patterns
|
||||
|
||||
## Priority Order
|
||||
|
||||
1. **Highest**: Fix existing routine ID mappings (Step 1)
|
||||
2. **High**: Implement `Draw4x4FloorIn4x4SuperSquare` (unlocks ~20 objects)
|
||||
3. **Medium**: Add simple variant routines (Step 2)
|
||||
4. **Medium**: Diagonal ceiling routines (Step 4)
|
||||
5. **Lower**: Logic-dependent and special objects (Step 5)
|
||||
|
||||
## Notes
|
||||
|
||||
- The audit found that objects 0x97-0x9F, 0xAD-0xAF, 0xBE-0xBF, 0xE9-0xF7 correctly map to `RoomDraw_Nothing_B` (routine 38)
|
||||
- Some objects like 0xD3-0xD6 (`CheckIfWallIsMoved`) are logic-only and don't render tiles
|
||||
- Interactive objects (pots, hammer pegs) may need additional state handling
|
||||
1421
docs/internal/plans/editor-ui-refactor.md
Normal file
1421
docs/internal/plans/editor-ui-refactor.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,510 +0,0 @@
|
||||
# Emulator Debug API Design for AI Agent Integration
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document outlines the design for a comprehensive debugging API that enables AI agents to debug Zelda ROM hacks through the yaze emulator. The API provides execution control, memory inspection, disassembly, and analysis capabilities specifically tailored for 65816 and SPC700 debugging.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌─────────────────┐ ┌──────────────────┐
|
||||
│ AI Agent │◄────►│ Tool Dispatcher │◄────►│ gRPC Service │
|
||||
│ (Claude/GPT) │ │ │ │ │
|
||||
└──────────────────┘ └─────────────────┘ └──────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────┐ ┌──────────────────┐
|
||||
│ Tool Handlers │ │ Emulator Service │
|
||||
│ │ │ Implementation │
|
||||
└─────────────────┘ └──────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Debug Infrastructure │
|
||||
├─────────────────┬───────────────────────┤
|
||||
│ Disassembler │ Step Controller │
|
||||
│ Symbol Provider │ Breakpoint Manager │
|
||||
│ Memory Tracker │ State Snapshots │
|
||||
└─────────────────┴───────────────────────┘
|
||||
```
|
||||
|
||||
## Phase 1 (MVP) Features
|
||||
|
||||
### 1. Execution Control API
|
||||
|
||||
```cpp
|
||||
// Tool Dispatcher Commands
|
||||
enum class EmulatorDebugTool {
|
||||
// Basic execution
|
||||
kDebugRun, // Run until breakpoint or pause
|
||||
kDebugStep, // Single instruction step
|
||||
kDebugStepOver, // Step over JSR/JSL calls
|
||||
kDebugStepOut, // Step out of current subroutine
|
||||
kDebugPause, // Pause execution
|
||||
kDebugReset, // Reset to power-on state
|
||||
|
||||
// Breakpoint management
|
||||
kDebugSetBreak, // Set execution breakpoint
|
||||
kDebugClearBreak, // Clear breakpoint by ID
|
||||
kDebugListBreaks, // List all breakpoints
|
||||
kDebugToggleBreak, // Enable/disable breakpoint
|
||||
};
|
||||
```
|
||||
|
||||
#### Example Tool Call Structure:
|
||||
```cpp
|
||||
struct DebugStepRequest {
|
||||
enum StepType {
|
||||
SINGLE, // One instruction
|
||||
OVER, // Step over calls
|
||||
OUT, // Step out of routine
|
||||
TO_ADDRESS // Run to specific address
|
||||
};
|
||||
|
||||
StepType type;
|
||||
uint32_t target_address; // For TO_ADDRESS
|
||||
uint32_t max_steps; // Timeout protection
|
||||
};
|
||||
|
||||
struct DebugStepResponse {
|
||||
bool success;
|
||||
uint32_t pc; // New program counter
|
||||
uint32_t instruction_count;
|
||||
DisassembledInstruction current_instruction;
|
||||
std::vector<std::string> call_stack;
|
||||
std::string message;
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Memory Inspection API
|
||||
|
||||
```cpp
|
||||
enum class MemoryDebugTool {
|
||||
kMemoryRead, // Read memory region
|
||||
kMemoryWrite, // Write memory (for patching)
|
||||
kMemoryWatch, // Set memory watchpoint
|
||||
kMemoryCompare, // Compare two memory regions
|
||||
kMemorySearch, // Search for byte pattern
|
||||
kMemorySnapshot, // Save memory state
|
||||
kMemoryDiff, // Diff against snapshot
|
||||
};
|
||||
```
|
||||
|
||||
#### Memory Region Types:
|
||||
```cpp
|
||||
enum class MemoryRegion {
|
||||
WRAM, // Work RAM ($7E0000-$7FFFFF)
|
||||
SRAM, // Save RAM ($700000-$77FFFF)
|
||||
ROM, // ROM banks ($008000-$FFFFFF)
|
||||
VRAM, // Video RAM (PPU)
|
||||
OAM, // Sprite data
|
||||
CGRAM, // Palette data
|
||||
APU_RAM, // Audio RAM ($0000-$FFFF in SPC700 space)
|
||||
};
|
||||
|
||||
struct MemoryReadRequest {
|
||||
MemoryRegion region;
|
||||
uint32_t address; // 24-bit SNES address
|
||||
uint32_t size; // Bytes to read
|
||||
bool as_hex; // Format as hex dump
|
||||
bool with_symbols; // Include symbol annotations
|
||||
};
|
||||
|
||||
struct MemoryReadResponse {
|
||||
std::vector<uint8_t> data;
|
||||
std::string hex_dump;
|
||||
std::map<uint32_t, std::string> symbols; // Address -> symbol name
|
||||
std::string interpretation; // AI-friendly interpretation
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Disassembly API
|
||||
|
||||
```cpp
|
||||
enum class DisassemblyTool {
|
||||
kDisassemble, // Disassemble at address
|
||||
kDisassembleRange, // Disassemble N instructions
|
||||
kDisassembleContext, // Show surrounding code
|
||||
kFindInstruction, // Search for instruction pattern
|
||||
kGetCallStack, // Get current call stack
|
||||
kTraceExecution, // Get execution history
|
||||
};
|
||||
```
|
||||
|
||||
#### Disassembly Request/Response:
|
||||
```cpp
|
||||
struct DisassemblyRequest {
|
||||
uint32_t address;
|
||||
uint32_t instruction_count;
|
||||
uint32_t context_before; // Instructions before target
|
||||
uint32_t context_after; // Instructions after target
|
||||
bool include_symbols;
|
||||
bool include_execution_counts;
|
||||
bool track_branches; // Show branch targets
|
||||
};
|
||||
|
||||
struct DisassemblyResponse {
|
||||
struct Line {
|
||||
uint32_t address;
|
||||
std::string hex_bytes; // "20 34 80"
|
||||
std::string mnemonic; // "JSR"
|
||||
std::string operands; // "$8034"
|
||||
std::string symbol; // "MainGameLoop"
|
||||
std::string comment; // "; Initialize game state"
|
||||
bool is_breakpoint;
|
||||
bool is_current_pc;
|
||||
uint32_t execution_count;
|
||||
uint32_t branch_target; // For jumps/branches
|
||||
};
|
||||
|
||||
std::vector<Line> lines;
|
||||
std::string formatted_text; // Human-readable disassembly
|
||||
std::vector<std::string> referenced_symbols;
|
||||
};
|
||||
```
|
||||
|
||||
### 4. Analysis API
|
||||
|
||||
```cpp
|
||||
enum class AnalysisTool {
|
||||
kAnalyzeRoutine, // Analyze subroutine behavior
|
||||
kFindReferences, // Find references to address
|
||||
kDetectPattern, // Detect common bug patterns
|
||||
kCompareRom, // Compare with original ROM
|
||||
kProfileExecution, // Performance profiling
|
||||
kTrackDataFlow, // Track value propagation
|
||||
};
|
||||
```
|
||||
|
||||
## Tool Dispatcher Integration
|
||||
|
||||
### New Tool Definitions
|
||||
|
||||
```cpp
|
||||
// In tool_dispatcher.h
|
||||
enum class ToolCallType {
|
||||
// ... existing tools ...
|
||||
|
||||
// Debugger - Execution Control
|
||||
kDebugRun,
|
||||
kDebugStep,
|
||||
kDebugStepOver,
|
||||
kDebugStepOut,
|
||||
kDebugRunToAddress,
|
||||
|
||||
// Debugger - Breakpoints
|
||||
kDebugSetBreakpoint,
|
||||
kDebugSetWatchpoint,
|
||||
kDebugClearBreakpoint,
|
||||
kDebugListBreakpoints,
|
||||
kDebugEnableBreakpoint,
|
||||
|
||||
// Debugger - Memory
|
||||
kDebugReadMemory,
|
||||
kDebugWriteMemory,
|
||||
kDebugSearchMemory,
|
||||
kDebugCompareMemory,
|
||||
kDebugSnapshotMemory,
|
||||
|
||||
// Debugger - Disassembly
|
||||
kDebugDisassemble,
|
||||
kDebugGetCallStack,
|
||||
kDebugGetExecutionTrace,
|
||||
kDebugFindInstruction,
|
||||
|
||||
// Debugger - Analysis
|
||||
kDebugAnalyzeRoutine,
|
||||
kDebugFindReferences,
|
||||
kDebugDetectBugs,
|
||||
kDebugProfileCode,
|
||||
};
|
||||
```
|
||||
|
||||
### Tool Handler Implementation
|
||||
|
||||
```cpp
|
||||
class DebuggerToolHandler {
|
||||
public:
|
||||
explicit DebuggerToolHandler(EmulatorServiceImpl* service);
|
||||
|
||||
absl::StatusOr<ToolResponse> HandleDebugStep(const nlohmann::json& params);
|
||||
absl::StatusOr<ToolResponse> HandleDebugSetBreakpoint(const nlohmann::json& params);
|
||||
absl::StatusOr<ToolResponse> HandleDebugDisassemble(const nlohmann::json& params);
|
||||
absl::StatusOr<ToolResponse> HandleDebugReadMemory(const nlohmann::json& params);
|
||||
absl::StatusOr<ToolResponse> HandleDebugAnalyze(const nlohmann::json& params);
|
||||
|
||||
private:
|
||||
EmulatorServiceImpl* emulator_service_;
|
||||
Disassembler65816 disassembler_;
|
||||
SymbolProvider symbol_provider_;
|
||||
MemoryAnalyzer analyzer_;
|
||||
};
|
||||
```
|
||||
|
||||
## Example AI Agent Interactions
|
||||
|
||||
### Example 1: Debugging a Crash
|
||||
|
||||
**Agent Query:**
|
||||
```json
|
||||
{
|
||||
"tool": "debug_analyze",
|
||||
"params": {
|
||||
"problem": "Game crashes when entering dungeon room 15",
|
||||
"context": {
|
||||
"room_id": 15,
|
||||
"entrance_id": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**System Response:**
|
||||
```json
|
||||
{
|
||||
"analysis": {
|
||||
"crash_location": {
|
||||
"address": "0x008A45",
|
||||
"instruction": "LDA [$00],Y",
|
||||
"symbol": "LoadRoomHeader+0x15"
|
||||
},
|
||||
"cause": "Null pointer dereference",
|
||||
"explanation": "Direct page location $00 contains $0000, causing invalid long pointer access",
|
||||
"registers_at_crash": {
|
||||
"Y": "0x0010",
|
||||
"DP": "0x1E00",
|
||||
"$1E00": "0x0000"
|
||||
},
|
||||
"suggested_fix": "Check room header pointer before dereferencing",
|
||||
"call_stack": [
|
||||
"Module_Dungeon",
|
||||
"Dungeon_LoadRoom",
|
||||
"LoadRoomHeader"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Step-by-Step Debugging
|
||||
|
||||
**Agent Query:**
|
||||
```json
|
||||
{
|
||||
"tool": "debug_step",
|
||||
"params": {
|
||||
"type": "over",
|
||||
"with_context": true,
|
||||
"show_memory": ["$7E0010", "$7E0012"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"pc_before": "0x008034",
|
||||
"pc_after": "0x008037",
|
||||
"instruction_executed": {
|
||||
"address": "0x008034",
|
||||
"mnemonic": "JSR",
|
||||
"operand": "$8520",
|
||||
"symbol": "UpdateSprites",
|
||||
"cycles": 6
|
||||
},
|
||||
"context": {
|
||||
"before": [
|
||||
{"address": "0x008031", "instruction": "LDA $10", "value": "0x07"}
|
||||
],
|
||||
"after": [
|
||||
{"address": "0x008037", "instruction": "BEQ $8045"}
|
||||
]
|
||||
},
|
||||
"memory_values": {
|
||||
"$7E0010": "0x07",
|
||||
"$7E0012": "0x00"
|
||||
},
|
||||
"call_depth": 2
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Finding Bug Patterns
|
||||
|
||||
**Agent Query:**
|
||||
```json
|
||||
{
|
||||
"tool": "debug_detect_bugs",
|
||||
"params": {
|
||||
"patterns": ["stack_overflow", "invalid_bank", "dma_collision"],
|
||||
"range": {
|
||||
"start": "0x008000",
|
||||
"end": "0x00FFFF"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"bugs_found": [
|
||||
{
|
||||
"type": "potential_stack_overflow",
|
||||
"location": "0x009A23",
|
||||
"description": "Recursive JSR without stack check",
|
||||
"severity": "high",
|
||||
"suggestion": "Add stack pointer validation before recursive call"
|
||||
},
|
||||
{
|
||||
"type": "invalid_bank_switch",
|
||||
"location": "0x00B456",
|
||||
"description": "PHB without corresponding PLB",
|
||||
"severity": "medium",
|
||||
"suggestion": "Ensure data bank is restored after operation"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Example 4: Memory Watchpoint
|
||||
|
||||
**Agent Query:**
|
||||
```json
|
||||
{
|
||||
"tool": "debug_set_watchpoint",
|
||||
"params": {
|
||||
"address": "0x7E0020",
|
||||
"size": 2,
|
||||
"type": "write",
|
||||
"condition": "value > 0x00FF",
|
||||
"description": "Monitor game state overflow"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"watchpoint_id": 5,
|
||||
"status": "active",
|
||||
"message": "Watchpoint set on $7E0020-$7E0021 for writes > 0x00FF"
|
||||
}
|
||||
```
|
||||
|
||||
## Phase 2 (Full) Features
|
||||
|
||||
### Advanced Analysis
|
||||
- **Control Flow Graphs**: Generate CFG for routines
|
||||
- **Data Flow Analysis**: Track value propagation through code
|
||||
- **Symbolic Execution**: Analyze possible execution paths
|
||||
- **Pattern Matching**: Detect specific code patterns (e.g., DMA setup, HDMA tables)
|
||||
- **Performance Profiling**: Cycle-accurate performance analysis
|
||||
|
||||
### Enhanced Debugging
|
||||
- **Conditional Breakpoints**: Complex expressions (e.g., "A > 0x10 && X == 0")
|
||||
- **Trace Recording**: Record full execution traces to file
|
||||
- **Reverse Debugging**: Step backwards through recorded execution
|
||||
- **Memory Diffing**: Visual diff between memory states
|
||||
- **SPC700 Debugging**: Full audio processor debugging support
|
||||
|
||||
### AI-Specific Features
|
||||
- **Semantic Analysis**: Understanding game logic from assembly
|
||||
- **Bug Pattern Database**: ML-trained bug detection
|
||||
- **Automated Fix Suggestions**: Propose assembly patches for bugs
|
||||
- **Test Case Generation**: Generate test scenarios for ROM hacks
|
||||
- **Documentation Generation**: Auto-document assembly routines
|
||||
|
||||
## Implementation Priority
|
||||
|
||||
### Phase 1A (Immediate - Week 1-2)
|
||||
1. Basic step control (single, over, out)
|
||||
2. Simple breakpoints (address-based)
|
||||
3. Memory read/write operations
|
||||
4. Basic disassembly at address
|
||||
|
||||
### Phase 1B (Short-term - Week 3-4)
|
||||
1. Call stack tracking
|
||||
2. Symbol resolution
|
||||
3. Memory watchpoints
|
||||
4. Execution trace (last N instructions)
|
||||
|
||||
### Phase 1C (Medium-term - Week 5-6)
|
||||
1. Pattern-based bug detection
|
||||
2. Memory snapshots and comparison
|
||||
3. Advanced breakpoint conditions
|
||||
4. Performance metrics
|
||||
|
||||
### Phase 2 (Long-term - Month 2+)
|
||||
1. Full analysis suite
|
||||
2. SPC700 debugging
|
||||
3. Reverse debugging
|
||||
4. AI-specific enhancements
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Technical Metrics
|
||||
- Response time < 100ms for step operations
|
||||
- Support for 100+ simultaneous breakpoints without performance impact
|
||||
- Accurate disassembly for 100% of valid 65816 opcodes
|
||||
- Symbol resolution for all loaded ASM files
|
||||
|
||||
### User Experience Metrics
|
||||
- AI agents can identify crash causes in < 5 interactions
|
||||
- Step debugging provides sufficient context without overwhelming
|
||||
- Memory inspection clearly shows relevant game state
|
||||
- Bug detection has < 10% false positive rate
|
||||
|
||||
## Integration Points
|
||||
|
||||
### With Existing yaze Components
|
||||
- **Rom Class**: Read-only access to ROM data
|
||||
- **Emulator Core**: Direct CPU/PPU/APU state access
|
||||
- **Symbol Files**: Integration with usdasm output
|
||||
- **Canvas System**: Visual debugging overlays (Phase 2)
|
||||
|
||||
### With AI Infrastructure
|
||||
- **Tool Dispatcher**: Seamless tool call routing
|
||||
- **Prompt Builder**: Context-aware debugging prompts
|
||||
- **Agent Memory**: Persistent debugging session state
|
||||
- **Response Formatter**: Human-readable debug output
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Read-Only by Default**: Prevent accidental ROM corruption
|
||||
2. **Sandboxed Execution**: Limit memory access to emulated space
|
||||
3. **Rate Limiting**: Prevent runaway debugging loops
|
||||
4. **Audit Logging**: Track all debugging operations
|
||||
5. **Session Isolation**: Separate debug sessions per agent
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- Disassembler accuracy for all opcodes
|
||||
- Step controller call stack tracking
|
||||
- Breakpoint manager hit detection
|
||||
- Symbol provider resolution
|
||||
|
||||
### Integration Tests
|
||||
- Full debugging session workflows
|
||||
- gRPC service communication
|
||||
- Tool dispatcher routing
|
||||
- Memory state consistency
|
||||
|
||||
### End-to-End Tests
|
||||
- AI agent debugging scenarios
|
||||
- Bug detection accuracy
|
||||
- Performance under load
|
||||
- Error recovery paths
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
1. **API Reference**: Complete gRPC service documentation
|
||||
2. **Tool Guide**: How to use each debugging tool
|
||||
3. **Assembly Primer**: 65816 basics for AI agents
|
||||
4. **Common Patterns**: Debugging patterns for Zelda3
|
||||
5. **Troubleshooting**: Common issues and solutions
|
||||
|
||||
## Conclusion
|
||||
|
||||
This debugging API design provides a comprehensive foundation for AI agents to effectively debug SNES ROM hacks. The phased approach ensures quick delivery of core features while building toward advanced analysis capabilities. The integration with existing yaze infrastructure and focus on 65816-specific debugging makes this a powerful tool for ROM hacking assistance.
|
||||
|
||||
The API balances technical depth with usability, providing both low-level control for precise debugging and high-level analysis for pattern recognition. This enables AI agents to assist with everything from simple crash debugging to complex performance optimization.
|
||||
42
docs/internal/plans/hyrule-magic-support-plan.md
Normal file
42
docs/internal/plans/hyrule-magic-support-plan.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Implementation Plan - Hyrule Magic & Parallel Worlds Support
|
||||
|
||||
## Goal Description
|
||||
Add support for "doctoring" legacy Hyrule Magic (HM) ROMs and loading Parallel Worlds (PW) ROMs which use custom dungeon pointer tables.
|
||||
|
||||
## User Review Required
|
||||
- **Plan:** Review the proposed detection and compatibility logic.
|
||||
|
||||
## Proposed Changes
|
||||
|
||||
### 1. Hyrule Magic Doctor (`z3ed rom-doctor`)
|
||||
- **Detection:**
|
||||
- Detect HM header signatures (if any).
|
||||
- Detect "Bank 00 Erasure" (already implemented in Phase 1, confirmed working on `GoT-v040.smc`).
|
||||
- Detect Parallel Worlds by internal name or specific byte sequences.
|
||||
- **Fixes:**
|
||||
- **Checksum Fix:** Auto-calculate and update SNES checksum.
|
||||
- **Resize:** suggest resizing to 2MB/4MB if non-standard (e.g., 1.5MB PW ROMs).
|
||||
- **Bank 00 Restoration:** (Optional) If Bank 00 is erased, offer to restore from a vanilla ROM.
|
||||
|
||||
### 2. Parallel Worlds Compatibility Mode
|
||||
- **Problem:** PW uses a custom version of HM that moved dungeon pointer tables to support larger rooms/more data.
|
||||
- **Solution:**
|
||||
- Add `Rom::IsParallelWorlds()` check.
|
||||
- Implement `ParallelWorldsDungeonLoader` that uses the modified pointer tables.
|
||||
- **Offsets (To Be Verified):**
|
||||
- Vanilla Room Pointers: `0x21633` (PC)
|
||||
- PW Room Pointers: Need to locate these. Likely in expanded space.
|
||||
|
||||
### 3. Implementation Steps
|
||||
#### [NEW] [hm_support.cc](file:///Users/scawful/Code/yaze/src/rom/hm_support.cc)
|
||||
- Implement detection and fix logic.
|
||||
|
||||
#### [MODIFY] [rom_doctor_commands.cc](file:///Users/scawful/Code/yaze/src/cli/handlers/tools/rom_doctor_commands.cc)
|
||||
- Integrate HM/PW checks.
|
||||
|
||||
#### [MODIFY] [dungeon_loader.cc](file:///Users/scawful/Code/yaze/src/zelda3/dungeon/dungeon_loader.cc)
|
||||
- Add branching logic for PW ROMs to use alternate pointer tables.
|
||||
|
||||
## Verification Plan
|
||||
- **Doctor:** Run `z3ed rom-doctor` on `GoT-v040.smc` and `PW-V1349.SMC`.
|
||||
- **Load:** Attempt to load PW dungeon rooms in `yaze` (once loader is updated).
|
||||
@@ -1,772 +0,0 @@
|
||||
# Message Editor Implementation Roadmap
|
||||
|
||||
**Status**: Active Development
|
||||
**Last Updated**: 2025-11-21
|
||||
**Owner**: Frontend/UI Team
|
||||
**Related Docs**:
|
||||
- `docs/internal/architecture/message_system.md` (Gemini's architecture vision)
|
||||
- `docs/internal/plans/message_system_improvement_plan.md` (Gemini's feature proposals)
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This roadmap bridges Gemini's architectural vision with practical implementation steps for completing the Message Editor. The current implementation has the **core foundation** in place (message parsing, dictionary system, preview rendering) but lacks several key features proposed in Gemini's plan, particularly around **JSON import/export**, **translation workflows**, and **theme integration**.
|
||||
|
||||
---
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### What's Working (Completed Features)
|
||||
|
||||
#### Core Data Layer ✅
|
||||
- **MessageData**: Full implementation with raw/parsed representations
|
||||
- **DictionaryEntry**: Compression system with dictionary optimization
|
||||
- **TextElement**: Command and special character parsing
|
||||
- **Character Encoding**: Complete CharEncoder table (0x00-0x66)
|
||||
- **ROM Reading**: `ReadAllTextData()` successfully loads all 396 messages
|
||||
- **ROM Writing**: `Save()` handles two-bank text data with overflow detection
|
||||
|
||||
#### Message Preview System ✅
|
||||
- **MessagePreview**: Live rendering of messages as they appear in-game
|
||||
- **Font Graphics**: 2BPP font tiles loaded and displayed at 0x70000
|
||||
- **Character Widths**: Proportional font support via width table at 0x74ADF
|
||||
- **Preview Bitmap**: Real-time message rendering with proper palette support
|
||||
|
||||
#### Editor UI ✅
|
||||
- **Card System**: Four dockable cards (Message List, Editor, Font Atlas, Dictionary)
|
||||
- **Message List**: Table view with ID, contents, and address columns
|
||||
- **Text Editor**: Multiline input with live preview updates
|
||||
- **Command Insertion**: Buttons to insert text commands and special characters
|
||||
- **Dictionary Display**: Read-only view of all 97 dictionary entries
|
||||
- **Expanded Messages**: Basic support for loading external message bins
|
||||
|
||||
#### Testing Coverage ✅
|
||||
- **Unit Tests**: 20+ tests covering parsing, encoding, dictionary optimization
|
||||
- **Integration Tests**: ROM-dependent tests verify actual game data
|
||||
- **Command Parsing**: Regression tests for argument handling bugs
|
||||
|
||||
#### CLI Integration ✅
|
||||
- **Message List**: `z3ed message list --format json --range 0-100`
|
||||
- **Message Read**: `z3ed message read --id 5 --format json`
|
||||
- **Message Search**: `z3ed message search --query "Link"`
|
||||
- **Message Stats**: `z3ed message stats --format json`
|
||||
|
||||
### What's Missing (Gaps vs. Gemini's Vision)
|
||||
|
||||
#### 1. JSON Import/Export ❌ (HIGH PRIORITY)
|
||||
**Status**: Not implemented
|
||||
**Gemini's Vision**:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"address": 917504,
|
||||
"text": "[W:00][SPD:00]Welcome to [D:05]...",
|
||||
"context": "Uncle dying in sewers"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Current Gap**:
|
||||
- No `SerializeMessages()` or `DeserializeMessages()` in `MessageData`
|
||||
- No UI for export/import operations
|
||||
- No context field for translator notes
|
||||
- CLI has JSON output but not JSON input
|
||||
|
||||
**Impact**: Cannot version control text, cannot use external editors, cannot collaborate with translators
|
||||
|
||||
---
|
||||
|
||||
#### 2. Translation Workspace ❌ (MEDIUM PRIORITY)
|
||||
**Status**: Not implemented
|
||||
**Gemini's Vision**: Side-by-side view with reference ROM/JSON and editable translation
|
||||
|
||||
**Current Gap**:
|
||||
- No reference text display
|
||||
- No side-by-side layout
|
||||
- No translation progress tracking
|
||||
- No language-specific dictionary optimization
|
||||
|
||||
**Impact**: Manual translation workflows are tedious and error-prone
|
||||
|
||||
---
|
||||
|
||||
#### 3. Search & Replace ⚠️ (PARTIAL)
|
||||
**Status**: Stub implementation exists
|
||||
**Gemini's Vision**: Regex support, batch replace across all messages
|
||||
|
||||
**Current Implementation**:
|
||||
- `Find()` method exists in `MessageEditor` (lines 574-600)
|
||||
- Basic UI skeleton present (search input, case sensitivity toggle)
|
||||
- **Missing**: Replace functionality, regex support, "Find All", multi-message operations
|
||||
|
||||
**Impact**: Global text edits require manual per-message changes
|
||||
|
||||
---
|
||||
|
||||
#### 4. Theme Integration ❌ (LOW PRIORITY - UI POLISH)
|
||||
**Status**: Not implemented
|
||||
**Current Issues**:
|
||||
- No hardcoded `ImVec4` colors found (GOOD!)
|
||||
- Not using `AgentUITheme` system for consistency
|
||||
- Missing semantic color names for message editor components
|
||||
|
||||
**Impact**: Message Editor UI may not match rest of application theme
|
||||
|
||||
---
|
||||
|
||||
#### 5. Expanded ROM Support ⚠️ (PARTIAL)
|
||||
**Status**: Basic implementation exists
|
||||
**Gemini's Vision**: Repointing text blocks to expanded ROM space (Banks 10+), automatic bank switching
|
||||
|
||||
**Current Implementation**:
|
||||
- Can load expanded message bins (lines 322-334)
|
||||
- Can save expanded messages (lines 497-508)
|
||||
- **Missing**: Repointing logic, bank management, automatic overflow handling
|
||||
|
||||
**Impact**: Cannot support large translation projects that exceed vanilla space
|
||||
|
||||
---
|
||||
|
||||
#### 6. Scripting Integration ❌ (FUTURE)
|
||||
**Status**: Not planned
|
||||
**Gemini's Vision**: Lua/Python API for procedural text generation
|
||||
|
||||
**Current Gap**: No scripting hooks in message system
|
||||
|
||||
**Impact**: Low - nice-to-have for advanced users
|
||||
|
||||
---
|
||||
|
||||
## Architectural Decisions Required
|
||||
|
||||
### Decision 1: JSON Schema Design
|
||||
**Question**: What fields should the JSON export include?
|
||||
|
||||
**Proposal**:
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"rom_name": "zelda3.sfc",
|
||||
"messages": [
|
||||
{
|
||||
"id": 0,
|
||||
"address": 917504,
|
||||
"address_hex": "0xE0000",
|
||||
"text": "[W:00][SPD:00]Welcome...",
|
||||
"context": "Optional translator note",
|
||||
"dictionary_optimized": true,
|
||||
"expanded": false
|
||||
}
|
||||
],
|
||||
"dictionary": [
|
||||
{
|
||||
"id": 0,
|
||||
"token": "[D:00]",
|
||||
"contents": "the"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Trade-offs**:
|
||||
- Verbose but human-readable
|
||||
- Includes metadata for validation
|
||||
- Context field for translator workflow
|
||||
|
||||
**Status**: ✅ RECOMMENDED
|
||||
|
||||
---
|
||||
|
||||
### Decision 2: Translation Workspace Layout
|
||||
**Question**: How should reference vs. translation be displayed?
|
||||
|
||||
**Option A**: Side-by-side split pane
|
||||
```
|
||||
┌────────────────┬────────────────┐
|
||||
│ Reference │ Translation │
|
||||
│ (English) │ (Spanish) │
|
||||
│ [Read-only] │ [Editable] │
|
||||
│ │ │
|
||||
│ Message 0: │ Message 0: │
|
||||
│ "Welcome to │ "Bienvenido a │
|
||||
│ Hyrule" │ Hyrule" │
|
||||
└────────────────┴────────────────┘
|
||||
```
|
||||
|
||||
**Option B**: Top-bottom with context panel
|
||||
```
|
||||
┌────────────────────────────────┐
|
||||
│ Reference: "Welcome to Hyrule" │
|
||||
│ Context: Uncle's dying words │
|
||||
├────────────────────────────────┤
|
||||
│ Translation: │
|
||||
│ [Editable text box] │
|
||||
└────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Recommendation**: Option A for large screens, Option B for narrow windows
|
||||
|
||||
**Status**: ⚠️ NEEDS USER FEEDBACK
|
||||
|
||||
---
|
||||
|
||||
### Decision 3: Dictionary Auto-Optimization
|
||||
**Question**: Should we auto-generate optimal dictionary for new languages?
|
||||
|
||||
**Challenges**:
|
||||
- Dictionary optimization is NP-hard (longest common substring problem)
|
||||
- Need to preserve ROM space constraints (97 entries max)
|
||||
- Different languages have different common phrases
|
||||
|
||||
**Proposal**:
|
||||
1. Provide "Analyze Translation" button that suggests optimal dictionary
|
||||
2. Let user accept/reject suggestions
|
||||
3. Preserve manual dictionary entries
|
||||
|
||||
**Status**: ⚠️ NEEDS RESEARCH
|
||||
|
||||
---
|
||||
|
||||
## Implementation Priority Matrix
|
||||
|
||||
### Phase 1: Foundation (Sprint 1-2 weeks)
|
||||
**Goal**: JSON import/export with UI integration
|
||||
|
||||
#### Task 1.1: Implement JSON Serialization
|
||||
**Location**: `src/app/editor/message/message_data.h`, `message_data.cc`
|
||||
**Priority**: P0 (Blocker for translation workflow)
|
||||
**Estimated Effort**: 3 days
|
||||
|
||||
**Implementation**:
|
||||
```cpp
|
||||
// In MessageData
|
||||
nlohmann::json SerializeToJson() const;
|
||||
static absl::StatusOr<MessageData> DeserializeFromJson(const nlohmann::json& j);
|
||||
|
||||
// Free functions
|
||||
absl::Status ExportMessagesToJson(
|
||||
const std::vector<MessageData>& messages,
|
||||
const std::vector<DictionaryEntry>& dictionary,
|
||||
const std::string& output_path);
|
||||
|
||||
absl::StatusOr<std::vector<MessageData>> ImportMessagesFromJson(
|
||||
const std::string& input_path);
|
||||
```
|
||||
|
||||
**Dependencies**: nlohmann/json (already in project via CPM)
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Export all 396 messages to valid JSON
|
||||
- [ ] Import JSON and verify byte-for-byte ROM equivalence
|
||||
- [ ] Handle malformed JSON with clear error messages
|
||||
- [ ] Preserve dictionary optimization
|
||||
- [ ] Include context field in schema
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.2: Add Export/Import UI
|
||||
**Location**: `src/app/editor/message/message_editor.cc`
|
||||
**Priority**: P0
|
||||
**Estimated Effort**: 2 days
|
||||
|
||||
**UI Additions**:
|
||||
```cpp
|
||||
void MessageEditor::DrawExportImportPanel() {
|
||||
if (ImGui::Button("Export to JSON")) {
|
||||
std::string path = util::FileDialogWrapper::ShowSaveFileDialog("json");
|
||||
PRINT_IF_ERROR(ExportMessagesToJson(list_of_texts_,
|
||||
message_preview_.all_dictionaries_,
|
||||
path));
|
||||
}
|
||||
|
||||
if (ImGui::Button("Import from JSON")) {
|
||||
std::string path = util::FileDialogWrapper::ShowOpenFileDialog();
|
||||
auto result = ImportMessagesFromJson(path);
|
||||
if (result.ok()) {
|
||||
list_of_texts_ = result.value();
|
||||
RefreshMessageList();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] File dialogs open with correct filters
|
||||
- [ ] Progress indicator for large exports
|
||||
- [ ] Confirmation dialog on import (warns about overwriting)
|
||||
- [ ] Error popup on import failure with details
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.3: CLI JSON Import Support
|
||||
**Location**: `src/cli/handlers/game/message.cc`
|
||||
**Priority**: P1
|
||||
**Estimated Effort**: 1 day
|
||||
|
||||
**Implementation**:
|
||||
```bash
|
||||
z3ed message import --json messages.json --rom zelda3.sfc --output zelda3_translated.sfc
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Import JSON and write to ROM
|
||||
- [ ] Validate JSON schema before import
|
||||
- [ ] Verify ROM size constraints
|
||||
- [ ] Dry-run mode (validate without writing)
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Translation Workflow (Sprint 2-3 weeks)
|
||||
**Goal**: Side-by-side translation UI
|
||||
|
||||
#### Task 2.1: Add Translation Mode Card
|
||||
**Location**: `src/app/editor/message/message_editor.h`, `message_editor.cc`
|
||||
**Priority**: P1
|
||||
**Estimated Effort**: 5 days
|
||||
|
||||
**New Components**:
|
||||
```cpp
|
||||
class TranslationWorkspace {
|
||||
public:
|
||||
void Initialize(Rom* reference_rom, Rom* translation_rom);
|
||||
void DrawUI();
|
||||
void LoadReferenceFromJson(const std::string& path);
|
||||
|
||||
private:
|
||||
void DrawSideBySideView();
|
||||
void DrawProgressTracker();
|
||||
void UpdateTranslationProgress();
|
||||
|
||||
std::vector<MessageData> reference_messages_;
|
||||
std::vector<MessageData> translation_messages_;
|
||||
std::map<int, bool> translation_complete_flags_;
|
||||
Rom* reference_rom_ = nullptr;
|
||||
Rom* translation_rom_ = nullptr;
|
||||
};
|
||||
```
|
||||
|
||||
**UI Mockup**:
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Translation Progress: 42/396 (10.6%) │
|
||||
├──────────────────────┬──────────────────────────┤
|
||||
│ Reference (EN) │ Translation (ES) │
|
||||
├──────────────────────┼──────────────────────────┤
|
||||
│ Message 0: │ Message 0: │
|
||||
│ "Welcome to Hyrule" │ [Editable input box] │
|
||||
│ │ │
|
||||
│ Dictionary: [D:05] │ Dictionary: [D:05] │
|
||||
├──────────────────────┴──────────────────────────┤
|
||||
│ [Previous] [Next] [Mark Complete] [Skip] │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Load reference ROM or JSON
|
||||
- [ ] Display messages side-by-side
|
||||
- [ ] Track translation progress (per-message completion)
|
||||
- [ ] Keyboard shortcuts for navigation (Ctrl+N, Ctrl+P)
|
||||
- [ ] Auto-save translated ROM on completion
|
||||
|
||||
---
|
||||
|
||||
#### Task 2.2: Context/Notes System
|
||||
**Location**: `src/app/editor/message/message_data.h`
|
||||
**Priority**: P2
|
||||
**Estimated Effort**: 2 days
|
||||
|
||||
**Schema Addition**:
|
||||
```cpp
|
||||
struct MessageData {
|
||||
// ... existing fields ...
|
||||
std::string context; // Translator notes, scene context
|
||||
std::string screenshot_path; // Optional screenshot reference
|
||||
|
||||
nlohmann::json SerializeToJson() const {
|
||||
return {
|
||||
{"id", ID},
|
||||
{"address", Address},
|
||||
{"text", RawString},
|
||||
{"context", context},
|
||||
{"screenshot", screenshot_path}
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**UI Addition**:
|
||||
```cpp
|
||||
void MessageEditor::DrawContextPanel() {
|
||||
ImGui::InputTextMultiline("Context Notes", ¤t_message_.context);
|
||||
if (!current_message_.screenshot_path.empty()) {
|
||||
ImGui::Image(LoadScreenshot(current_message_.screenshot_path));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Context field persists in JSON export/import
|
||||
- [ ] Context displayed in translation workspace
|
||||
- [ ] Optional screenshot attachment (stored as relative path)
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Search & Replace (Sprint 3-1 week)
|
||||
**Goal**: Complete Find/Replace implementation
|
||||
|
||||
#### Task 3.1: Implement Replace Functionality
|
||||
**Location**: `src/app/editor/message/message_editor.cc`
|
||||
**Priority**: P2
|
||||
**Estimated Effort**: 2 days
|
||||
|
||||
**Implementation**:
|
||||
```cpp
|
||||
absl::Status MessageEditor::Replace(const std::string& find_text,
|
||||
const std::string& replace_text,
|
||||
bool case_sensitive,
|
||||
bool whole_word,
|
||||
bool all_messages) {
|
||||
int replaced_count = 0;
|
||||
|
||||
if (all_messages) {
|
||||
for (auto& message : list_of_texts_) {
|
||||
replaced_count += ReplaceInMessage(message, find_text, replace_text,
|
||||
case_sensitive, whole_word);
|
||||
}
|
||||
} else {
|
||||
replaced_count += ReplaceInMessage(current_message_, find_text,
|
||||
replace_text, case_sensitive, whole_word);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
```
|
||||
|
||||
**UI Updates**:
|
||||
```cpp
|
||||
void MessageEditor::DrawFindReplacePanel() {
|
||||
static char find_text[256] = "";
|
||||
static char replace_text[256] = "";
|
||||
|
||||
ImGui::InputText("Find", find_text, IM_ARRAYSIZE(find_text));
|
||||
ImGui::InputText("Replace", replace_text, IM_ARRAYSIZE(replace_text));
|
||||
|
||||
ImGui::Checkbox("Case Sensitive", &case_sensitive_);
|
||||
ImGui::Checkbox("Whole Word", &match_whole_word_);
|
||||
ImGui::Checkbox("All Messages", &replace_all_messages_);
|
||||
|
||||
if (ImGui::Button("Replace")) {
|
||||
PRINT_IF_ERROR(Replace(find_text, replace_text, case_sensitive_,
|
||||
match_whole_word_, false));
|
||||
}
|
||||
|
||||
if (ImGui::Button("Replace All")) {
|
||||
PRINT_IF_ERROR(Replace(find_text, replace_text, case_sensitive_,
|
||||
match_whole_word_, true));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Replace in current message
|
||||
- [ ] Replace in all messages
|
||||
- [ ] Case-sensitive/insensitive options
|
||||
- [ ] Whole word matching
|
||||
- [ ] Undo support (requires history stack)
|
||||
|
||||
---
|
||||
|
||||
#### Task 3.2: Add Regex Support
|
||||
**Location**: `src/app/editor/message/message_editor.cc`
|
||||
**Priority**: P3 (Nice-to-have)
|
||||
**Estimated Effort**: 2 days
|
||||
|
||||
**Implementation**:
|
||||
```cpp
|
||||
absl::Status MessageEditor::ReplaceRegex(const std::string& pattern,
|
||||
const std::string& replacement,
|
||||
bool all_messages) {
|
||||
std::regex regex_pattern;
|
||||
try {
|
||||
regex_pattern = std::regex(pattern);
|
||||
} catch (const std::regex_error& e) {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrFormat("Invalid regex: %s", e.what()));
|
||||
}
|
||||
|
||||
// Perform replacement...
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Regex validation with error messages
|
||||
- [ ] Capture group support ($1, $2, etc.)
|
||||
- [ ] Preview matches before replacement
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: UI Polish (Sprint 4-1 week)
|
||||
**Goal**: Theme integration and UX improvements
|
||||
|
||||
#### Task 4.1: Integrate AgentUITheme
|
||||
**Location**: `src/app/editor/message/message_editor.cc`
|
||||
**Priority**: P3
|
||||
**Estimated Effort**: 1 day
|
||||
|
||||
**Implementation**:
|
||||
```cpp
|
||||
void MessageEditor::DrawMessageList() {
|
||||
const auto& theme = AgentUI::GetTheme();
|
||||
|
||||
AgentUI::PushPanelStyle();
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, theme.panel_bg_darker);
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, theme.accent_color);
|
||||
|
||||
// ... table rendering ...
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
AgentUI::PopPanelStyle();
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] All panels use `AgentUI::PushPanelStyle()`
|
||||
- [ ] Section headers use `AgentUI::RenderSectionHeader()`
|
||||
- [ ] Buttons use `AgentUI::StyledButton()` where appropriate
|
||||
- [ ] Color scheme matches rest of editor
|
||||
|
||||
---
|
||||
|
||||
#### Task 4.2: Add Keyboard Shortcuts
|
||||
**Location**: `src/app/editor/message/message_editor.cc`
|
||||
**Priority**: P3
|
||||
**Estimated Effort**: 1 day
|
||||
|
||||
**Shortcuts**:
|
||||
- `Ctrl+F`: Open Find/Replace
|
||||
- `Ctrl+E`: Export to JSON
|
||||
- `Ctrl+I`: Import from JSON
|
||||
- `Ctrl+S`: Save ROM
|
||||
- `Ctrl+N`: Next message (in translation mode)
|
||||
- `Ctrl+P`: Previous message (in translation mode)
|
||||
|
||||
**Implementation**:
|
||||
```cpp
|
||||
void MessageEditor::HandleKeyboardShortcuts() {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F) &&
|
||||
ImGui::GetIO().KeyCtrl) {
|
||||
show_find_replace_ = true;
|
||||
}
|
||||
|
||||
// ... other shortcuts ...
|
||||
}
|
||||
```
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Shortcuts don't conflict with global shortcuts
|
||||
- [ ] Shortcuts displayed in tooltips
|
||||
- [ ] Configurable shortcuts (future enhancement)
|
||||
|
||||
---
|
||||
|
||||
## Test Strategy
|
||||
|
||||
### Unit Tests
|
||||
**Location**: `test/unit/message_data_test.cc` (new file)
|
||||
```cpp
|
||||
TEST(MessageDataTest, SerializeToJson_BasicMessage) {
|
||||
MessageData msg;
|
||||
msg.ID = 0;
|
||||
msg.Address = 0xE0000;
|
||||
msg.RawString = "Hello World";
|
||||
msg.context = "Test message";
|
||||
|
||||
auto json = msg.SerializeToJson();
|
||||
|
||||
EXPECT_EQ(json["id"], 0);
|
||||
EXPECT_EQ(json["text"], "Hello World");
|
||||
EXPECT_EQ(json["context"], "Test message");
|
||||
}
|
||||
|
||||
TEST(MessageDataTest, DeserializeFromJson_RoundTrip) {
|
||||
MessageData original;
|
||||
original.ID = 5;
|
||||
original.RawString = "[W:00][K]Test";
|
||||
|
||||
auto json = original.SerializeToJson();
|
||||
auto result = MessageData::DeserializeFromJson(json);
|
||||
|
||||
ASSERT_TRUE(result.ok());
|
||||
EXPECT_EQ(result.value().ID, 5);
|
||||
EXPECT_EQ(result.value().RawString, "[W:00][K]Test");
|
||||
}
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
**Location**: `test/integration/message_export_test.cc` (new file)
|
||||
```cpp
|
||||
TEST_F(MessageRomTest, ExportImport_RoundTrip) {
|
||||
// Export all messages to JSON
|
||||
std::string json_path = "/tmp/messages.json";
|
||||
EXPECT_OK(ExportMessagesToJson(list_of_texts_, dictionary_, json_path));
|
||||
|
||||
// Import back
|
||||
auto imported = ImportMessagesFromJson(json_path);
|
||||
ASSERT_TRUE(imported.ok());
|
||||
|
||||
// Verify identical
|
||||
EXPECT_EQ(imported.value().size(), list_of_texts_.size());
|
||||
for (size_t i = 0; i < list_of_texts_.size(); ++i) {
|
||||
EXPECT_EQ(imported.value()[i].RawString, list_of_texts_[i].RawString);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### E2E Tests
|
||||
**Location**: `test/e2e/message_editor_workflow_test.cc` (new file)
|
||||
```cpp
|
||||
TEST_F(MessageEditorE2ETest, TranslationWorkflow) {
|
||||
// Open translation workspace
|
||||
EXPECT_OK(ClickButton("Translation Mode"));
|
||||
|
||||
// Load reference ROM
|
||||
EXPECT_OK(OpenFileDialog("reference_rom.sfc"));
|
||||
|
||||
// Navigate to message 0
|
||||
EXPECT_EQ(GetCurrentMessageID(), 0);
|
||||
|
||||
// Edit translation
|
||||
EXPECT_OK(SetTextBoxValue("Bienvenido a Hyrule"));
|
||||
|
||||
// Mark complete
|
||||
EXPECT_OK(ClickButton("Mark Complete"));
|
||||
|
||||
// Verify progress
|
||||
EXPECT_EQ(GetTranslationProgress(), "1/396");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Risks
|
||||
|
||||
### External Dependencies
|
||||
1. **nlohmann/json**: Already integrated via CPM ✅
|
||||
2. **ImGui Test Engine**: Available for E2E tests ✅
|
||||
3. **File Dialog**: `util::FileDialogWrapper` already exists ✅
|
||||
|
||||
### Technical Risks
|
||||
|
||||
#### Risk 1: JSON Schema Evolution
|
||||
**Impact**: Breaking changes to JSON format
|
||||
**Mitigation**:
|
||||
- Include version number in schema
|
||||
- Implement forward/backward compatibility
|
||||
- Provide migration tool for old exports
|
||||
|
||||
#### Risk 2: Dictionary Auto-Optimization Complexity
|
||||
**Impact**: Algorithm may be too slow for real-time use
|
||||
**Mitigation**:
|
||||
- Run optimization in background thread
|
||||
- Provide progress indicator
|
||||
- Allow cancellation
|
||||
|
||||
#### Risk 3: Large ROM Size with Expanded Messages
|
||||
**Impact**: May exceed bank boundaries
|
||||
**Mitigation**:
|
||||
- Implement repointing logic early (Phase 5)
|
||||
- Warn user when approaching limits
|
||||
- Suggest dictionary optimization
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Quantitative Metrics
|
||||
- [ ] 100% message export/import success rate (no data loss)
|
||||
- [ ] JSON schema supports all 396 vanilla messages
|
||||
- [ ] Translation workspace reduces edit time by 50% vs. current workflow
|
||||
- [ ] Search/Replace handles batch operations in <1 second
|
||||
- [ ] 90%+ test coverage for new code
|
||||
|
||||
### Qualitative Metrics
|
||||
- [ ] Translator feedback: "Translation workflow is intuitive"
|
||||
- [ ] No hardcoded colors in Message Editor
|
||||
- [ ] UI matches yaze style guide
|
||||
- [ ] Documentation complete for all new features
|
||||
|
||||
---
|
||||
|
||||
## Timeline Estimate
|
||||
|
||||
| Phase | Duration | Effort (Dev Days) |
|
||||
|-------|----------|-------------------|
|
||||
| Phase 1: JSON Export/Import | 2 weeks | 6 days |
|
||||
| Phase 2: Translation Workspace | 3 weeks | 9 days |
|
||||
| Phase 3: Search & Replace | 1 week | 4 days |
|
||||
| Phase 4: UI Polish | 1 week | 2 days |
|
||||
| **Total** | **7 weeks** | **21 dev days** |
|
||||
|
||||
**Note**: Timeline assumes single developer working full-time. Adjust for part-time work or team collaboration.
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements (Post-MVP)
|
||||
|
||||
1. **Scripting API** (Gemini's vision)
|
||||
- Expose MessageData to Lua/Python
|
||||
- Allow procedural text generation
|
||||
- Useful for randomizers
|
||||
|
||||
2. **Cloud Translation Integration**
|
||||
- Google Translate API for quick drafts
|
||||
- DeepL API for quality translations
|
||||
- Requires API key management
|
||||
|
||||
3. **Collaborative Editing**
|
||||
- Real-time multi-user translation
|
||||
- Conflict resolution for concurrent edits
|
||||
- Requires network infrastructure
|
||||
|
||||
4. **ROM Patch Generation**
|
||||
- Export as `.ips` or `.bps` patch files
|
||||
- Useful for distribution without ROM sharing
|
||||
- Requires patch generation library
|
||||
|
||||
5. **Message Validation**
|
||||
- Check for overlong messages (exceeds textbox width)
|
||||
- Verify all messages have terminators
|
||||
- Flag unused dictionary entries
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Q**: Should we support multiple translation languages simultaneously?
|
||||
**A**: TBD - May require multi-ROM workspace UI
|
||||
|
||||
2. **Q**: How should we handle custom dictionary entries for expanded ROMs?
|
||||
**A**: TBD - Need research into ROM space allocation
|
||||
|
||||
3. **Q**: Should translation progress be persisted?
|
||||
**A**: TBD - Could store in `.yaze` project file
|
||||
|
||||
4. **Q**: Do we need undo/redo for message editing?
|
||||
**A**: TBD - ImGui InputTextMultiline has built-in undo, may be sufficient
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Message Editor has a **solid foundation** with core parsing, preview, and UI systems in place. The main gaps are **JSON export/import** (P0), **translation workspace** (P1), and **search/replace** (P2).
|
||||
|
||||
**Recommended Next Steps**:
|
||||
1. Start with Phase 1 (JSON export/import) - this unblocks all translation workflows
|
||||
2. Get user feedback on translation workspace mockups before Phase 2
|
||||
3. Defer theme integration to Phase 4 - not blocking functionality
|
||||
|
||||
**Estimated Effort**: ~7 weeks to MVP, ~21 dev days total.
|
||||
|
||||
**Success Criteria**: Translator can export messages to JSON, edit in external tool, and re-import without data loss. Side-by-side translation workspace reduces manual comparison time by 50%.
|
||||
@@ -1,56 +0,0 @@
|
||||
# Message System Improvement Plan
|
||||
|
||||
**Status**: Proposal
|
||||
**Last Updated**: 2025-11-21
|
||||
|
||||
This document outlines a plan to enhance the dialogue editing capabilities of YAZE, focusing on translation workflows and data portability.
|
||||
|
||||
## 1. JSON Import/Export
|
||||
|
||||
**Goal**: Enable external editing and version control of text.
|
||||
|
||||
* **Format**:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"address": 917504,
|
||||
"text": "[W:00][SPD:00]Welcome to [D:05]...",
|
||||
"context": "Uncle dying in sewers"
|
||||
}
|
||||
]
|
||||
```
|
||||
* **Implementation**:
|
||||
* Add `SerializeMessages()` and `DeserializeMessages()` to `MessageData`.
|
||||
* Integrate with the existing CLI `export` commands.
|
||||
|
||||
## 2. Translation Workspace
|
||||
|
||||
**Goal**: Facilitate translating the game into new languages.
|
||||
|
||||
* **Side-by-Side View**: Show the original text (Reference) next to the editable text (Translation).
|
||||
* **Reference Source**: Allow loading a second "Reference ROM" or a JSON file to serve as the source text.
|
||||
* **Dictionary Management**:
|
||||
* **Auto-Optimization**: Analyze the full translated text to propose a *new* optimal dictionary for that language.
|
||||
* **Manual Editing**: Allow users to define custom dictionary entries.
|
||||
|
||||
## 3. Expanded Text Support
|
||||
|
||||
**Goal**: Break free from vanilla size limits.
|
||||
|
||||
* **Repointing**: Allow the text blocks to be moved to expanded ROM space (Banks 10+).
|
||||
* **Bank Management**: Handle bank switching commands automatically when text exceeds 64KB.
|
||||
|
||||
## 4. Search & Replace
|
||||
|
||||
**Goal**: Global editing operations.
|
||||
|
||||
* **Regex Support**: Advanced search across all messages.
|
||||
* **Batch Replace**: "Replace 'Hyrule' with 'Lorule' in all messages".
|
||||
|
||||
## 5. Scripting Integration
|
||||
|
||||
**Goal**: Allow procedural generation of text.
|
||||
|
||||
* **Lua/Python API**: Expose message data to the scripting engine.
|
||||
* **Usage**: "Generate 100 variations of the shopkeeper dialogue".
|
||||
454
docs/internal/plans/music_editor.md
Normal file
454
docs/internal/plans/music_editor.md
Normal file
@@ -0,0 +1,454 @@
|
||||
# Music Editor Development Guide
|
||||
|
||||
This is a living document tracking the development of yaze's SNES music editor.
|
||||
|
||||
## Overview
|
||||
|
||||
The music editor enables editing ALTTP music data stored in ROM, composing new songs, and integrating with the Oracle of Secrets music_macros ASM format for custom music.
|
||||
|
||||
## Sprint Plan
|
||||
|
||||
### Sprint 1: Data Model
|
||||
**Status: Complete**
|
||||
|
||||
- Core data structures (`Note`, `MusicCommand`, `TrackEvent`, `MusicSong`)
|
||||
- `MusicBank` manager for ROM loading/saving
|
||||
- `SpcParser` and `SpcSerializer`
|
||||
- `BrrCodec` for sample handling
|
||||
|
||||
### Sprint 2: Tracker View (Read-Only)
|
||||
**Status: Complete**
|
||||
|
||||
- `TrackerView` component with 8-channel grid
|
||||
- Song selector and playback integration
|
||||
- Visualization of notes and commands
|
||||
|
||||
### Sprint 3: Tracker Editing
|
||||
**Status: Complete**
|
||||
|
||||
- Keyboard navigation and note entry
|
||||
- Selection system (cells and ranges)
|
||||
- Undo/Redo system
|
||||
- Clipboard placeholder
|
||||
|
||||
### Sprint 4: APU Playback
|
||||
**Status: Complete**
|
||||
|
||||
- Mixer Panel with Mute/Solo
|
||||
- Real-time Volume Meters
|
||||
- Master Oscilloscope
|
||||
- DSP state integration
|
||||
|
||||
### Sprint 5: Piano Roll
|
||||
**Status: Complete**
|
||||
|
||||
- `PianoRollView` component (Horizontal)
|
||||
- Mouse-based note entry/editing
|
||||
- Zoom controls
|
||||
- Integrated with `MusicEditor` state
|
||||
|
||||
### Sprint 6: Instruments & Samples
|
||||
**Status: Complete**
|
||||
|
||||
- `InstrumentEditorView`: ADSR visualization (`ImPlot`), property editing.
|
||||
- `SampleEditorView`: Waveform visualization (`ImPlot`), loop point editing.
|
||||
- Basic WAV import placeholder (generates sine wave).
|
||||
- Integrated into `MusicEditor` tabs.
|
||||
|
||||
### Sprint 7: Project Management & Song Browser
|
||||
**Status: Complete**
|
||||
|
||||
- **Song Browser:**
|
||||
- Tree view separating "Vanilla Songs" (IDs 1-34) and "Custom Songs" (IDs 35+).
|
||||
- Dockable "Song Browser" card in Activity Bar.
|
||||
- Search filtering and context menus (Duplicate/Delete).
|
||||
- **Integration:**
|
||||
- Replaced legacy dropdown selector with robust browser selection.
|
||||
- Linked `MusicEditor` state to browser actions.
|
||||
|
||||
### Sprint 8: Export & Polish
|
||||
**Status: In Progress**
|
||||
|
||||
- ✅ Integrated `SpcParser::ParseSong()` into `MusicBank::LoadSongTable()` so the editor now reflects real ROM song data (vanilla + custom slots).
|
||||
- [ ] ROM patching finalization (ensure `SaveToRom` works robustly).
|
||||
- [ ] ASM export (`music_macros` format generation).
|
||||
- [ ] SPC file export (standalone).
|
||||
- [ ] Full WAV import/resampling logic (replace dummy sine wave).
|
||||
|
||||
---
|
||||
|
||||
## Quality Improvements (Review Findings)
|
||||
|
||||
Tracked fixes identified during the agent swarm code review.
|
||||
|
||||
### High Priority (Blockers)
|
||||
- [x] **Replace hardcoded colors with theme system** - `tracker_view.cc` (4 instances), `music_editor.cc` (3 instances)
|
||||
- [x] **Integrate SpcParser into MusicBank** - `MusicBank::LoadSongTable()` now uses `SpcParser::ParseSong()`
|
||||
- [ ] **Fix serializer relocation bug** - Track address calculation in `SerializeSong` is incorrect
|
||||
- [ ] **Implement SaveToRom()** - Currently returns `UnimplementedError`
|
||||
|
||||
### Medium Priority (Quality)
|
||||
- [x] **Add undo stack size limit** - Capped at 50 states with FIFO eviction (`music_editor.cc`)
|
||||
- [x] **Fix oscilloscope ring buffer wrap-around** - Proper mask `& (kBufferSize - 1)` (`music_editor.cc`)
|
||||
- [ ] **Add VU meter smoothing/peak-hold** - Currently uses instantaneous sample values
|
||||
- [x] **Change Copy()/Paste() to return UnimplementedError** - Honest API reporting (`music_editor.cc`)
|
||||
|
||||
### Low Priority (Nice to Have)
|
||||
- [ ] Add stereo oscilloscope toggle
|
||||
- [ ] Implement range deletion in TrackerView
|
||||
- [ ] Add visual octave indicator (F1/F2 feedback)
|
||||
- [ ] Per-song undo stacks
|
||||
|
||||
### Test Gaps
|
||||
- [ ] ROM-dependent integration tests (`test/e2e/rom_dependent/music_rom_test.cc`)
|
||||
- [ ] Error handling tests for parse failures
|
||||
- [ ] Parse → Serialize → Parse roundtrip validation
|
||||
|
||||
---
|
||||
|
||||
### Sprint 9: Expanded Music Banks (Oracle of Secrets Integration)
|
||||
**Status: Planned**
|
||||
|
||||
The Oracle of Secrets ROM hack demonstrates expanded music bank support, allowing custom songs beyond vanilla ROM limits. This sprint brings those capabilities to yaze.
|
||||
|
||||
**Goals:**
|
||||
- [ ] Support for expanded bank detection (`SongBank_OverworldExpanded_Main`)
|
||||
- [ ] Dynamic bank allocation for custom songs (slots 35+)
|
||||
- [ ] Auxiliary bank support (`SONG_POINTERS_AUX` at `$2B00`)
|
||||
- [ ] Bank space visualization with overflow warnings
|
||||
- [ ] Auto-relocate songs when bank space exceeded
|
||||
|
||||
**Bank Architecture (from Oracle of Secrets):**
|
||||
|
||||
| Symbol | Address | Purpose |
|
||||
|--------|---------|---------|
|
||||
| `SPC_ENGINE` | `$0800` | Sound driver code |
|
||||
| `SFX_DATA` | `$17C0` | Sound effects |
|
||||
| `SAMPLE_POINTERS` | `$3C00` | Sample directory |
|
||||
| `INSTRUMENT_DATA` | `$3D00` | Instrument definitions |
|
||||
| `SAMPLE_DATA` | `$4000` | BRR sample data |
|
||||
| `SONG_POINTERS` | `$D000` | Main song pointer table |
|
||||
| `SONG_POINTERS_AUX` | `$2B00` | Auxiliary song pointers |
|
||||
|
||||
### Sprint 10: ASM Editor Integration
|
||||
**Status: Planned**
|
||||
|
||||
Full integration with Oracle of Secrets `music_macros.asm` format for bidirectional editing.
|
||||
|
||||
**Goals:**
|
||||
- [ ] Import `.asm` song files directly
|
||||
- [ ] Export songs to `music_macros` syntax
|
||||
- [ ] Syntax highlighting for N-SPC commands
|
||||
- [ ] Live preview compilation (ASM → binary → playback)
|
||||
- [ ] Subroutine deduplication detection
|
||||
|
||||
**Export Format Example:**
|
||||
```asm
|
||||
MySong:
|
||||
!ARAMAddr = $D86A
|
||||
dw !ARAMAddr+$0A ; Intro section
|
||||
dw !ARAMAddr+$1A ; Looping section
|
||||
dw $00FF ; Fade-in
|
||||
dw !ARAMAddr+$02 ; Loop start
|
||||
dw $0000
|
||||
|
||||
.Channels
|
||||
!ARAMC = !ARAMAddr-MySong
|
||||
dw .Channel0+!ARAMC
|
||||
dw .Channel1+!ARAMC
|
||||
; ... 8 channels
|
||||
|
||||
.Channel0
|
||||
%SetMasterVolume($DA)
|
||||
%SetTempo(62)
|
||||
%Piano()
|
||||
%SetDurationN(!4th, $7F)
|
||||
%CallSubroutine(.MelodyA+!ARAMC, 3)
|
||||
db End
|
||||
```
|
||||
|
||||
### Sprint 11: Common Patterns Library
|
||||
**Status: Planned**
|
||||
|
||||
Inspired by Oracle of Secrets documentation proposals for reusable musical patterns.
|
||||
|
||||
**Goals:**
|
||||
- [ ] Built-in pattern library (drum loops, arpeggios, basslines)
|
||||
- [ ] User-defined pattern saving/loading
|
||||
- [ ] Pattern browser with preview
|
||||
- [ ] Auto-convert repeated sections to subroutines
|
||||
|
||||
**Pattern Categories:**
|
||||
- Percussion: Standard 4/4 beats, fills, breaks
|
||||
- Basslines: Walking bass, pedal tones, arpeggiated
|
||||
- Arpeggios: Major, minor, diminished, suspended
|
||||
- Effects: Risers, sweeps, transitions
|
||||
|
||||
---
|
||||
|
||||
## Oracle of Secrets Integration
|
||||
|
||||
### music_macros.asm Reference
|
||||
|
||||
The Oracle of Secrets project uses a comprehensive macro system for music composition. Key macros that yaze should support for import/export:
|
||||
|
||||
**Duration Constants:**
|
||||
| Macro | Value | Description |
|
||||
|-------|-------|-------------|
|
||||
| `!4th` | `$48` | Quarter note (72 ticks) |
|
||||
| `!4thD` | `$6C` | Dotted quarter (108 ticks) |
|
||||
| `!4thT` | `$30` | Quarter triplet (48 ticks) |
|
||||
|
||||
---
|
||||
|
||||
## Plain-English Reference (Tracker/ASM)
|
||||
|
||||
### Tracker Cell Cheatsheet
|
||||
- **Tick column**: absolute tick where the event starts (0-based). Quarter note = 72 ticks, eighth = 36, sixteenth = 18.
|
||||
- **Pitch**: C1 = `$80`, B6 = `$C7`; `$C8` = tie, `$C9` = rest.
|
||||
- **Duration**: stored per-note; tracker shows the event at the start tick, piano roll shows its full width.
|
||||
- **Channel**: 8 channels run in parallel; channel-local commands (transpose/volume/pan) affect only that lane.
|
||||
|
||||
### Common N-SPC Commands (0xE0–0xFF)
|
||||
- `$E0 SetInstrument i` — pick instrument index `i` (0–24 vanilla ALTTP).
|
||||
- `$E1 SetPan p` — pan left/right (`$00` hard L, `$10` center, `$1F` hard R).
|
||||
- `$E5 SetMasterVolume v` — global volume.
|
||||
- `$E7 SetTempo t` — tempo; higher = faster.
|
||||
- `$E9 GlobalTranspose s` — shift all channels by semitones (signed byte).
|
||||
- `$EA ChannelTranspose s` — shift this channel only.
|
||||
- `$ED SetChannelVolume v` — per-channel volume.
|
||||
- `$EF CallSubroutine addr, reps` — jump to a subroutine `reps` times.
|
||||
- `$F5 EchoVBits mask` / `$F6 EchoOff` — enable/disable echo.
|
||||
- `$F7 EchoParams vL vR delay` — echo volume/delay.
|
||||
- `$F9 PitchSlide` — slide toward target pitch.
|
||||
- `$FA PercussionPatch` — switch to percussion set.
|
||||
- `$FF` (unused), `$00` marks track end.
|
||||
|
||||
### Instruments (ALTTP table at $3D00)
|
||||
- **Bytes**: `[sample][AD][SR][gain][pitch_hi][pitch_lo]`
|
||||
- `sample` = BRR slot (0–24 in vanilla).
|
||||
- `AD` = Attack (bits0-3, 0=slow, F=fast) + Decay (bits4-6).
|
||||
- `SR` = Sustain rate (bits0-4, higher = faster decay) + Sustain level (bits5-7, 0=quiet, 7=loud).
|
||||
- `gain` = raw gain byte (rarely used in ALTTP; ADSR preferred).
|
||||
- `pitch_hi/lo` = 16-bit pitch multiplier (0x1000 = normal; >0x1000 raises pitch).
|
||||
- In the tracker, a `SetInstrument` command changes these fields for the channel until another `$E0` appears.
|
||||
|
||||
### music_macros Quick Map
|
||||
- `%SetInstrument(i)` → `$E0 i`
|
||||
- `%SetPan(p)` → `$E1 p`
|
||||
- `%SetTempo(t)` → `$E7 t`
|
||||
- `%SetChannelVolume(v)` → `$ED v`
|
||||
- `%CallSubroutine(label, reps)` → `$EF` + 16-bit pointer + `reps`
|
||||
- `%SetDurationN(!4th, vel)` → duration prefix + note byte; duration constants map to the table above.
|
||||
- Note names in macros (e.g., `%C4`, `%F#3`) map directly to tracker pitches (C1 = `$80`).
|
||||
|
||||
### Durations and Snapping
|
||||
- Quarter = 72 ticks, Eighth = 36, Sixteenth = 18, Triplets use the `T` constants (e.g., `!4thT` = 48).
|
||||
- Piano roll snap defaults to sixteenth (18 ticks); turn snap off to place micro-timing.
|
||||
| `!8th` | `$24` | Eighth note (36 ticks) |
|
||||
| `!8thD` | `$36` | Dotted eighth (54 ticks) |
|
||||
| `!8thT` | `$18` | Eighth triplet (24 ticks) |
|
||||
| `!16th` | `$12` | Sixteenth (18 ticks) |
|
||||
| `!32nd` | `$09` | Thirty-second (9 ticks) |
|
||||
|
||||
**Instrument Helpers:**
|
||||
```asm
|
||||
%Piano() ; SetInstrument($18)
|
||||
%Strings() ; SetInstrument($09)
|
||||
%Trumpet() ; SetInstrument($11)
|
||||
%Flute() ; SetInstrument($16)
|
||||
%Choir() ; SetInstrument($15)
|
||||
%Tympani() ; SetInstrument($02)
|
||||
%Harp() ; SetInstrument($0F)
|
||||
%Snare() ; SetInstrument($13)
|
||||
```
|
||||
|
||||
**Note Constants (Octaves 1-6):**
|
||||
- Format: `C4`, `C4s` (sharp), `D4`, etc.
|
||||
- Range: `C1` ($80) through `B6` ($C7)
|
||||
- Special: `Tie` ($C8), `Rest` ($C9), `End` ($00)
|
||||
|
||||
### Expanded Bank Hooking
|
||||
|
||||
Oracle of Secrets expands music by hooking the `LoadOverworldSongs` routine:
|
||||
|
||||
```asm
|
||||
org $008919 ; LoadOverworldSongs
|
||||
JSL LoadOverworldSongsExpanded
|
||||
|
||||
LoadOverworldSongsExpanded:
|
||||
LDA.w $0FFF : BEQ .light_world
|
||||
; Load expanded bank for Dark World
|
||||
LDA.b #SongBank_OverworldExpanded_Main>>0
|
||||
STA.b $00
|
||||
; ... set bank pointer
|
||||
RTL
|
||||
.light_world
|
||||
; Load vanilla bank
|
||||
; ...
|
||||
```
|
||||
|
||||
**yaze Implementation Strategy:**
|
||||
1. Detect if ROM has expanded music patch applied
|
||||
2. Parse expanded song table at `SongBank_OverworldExpanded_Main`
|
||||
3. Allow editing both vanilla and expanded songs
|
||||
4. Generate proper ASM patches for new songs
|
||||
|
||||
### Proposed Advanced Macros
|
||||
|
||||
The Oracle of Secrets documentation proposes these macros for cleaner composition (not yet implemented there, but yaze could pioneer):
|
||||
|
||||
```asm
|
||||
; Define a reusable measure
|
||||
%DefineMeasure(VerseMelody, !8th, C4, D4, E4, F4, G4, A4, B4, C5)
|
||||
%DefineMeasure(VerseBass, !4th, C2, G2, A2, F2)
|
||||
|
||||
; Use in channel data
|
||||
.Channel0
|
||||
%PlayMeasure(VerseMelody, 4) ; Play 4 times
|
||||
db End
|
||||
|
||||
.Channel1
|
||||
%PlayMeasure(VerseBass, 4)
|
||||
db End
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Channel data reads like a high-level arrangement
|
||||
- Automatic subroutine address calculation
|
||||
- Reduced code duplication
|
||||
|
||||
---
|
||||
|
||||
## Technical Reference
|
||||
|
||||
### N-SPC Command Bytes
|
||||
|
||||
| Byte | Macro | Params | Description |
|
||||
|------|-------|--------|-------------|
|
||||
| $E0 | SetInstrument | 1 | Select instrument (0-24) |
|
||||
| $E1 | SetPan | 1 | Stereo pan (0-20, 10=center) |
|
||||
| $E2 | PanFade | 2 | Fade pan over time |
|
||||
| $E3 | VibratoOn | 3 | Enable pitch vibrato (delay, rate, depth) |
|
||||
| $E4 | VibratoOff | 0 | Disable vibrato |
|
||||
| $E5 | SetMasterVolume | 1 | Global volume |
|
||||
| $E6 | MasterVolumeFade | 2 | Fade master volume |
|
||||
| $E7 | SetTempo | 1 | Song tempo |
|
||||
| $E8 | TempoFade | 2 | Gradual tempo change |
|
||||
| $E9 | GlobalTranspose | 1 | Transpose all channels |
|
||||
| $EA | ChannelTranspose | 1 | Transpose single channel |
|
||||
| $EB | TremoloOn | 3 | Volume oscillation |
|
||||
| $EC | TremoloOff | 0 | Disable tremolo |
|
||||
| $ED | SetChannelVolume | 1 | Per-channel volume |
|
||||
| $EE | ChannelVolumeFade | 2 | Fade channel volume |
|
||||
| $EF | CallSubroutine | 3 | Call music subroutine (addr_lo, addr_hi, repeat) |
|
||||
| $F0 | VibratoFade | 1 | Fade vibrato depth |
|
||||
| $F1 | PitchEnvelopeTo | 3 | Pitch slide to note |
|
||||
| $F2 | PitchEnvelopeFrom | 3 | Pitch slide from note |
|
||||
| $F3 | PitchEnvelopeOff | 0 | Disable pitch envelope |
|
||||
| $F4 | Tuning | 1 | Fine pitch adjustment |
|
||||
| $F5 | EchoVBits | 3 | Echo enable + volumes |
|
||||
| $F6 | EchoOff | 0 | Disable echo |
|
||||
| $F7 | EchoParams | 3 | Echo delay/feedback/filter |
|
||||
| $F8 | EchoVolumeFade | 3 | Fade echo volumes |
|
||||
| $F9 | PitchSlide | 3 | Direct pitch slide |
|
||||
| $FA | PercussionPatchBass | 1 | Set percussion base instrument |
|
||||
|
||||
### ARAM Layout (Extended)
|
||||
|
||||
| Address | Contents |
|
||||
|---------|----------|
|
||||
| $0000-$00EF | Zero Page |
|
||||
| $00F0-$00FF | APU Registers |
|
||||
| $0100-$01FF | Stack |
|
||||
| $0200-$07FF | Sound driver code |
|
||||
| $0800-$17BF | SPC Engine (expanded) |
|
||||
| $17C0-$2AFF | SFX Data |
|
||||
| $2B00-$3BFF | Auxiliary song pointers |
|
||||
| $3C00-$3CFF | Sample pointers |
|
||||
| $3D00-$3DFF | Instrument definitions |
|
||||
| $3E00-$3FFF | SFX instrument data |
|
||||
| $4000-$CFFF | Sample data (~36KB) |
|
||||
| $D000-$FFBF | Song data (~12KB) |
|
||||
| $FFC0-$FFFF | IPL ROM |
|
||||
|
||||
### Instrument IDs (Extended)
|
||||
|
||||
| ID | Name | Notes |
|
||||
|----|------|-------|
|
||||
| $00 | Noise | White noise generator |
|
||||
| $01 | Rain | Rain/ambient |
|
||||
| $02 | Tympani | Timpani drums |
|
||||
| $03 | Square wave | 8-bit synth |
|
||||
| $04 | Saw wave | Sawtooth synth |
|
||||
| $05 | Sine wave | Pure tone |
|
||||
| $06 | Wobbly lead | Modulated synth |
|
||||
| $07 | Compound saw | Rich saw |
|
||||
| $08 | Tweet | Bird/high chirp |
|
||||
| $09 | Strings A | Orchestral strings |
|
||||
| $0A | Strings B | Alternate strings |
|
||||
| $0B | Trombone | Brass |
|
||||
| $0C | Cymbal | Crash/ride |
|
||||
| $0D | Ocarina | Wind instrument |
|
||||
| $0E | Chime | Bell/chime |
|
||||
| $0F | Harp | Plucked strings |
|
||||
| $10 | Splash | Water/impact |
|
||||
| $11 | Trumpet | Brass lead |
|
||||
| $12 | Horn | French horn |
|
||||
| $13 | Snare A | Snare drum |
|
||||
| $14 | Snare B | Alternate snare |
|
||||
| $15 | Choir | Vocal pad |
|
||||
| $16 | Flute | Wind melody |
|
||||
| $17 | Oof | Voice/grunt |
|
||||
| $18 | Piano | Keyboard |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### ASM Export Strategy
|
||||
|
||||
When exporting to `music_macros` format:
|
||||
|
||||
1. **Header Generation:**
|
||||
- Calculate `!ARAMAddr` based on target bank position
|
||||
- Generate intro/loop section pointers
|
||||
- Create channel pointer table with `!ARAMC` offsets
|
||||
|
||||
2. **Channel Data:**
|
||||
- Convert `TrackEvent` objects to macro calls
|
||||
- Use instrument helper macros where applicable
|
||||
- Apply duration optimization (only emit when changed)
|
||||
|
||||
3. **Subroutine Extraction:**
|
||||
- Detect repeated note patterns across channels
|
||||
- Extract to `.subXXX` labels
|
||||
- Replace inline data with `%CallSubroutine()` calls
|
||||
|
||||
4. **Naming Convention:**
|
||||
- Prefer semantic names: `.MelodyVerseA`, `.BasslineIntro`, `.PercussionFill1`
|
||||
- Fall back to numbered: `.sub001`, `.sub002` if semantic unclear
|
||||
|
||||
### Bank Space Management
|
||||
|
||||
**Constraints:**
|
||||
- Main bank: ~12KB at `$D000-$FFBF`
|
||||
- Echo buffer can consume song space if delay > 2
|
||||
- Subroutines shared across all songs in bank
|
||||
|
||||
**Overflow Handling:**
|
||||
1. Calculate total song size before save
|
||||
2. Warn user if approaching limit (>90% used)
|
||||
3. Suggest moving songs to auxiliary bank
|
||||
4. Auto-suggest subroutine deduplication
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [spannerisms ASM Music Guide](https://spannerisms.github.io/asmmusic)
|
||||
- [Oracle of Secrets GitHub](https://github.com/scawful/Oracle-of-Secrets)
|
||||
- [SNES APU Documentation](https://wiki.superfamicom.org/spc700-reference)
|
||||
- Oracle of Secrets `Core/music_macros.asm` (comprehensive macro library)
|
||||
- Oracle of Secrets `Music/expanded.asm` (bank expansion technique)
|
||||
- Hyrule Magic source code (tracker.cc)
|
||||
78
docs/internal/plans/oracle-yaze-integration.md
Normal file
78
docs/internal/plans/oracle-yaze-integration.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Oracle of Secrets & YAZE Integration Plan
|
||||
|
||||
## Overview
|
||||
This document outlines the roadmap for enhancing `yaze` to better support the `Oracle of Secrets` ROM hack development workflow, specifically focusing on Assembly editing, version control, and AI integration.
|
||||
|
||||
## 1. Enhanced Assembly Editor
|
||||
|
||||
### A. Symbol Navigation & Autocomplete
|
||||
* **Goal:** Enable "Go to Definition" and autocomplete for labels and constants.
|
||||
* **Implementation:**
|
||||
* Parse `asar` symbol files (e.g., `*.sym` or `*.symbols` generated via `--symbols=wla`).
|
||||
* Index labels, defines, and macros from the source code (`.asm` files).
|
||||
* Integrate with the editor's text view to provide clickable links or hover information.
|
||||
|
||||
### B. Error Highlighting
|
||||
* **Goal:** Map `asar` build errors directly to lines in the code editor.
|
||||
* **Implementation:**
|
||||
* Capture `stdout` and `stderr` from the `asar` build process.
|
||||
* Parse standard `asar` error formats (e.g., `error: (file.asm:123) ...`).
|
||||
* Visualize errors using squiggly lines or markers in the gutter.
|
||||
* Populate a "Problems" or "Build Output" panel with clickable error entries.
|
||||
|
||||
### C. Macro & Snippet Library
|
||||
* **Goal:** Speed up coding with common OOS/ASM patterns.
|
||||
* **Implementation:**
|
||||
* Add a snippet system to `AssemblyEditor`.
|
||||
* Include built-in snippets for:
|
||||
* `pushpc` / `pullpc` hooks.
|
||||
* `%Set_Sprite_Properties` macros.
|
||||
* Standard routine headers (preserve registers, `PHP`/`PLP`).
|
||||
* Allow user-defined snippets in `Oracle-of-Secrets.yaze` project settings.
|
||||
|
||||
## 2. Lightweight Version Management
|
||||
|
||||
### A. Snapshot Feature
|
||||
* **Goal:** Quick local commits without leaving the editor.
|
||||
* **Implementation:**
|
||||
* Add a "Snapshot" button to the main toolbar.
|
||||
* Command: `git add . && git commit -m "Snapshot: <Timestamp>"`
|
||||
* Display a success/failure notification.
|
||||
|
||||
### B. Diff View
|
||||
* **Goal:** See what changed since the last commit.
|
||||
* **Implementation:**
|
||||
* Add "Compare with HEAD" context menu option for files.
|
||||
* Render a side-by-side or inline diff using `git diff`.
|
||||
|
||||
## 3. AI-Driven Idea Management
|
||||
|
||||
### A. Context Injection
|
||||
* **Goal:** Keep the AI aligned with the current task.
|
||||
* **Implementation:**
|
||||
* Utilize `.gemini/yaze_agent_prompt.md` (already created).
|
||||
* Allow the agent to read `oracle.org` (ToDo list) to understand current priorities.
|
||||
|
||||
### B. Memory Map Awareness
|
||||
* **Goal:** Prevent memory conflicts.
|
||||
* **Implementation:**
|
||||
* Grant the agent specific tool access to query `Docs/Core/MemoryMap.md`.
|
||||
* Implement a "Check Free RAM" tool that parses the memory map.
|
||||
|
||||
## 4. Proposed Script Changes (Oracle of Secrets)
|
||||
|
||||
To support the features above, the `run.sh` script in `Oracle-of-Secrets` needs to be updated to generate symbols.
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
cp "Roms/oos168_test2.sfc" "Roms/oos91x.sfc"
|
||||
# Generate WLA symbols for yaze integration
|
||||
asar --symbols=wla Oracle_main.asm Roms/oos91x.sfc
|
||||
# Rename to .symbols if yaze expects that, or configure yaze to read .sym
|
||||
mv Roms/oos91x.sym Roms/oos91x.symbols
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
1. **Assembly Editor:** Begin implementing Error Highlighting (Parsers & UI).
|
||||
2. **Build System:** Update `run.sh` and test symbol generation.
|
||||
3. **UI:** Prototype the "Snapshot" button.
|
||||
355
docs/internal/plans/startup-ui-flow-refresh.md
Normal file
355
docs/internal/plans/startup-ui-flow-refresh.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# Startup UI Flow Refresh
|
||||
Status: IMPLEMENTED
|
||||
Owner: imgui-frontend-engineer
|
||||
Created: 2025-12-07
|
||||
Last Reviewed: 2025-12-06
|
||||
Implemented: 2025-12-06
|
||||
Board Link: [Coordination Board – 2025-12-05 imgui-frontend-engineer – Panel launch/log filtering UX](../agents/coordination-board.md)
|
||||
|
||||
## Implementation Summary (2025-12-06)
|
||||
|
||||
### Completed:
|
||||
1. **StartupSurface enum** (`ui_coordinator.h`) - Single source of truth for startup state: `kWelcome`, `kDashboard`, `kEditor`
|
||||
2. **Centralized visibility logic** (`ui_coordinator.cc`) - `ShouldShowWelcome()`, `ShouldShowDashboard()`, `ShouldShowActivityBar()` methods
|
||||
3. **Activity Bar hidden until ROM load** - Modified `EditorManager::Update()` and `LayoutCoordinator::GetLeftLayoutOffset()`
|
||||
4. **Category-specific expressive colors** (`panel_manager.cc`) - Each category has unique vibrant color (gold for Dungeon, green for Overworld, etc.)
|
||||
5. **Enhanced icon rendering** (`activity_bar.cc`) - 4px accent border, 30% glow background, outer glow shadow for active categories
|
||||
6. **Updated TransparentIconButton** (`themed_widgets.cc`) - Added `active_color` parameter for custom icon colors
|
||||
7. **Side panel starts collapsed** (`panel_manager.h`) - Changed `panel_expanded_` default to `false`
|
||||
8. **Dashboard dismisses on category selection** - Added `TriggerCategorySelected()` callback, wired to `SetStartupSurface(kEditor)`
|
||||
|
||||
### Key Files Modified:
|
||||
- `src/app/editor/ui/ui_coordinator.h` - Added `StartupSurface` enum and methods
|
||||
- `src/app/editor/ui/ui_coordinator.cc` - Centralized startup logic
|
||||
- `src/app/editor/menu/activity_bar.cc` - Expressive icon theming, category selection callback
|
||||
- `src/app/editor/system/panel_manager.h/cc` - Category theme colors, `on_category_selected_` callback
|
||||
- `src/app/gui/widgets/themed_widgets.h/cc` - Active color parameter
|
||||
- `src/app/editor/editor_manager.cc` - Activity Bar visibility gating, category selection handler
|
||||
- `src/app/editor/layout/layout_coordinator.cc` - Layout offset calculation
|
||||
|
||||
### Current Behavior:
|
||||
| State | Welcome | Dashboard | Activity Bar | Side Panel |
|
||||
|-------|---------|-----------|--------------|------------|
|
||||
| Cold start (no ROM) | Visible | Hidden | Hidden | Hidden |
|
||||
| ROM loaded | Hidden | Visible | Icons shown | Collapsed |
|
||||
| Category icon clicked | Hidden | Hidden | Icons (active glow) | Expanded |
|
||||
| Same icon clicked again | Hidden | Hidden | Icons | Collapsed (toggle) |
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
The current startup surface (Welcome, Dashboard, Activity Bar/Panel Sidebar, Status Bar) overlaps and produces inconsistent state: welcome + sidebar visible, dashboard sticking when opening editors, status bar obscured by the Activity Bar, and panels (emulator/memory/agent) registered before ROM load but not actually usable. This plan proposes a single source of truth for startup/state gates, VSCode-style welcome behavior (only when empty), and clear rules for sidebar/dashboard/status visibility—respecting user overrides and CLI-driven flows for agents/tests.
|
||||
|
||||
## Problems Observed
|
||||
- Welcome screen shows alongside Activity Bar/Panel tree, causing clutter; welcome sometimes “wins” focus and blocks panels opened via sidebar/presets.
|
||||
- Dashboard occasionally remains visible after switching editors/categories.
|
||||
- Status bar is covered by Activity Bar in some layouts.
|
||||
- Panels for emulator/memory/agent are registered and “visible” before ROM load but cannot open, creating confusion.
|
||||
- Startup flags/CLI (`--open_panels`, `--editor`) need to bypass stickiness to enable automation (e.g., MusicEditor for audio debugging).
|
||||
|
||||
## Goals
|
||||
- Single gatekeeper for startup surface; welcome only when no ROM/project and no explicit editor/panel request.
|
||||
- Deterministic sidebar/panel sidebar behavior on startup and editor switch; status bar always visible (no overlap).
|
||||
- Hide or defer unusable panels until prerequisites (ROM/project) are met; provide inline messaging when blocked.
|
||||
- Respect explicit user intent (CLI flags, last-session settings) over defaults.
|
||||
- Make flows testable and scriptable for AI agents/CLI.
|
||||
|
||||
## Proposed Behavior
|
||||
### Welcome Screen
|
||||
- Show only when **no ROM/project loaded** and **no explicit startup editor/panel flags**.
|
||||
- Auto-hide on first successful ROM/project load or when user explicitly opens an editor/category.
|
||||
- If a user/flag forces show (`--welcome` or pref), keep visible but collapse sidebars to reduce clutter.
|
||||
- When welcome is visible, panel/sidebar buttons should surface a toast “Load a ROM/project to open panels” instead of silently failing.
|
||||
|
||||
### Dashboard Panel
|
||||
- Dashboard is a lightweight chooser: show only when welcome is hidden **and** no editor is active.
|
||||
- Hide immediately when switching to an editor or when any panel/category is activated via Activity Bar.
|
||||
- On return to “no editor” state (e.g., close session with no ROM), re-show dashboard unless suppressed by CLI.
|
||||
|
||||
### Activity Bar & Panel Sidebar
|
||||
- Cold start (no ROM/project, no CLI intent): **no Activity Bar, no category panel/sidebar**, only the welcome screen.
|
||||
- On ROM load: show **icon-only Activity Bar** by default (no persisted expanded state, no category preselected). Dashboard remains until user picks a category.
|
||||
- No auto-selection of categories/panels. Selecting a category from the icon bar or dashboard activates that category, shows its defaults, dismisses dashboard/welcome. Pinned items remain cross-category.
|
||||
- User can reopen the dashboard from the Activity Bar (dashboard icon) to deselect the current category; category panels collapse when leaving the category.
|
||||
|
||||
### Status Bar
|
||||
- Always visible when app is running; compute offsets so Activity Bar/side panels never overlap it. If dockspace margin math is incorrect, fix via LayoutCoordinator offsets.
|
||||
|
||||
### Panel Availability & Prereqs
|
||||
- Panels with hard dependencies (ROM) advertise `IsEnabled()` and return a tooltip “Load a ROM to use this panel.” Activity Bar selection opens a toast and does not flip visibility flags until enabled.
|
||||
- On ROM load, auto-reenable last requested-but-blocked panels (e.g., emulator/memory) and focus them if they were in the request queue.
|
||||
|
||||
### CLI / Agent Overrides
|
||||
- Flags `--editor`, `--open_panels`, `--welcome`, `--dashboard`, `--sidebar` define initial intent; intent beats persisted settings.
|
||||
- If `--open_panels` includes panels needing ROM and ROM is absent, queue them and show a status toast; auto-open after load.
|
||||
- Provide a small “startup state” summary in logs for reproducibility (welcome? dashboard? sidebar? active editor? queued panels?).
|
||||
|
||||
## Implementation Steps (high level)
|
||||
1) **State owner**: Centralize startup/welcome/dashboard/sidebar decisions in UICoordinator + PanelManager callbacks; remove competing logic elsewhere. Emit a structured log of the chosen state on startup.
|
||||
2) **Welcome rules**: Gate welcome on “no ROM/project and no explicit intent”; collapse sidebars while welcome is shown; hide on any editor/panel activation or ROM/project load.
|
||||
3) **Dashboard rules**: Show only when welcome is hidden and no active editor; hide on category/editor switch; reopen when back to empty.
|
||||
4) **Sidebar/Activity Bar**: Apply CLI/user overrides once; default to hidden when welcome is active, shown otherwise; clicking categories hides welcome/dashboard and activates layout defaults.
|
||||
5) **Prereq-aware panels**: Implement `IsEnabled`/tooltip on emulator/memory/agent panels; queue panel requests until ROM loaded; on load, auto-show queued panels and focus first.
|
||||
6) **Status bar spacing**: Ensure LayoutCoordinator offsets account for Activity Bar + side panel width so status bar is never obscured.
|
||||
7) **Tests/telemetry**: Add a lightweight sanity check (e.g., headless mode) asserting startup state matrix for combinations of flags (welcome/dashboard/sidebar/editor/panels with/without ROM).
|
||||
|
||||
## Defaults (proposed)
|
||||
- First launch, no ROM: Welcome shown; no Activity Bar/sidebar; dashboard hidden.
|
||||
- After ROM load: Welcome hidden; Activity Bar icons shown; dashboard shown until a category is chosen; no category selected by default.
|
||||
- CLI `--editor music --open_panels=music.piano_roll`: Welcome/dashboard skipped, Activity Bar icons shown, Music defaults + piano roll visible; if ROM missing, queue + toast.
|
||||
|
||||
### Activity Bar affordances
|
||||
- Fix the collapse/expand icon inversion so the glyph reflects the actual state.
|
||||
- Standardize the sidebar toggle shortcut and audit related Window/shortcut-manager entries so labels match behavior; ensure consistency across menu, tooltip, and shortcut display.
|
||||
|
||||
## Additional UX Ideas (Future Work)
|
||||
|
||||
These enhancements would improve the startup experience further. Each includes implementation guidance for future agents.
|
||||
|
||||
---
|
||||
|
||||
### 1. Empty State Checklist on Welcome/Dashboard
|
||||
|
||||
**Goal**: Guide new users through initial setup with actionable steps.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/ui/welcome_screen.cc`
|
||||
- **Location**: Add to main content area, below recent projects section
|
||||
- **Components**:
|
||||
```cpp
|
||||
struct ChecklistItem {
|
||||
const char* icon;
|
||||
const char* label;
|
||||
const char* description;
|
||||
std::function<bool()> is_completed; // Returns true if step is done
|
||||
std::function<void()> on_click; // Action when clicked
|
||||
};
|
||||
```
|
||||
- **Items**:
|
||||
- "Load ROM" → `!rom_loaded` → `TriggerOpenRom()`
|
||||
- "Open Project" → `!project_loaded` → `TriggerOpenProject()`
|
||||
- "Pick an Editor" → `current_editor == nullptr` → `ShowDashboard()`
|
||||
- **Styling**: Use `AgentUI::GetTheme()` colors, checkmark icon when complete, muted when incomplete
|
||||
|
||||
---
|
||||
|
||||
### 2. Panel Request Queue (Auto-open after ROM load)
|
||||
|
||||
**Goal**: Remember blocked panel requests and auto-open them when prerequisites are met.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/system/panel_manager.h/cc`
|
||||
- **New members**:
|
||||
```cpp
|
||||
std::vector<std::string> queued_panel_requests_; // Panels awaiting ROM
|
||||
|
||||
void QueuePanelRequest(const std::string& panel_id);
|
||||
void ProcessQueuedPanels(); // Called when ROM loads
|
||||
```
|
||||
- **Wire up**: In `EditorManager`, after successful ROM load:
|
||||
```cpp
|
||||
panel_manager_.ProcessQueuedPanels();
|
||||
```
|
||||
- **Toast**: Use `ToastManager::Show("Panel will open when ROM loads", ToastType::kInfo)`
|
||||
- **Focus**: Auto-focus first queued panel via `ImGui::SetWindowFocus()`
|
||||
|
||||
---
|
||||
|
||||
### 3. Dashboard Quick-Picks
|
||||
|
||||
**Goal**: One-click access to recent work without navigating the sidebar.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/ui/dashboard_panel.cc`
|
||||
- **Location**: Add row above editor grid
|
||||
- **Components**:
|
||||
- "Open Last Editor" button → reads from `user_settings_.prefs().last_editor`
|
||||
- "Recent Files" dropdown → reads from `recent_projects.txt`
|
||||
- **Callback**: `SetQuickPickCallback(std::function<void(QuickPickType, std::string)>)`
|
||||
- **Styling**: Use `gui::PrimaryButton()` for emphasis, secondary buttons for recent files
|
||||
|
||||
---
|
||||
|
||||
### 4. Sidebar Toggle Tooltip with Shortcut
|
||||
|
||||
**Goal**: Show current action and keyboard shortcut in tooltip.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/menu/activity_bar.cc`
|
||||
- **Location**: Collapse/expand button tooltip (line ~232)
|
||||
- **Current**: `ImGui::SetTooltip("Collapse Panel");`
|
||||
- **Change to**:
|
||||
```cpp
|
||||
const char* action = panel_manager_.IsPanelExpanded() ? "Collapse" : "Expand";
|
||||
const char* shortcut = "Ctrl+B"; // or Cmd+B on macOS
|
||||
ImGui::SetTooltip("%s Panel (%s)", action, shortcut);
|
||||
```
|
||||
- **Platform detection**: Use `#ifdef __APPLE__` for Cmd vs Ctrl
|
||||
|
||||
---
|
||||
|
||||
### 5. Status Bar Chips (ROM Status, Agent Status)
|
||||
|
||||
**Goal**: Always-visible indicators for why features might be disabled.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/ui/status_bar.cc`
|
||||
- **New method**: `DrawStatusChips()`
|
||||
- **Chips**:
|
||||
```cpp
|
||||
struct StatusChip {
|
||||
const char* icon;
|
||||
const char* label;
|
||||
ImVec4 color; // From theme (success, warning, error)
|
||||
};
|
||||
|
||||
// ROM chip
|
||||
if (rom_ && rom_->is_loaded()) {
|
||||
DrawChip(ICON_MD_CHECK_CIRCLE, rom_->name(), theme.success);
|
||||
} else {
|
||||
DrawChip(ICON_MD_ERROR, "No ROM", theme.warning);
|
||||
}
|
||||
|
||||
// Agent chip (if YAZE_BUILD_AGENT_UI)
|
||||
DrawChip(agent_connected ? ICON_MD_CLOUD_DONE : ICON_MD_CLOUD_OFF,
|
||||
agent_connected ? "Agent Online" : "Agent Offline",
|
||||
agent_connected ? theme.success : theme.text_disabled);
|
||||
```
|
||||
- **Position**: Right side of status bar, before version info
|
||||
- **Interaction**: Click chip → opens relevant action (load ROM / agent settings)
|
||||
|
||||
---
|
||||
|
||||
### 6. Global Search on Welcome/Dashboard
|
||||
|
||||
**Goal**: Quick access to commands, panels, and recent files from a single input.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/ui/welcome_screen.cc` or new `global_search_widget.cc`
|
||||
- **Components**:
|
||||
```cpp
|
||||
class GlobalSearchWidget {
|
||||
char query_[256];
|
||||
std::vector<SearchResult> results_;
|
||||
|
||||
struct SearchResult {
|
||||
enum Type { kCommand, kPanel, kRecentFile, kEditor };
|
||||
Type type;
|
||||
std::string display_name;
|
||||
std::string icon;
|
||||
std::function<void()> on_select;
|
||||
};
|
||||
|
||||
void Search(const char* query);
|
||||
void Draw();
|
||||
};
|
||||
```
|
||||
- **Sources to search**:
|
||||
- `ShortcutManager::GetShortcuts()` → commands
|
||||
- `PanelManager::GetAllPanelDescriptors()` → panels
|
||||
- `RecentProjects` file → recent files
|
||||
- `EditorRegistry::GetAllEditorTypes()` → editors
|
||||
- **Behavior**: On select → hide welcome/dashboard, execute action
|
||||
- **Styling**: Centered search bar, dropdown results with fuzzy matching
|
||||
|
||||
---
|
||||
|
||||
### 7. Sticky Hint for Blocked Actions
|
||||
|
||||
**Goal**: Persistent reminder when actions are blocked, clearing when resolved.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/ui/toast_manager.h/cc`
|
||||
- **New toast type**: `ToastType::kStickyHint`
|
||||
- **Behavior**:
|
||||
- Doesn't auto-dismiss (no timeout)
|
||||
- Has explicit dismiss callback: `on_condition_met`
|
||||
- Displayed in status bar area (not floating)
|
||||
```cpp
|
||||
void ShowStickyHint(const std::string& message,
|
||||
std::function<bool()> dismiss_condition);
|
||||
|
||||
// Usage:
|
||||
toast_manager_.ShowStickyHint(
|
||||
"Load a ROM to enable this feature",
|
||||
[this]() { return rom_ && rom_->is_loaded(); });
|
||||
```
|
||||
- **Visual**: Muted background, dismissible X button, auto-clears when condition met
|
||||
- **Position**: Below main toolbar or in status bar notification area
|
||||
|
||||
---
|
||||
|
||||
### 8. Activity Bar Icon State Improvements
|
||||
|
||||
**Goal**: Better visual feedback for icon states.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/menu/activity_bar.cc`
|
||||
- **Enhancements**:
|
||||
- **Disabled state**: 50% opacity + lock icon overlay for ROM-gated categories
|
||||
- **Hover state**: Subtle background highlight even when inactive
|
||||
- **Badge support**: Small dot/number for notifications (e.g., "3 unsaved changes")
|
||||
```cpp
|
||||
// Badge drawing after icon button
|
||||
if (has_badge) {
|
||||
ImVec2 badge_pos = {cursor.x + 36, cursor.y + 4};
|
||||
DrawList->AddCircleFilled(badge_pos, 6.0f, badge_color);
|
||||
// Optional: draw count text
|
||||
}
|
||||
```
|
||||
- **Animation**: Consider subtle pulse for categories with pending actions
|
||||
|
||||
---
|
||||
|
||||
### 9. Collapse/Expand Icon Inversion Fix
|
||||
|
||||
**Goal**: Glyph should reflect the action, not the state.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/menu/activity_bar.cc` (line ~232)
|
||||
- **Current issue**: Icon shows "collapse" when collapsed
|
||||
- **Fix**:
|
||||
```cpp
|
||||
const char* icon = panel_manager_.IsPanelExpanded()
|
||||
? ICON_MD_KEYBOARD_DOUBLE_ARROW_LEFT // Collapse action
|
||||
: ICON_MD_KEYBOARD_DOUBLE_ARROW_RIGHT; // Expand action
|
||||
```
|
||||
- **Tooltip**: Should match: "Collapse Panel" vs "Expand Panel"
|
||||
|
||||
---
|
||||
|
||||
### 10. Startup State Logging for CLI/Testing
|
||||
|
||||
**Goal**: Emit structured log for reproducibility and debugging.
|
||||
|
||||
**Implementation**:
|
||||
- **File**: `src/app/editor/ui/ui_coordinator.cc`
|
||||
- **Location**: End of constructor or in `DrawWelcomeScreen()` first call
|
||||
- **Log format**:
|
||||
```cpp
|
||||
LOG_INFO("Startup", "State: surface=%s rom=%s welcome=%s dashboard=%s "
|
||||
"sidebar=%s panel_expanded=%s active_category=%s",
|
||||
GetStartupSurfaceName(current_startup_surface_),
|
||||
rom_loaded ? "loaded" : "none",
|
||||
ShouldShowWelcome() ? "visible" : "hidden",
|
||||
ShouldShowDashboard() ? "visible" : "hidden",
|
||||
ShouldShowActivityBar() ? "visible" : "hidden",
|
||||
panel_manager_.IsPanelExpanded() ? "expanded" : "collapsed",
|
||||
panel_manager_.GetActiveCategory().c_str());
|
||||
```
|
||||
- **CLI flag**: `--log-startup-state` to enable verbose startup logging
|
||||
|
||||
---
|
||||
|
||||
## Priority Order for Future Implementation
|
||||
|
||||
1. **Status Bar Chips** - High visibility, low complexity
|
||||
2. **Collapse/Expand Icon Fix** - Quick fix, improves UX
|
||||
3. **Sidebar Toggle Tooltip** - Quick enhancement
|
||||
4. **Panel Request Queue** - Medium complexity, high value
|
||||
5. **Dashboard Quick-Picks** - Medium complexity
|
||||
6. **Empty State Checklist** - Helps onboarding
|
||||
7. **Global Search** - High complexity, high value
|
||||
8. **Sticky Hints** - Medium complexity
|
||||
9. **Activity Bar Badges** - Nice polish
|
||||
10. **Startup State Logging** - Developer tooling
|
||||
127
docs/internal/plans/test_dashboard_refactor.md
Normal file
127
docs/internal/plans/test_dashboard_refactor.md
Normal file
@@ -0,0 +1,127 @@
|
||||
YAZE GUI Test Integration Refactoring Plan
|
||||
|
||||
Author: Gemini
|
||||
Date: 2025-10-11
|
||||
Status: Proposed
|
||||
|
||||
1. Introduction & Motivation
|
||||
|
||||
The yaze application includes a valuable feature for developers: an in-application "Test Dashboard" that allows for
|
||||
viewing and running various test suites directly within the GUI. However, the current implementation, located primarily
|
||||
in src/app/test/, is tightly coupled with both the main application and the command-line test executables.
|
||||
|
||||
This tight coupling has led to several architectural and practical problems:
|
||||
* Conditional Compilation Complexity: Excluding the test dashboard from release or CI/CD builds is difficult, as its code
|
||||
is intertwined with core application logic. This unnecessarily bloats release binaries with test code.
|
||||
* Circular Dependencies: The yaze_test_support library, which contains the TestManager, links against nearly all other
|
||||
application libraries (yaze_editor, yaze_gui, etc.). When the main application also links against yaze_test_support to
|
||||
display the dashboard, it creates a confusing and potentially circular dependency graph that complicates the build
|
||||
process.
|
||||
* Mixed Concerns: The current TestManager is responsible for both the core logic of running tests and the UI logic for
|
||||
displaying the dashboard. This violates the Single-Responsibility Principle and makes the code harder to maintain.
|
||||
|
||||
This document proposes a plan to refactor the test integration system into a modular, layered, and conditionally
|
||||
compiled architecture.
|
||||
|
||||
2. Goals
|
||||
|
||||
* Decouple Test Infrastructure: Separate the core test framework from the test suites and the GUI dashboard.
|
||||
* Create an Optional Test Dashboard: Make the in-app test dashboard a compile-time feature that can be easily enabled for
|
||||
development builds and disabled for release builds.
|
||||
* Eliminate Complex Dependencies: Remove the need for the main application to link against the entire suite of test
|
||||
implementations, simplifying the build graph.
|
||||
* Improve Maintainability: Create a clean and logical structure for the test system that is easier to understand and
|
||||
extend.
|
||||
|
||||
3. Proposed Architecture
|
||||
|
||||
The test system will be decomposed into three distinct libraries, clearly separating the framework, the UI, and the
|
||||
tests themselves.
|
||||
|
||||
1 +-----------------------------------------------------------------+
|
||||
2 | Main Application ("yaze") |
|
||||
3 | (Conditionally links against test_dashboard) |
|
||||
4 +-----------------------------------------------------------------+
|
||||
5 | ^
|
||||
6 | Optionally depends on |
|
||||
7 v |
|
||||
8 +-----------------+ +-----------------+ +-----------------+
|
||||
9 | test_dashboard | --> | test_framework | <-- | test_suites |
|
||||
10 | (GUI Component) | | (Core Logic) | | (Test Cases) |
|
||||
11 +-----------------+ +-----------------+ +-----------------+
|
||||
12 ^ ^
|
||||
13 | |
|
||||
14 |-------------------------------------------------|
|
||||
15 |
|
||||
16 v
|
||||
17 +-----------------------------------------------------------------+
|
||||
18 | Test Executables (yaze_test_stable, etc.) |
|
||||
19 | (Link against test_framework and test_suites) |
|
||||
20 +-----------------------------------------------------------------+
|
||||
|
||||
3.1. test_framework (New Core Library)
|
||||
* Location: src/test/framework/
|
||||
* Responsibility: Provides the core, non-GUI logic for managing and executing tests.
|
||||
* Contents:
|
||||
* TestManager (core logic only: RunTests, RegisterTestSuite, GetLastResults, etc.).
|
||||
* TestSuite base class and related structs (TestResult, TestResults, etc.).
|
||||
* Dependencies: yaze_util, absl. It will not depend on yaze_gui or any specific test suites.
|
||||
|
||||
3.2. test_suites (New Library)
|
||||
* Location: src/test/suites/
|
||||
* Responsibility: Contains all the actual test implementations.
|
||||
* Contents:
|
||||
* E2ETestSuite, EmulatorTestSuite, IntegratedTestSuite, RomDependentTestSuite, ZSCustomOverworldTestSuite,
|
||||
Z3edAIAgentTestSuite.
|
||||
* Dependencies: test_framework, and any yaze libraries required for testing (e.g., yaze_zelda3, yaze_gfx).
|
||||
|
||||
3.3. test_dashboard (New Conditional GUI Library)
|
||||
* Location: src/app/gui/testing/
|
||||
* Responsibility: Contains all ImGui code for the in-application test dashboard. This library will be conditionally
|
||||
compiled and linked.
|
||||
* Contents:
|
||||
* A new TestDashboard class containing the DrawTestDashboard method (migrated from TestManager).
|
||||
* UI-specific logic for displaying results, configuring tests, and interacting with the TestManager.
|
||||
* Dependencies: test_framework, yaze_gui.
|
||||
|
||||
4. Migration & Refactoring Plan
|
||||
|
||||
1. Create New Directory Structure:
|
||||
* Create src/test/framework/.
|
||||
* Create src/test/suites/.
|
||||
* Create src/app/gui/testing/.
|
||||
|
||||
2. Split `TestManager`:
|
||||
* Move test_manager.h and test_manager.cc to src/test/framework/.
|
||||
* Create a new TestDashboard class in src/app/gui/testing/test_dashboard.h/.cc.
|
||||
* Move the DrawTestDashboard method and all its UI-related helper functions from TestManager into the new
|
||||
TestDashboard class.
|
||||
* The TestDashboard will hold a reference to the TestManager singleton to access results and trigger test runs.
|
||||
|
||||
3. Relocate Test Suites:
|
||||
* Move all ..._test_suite.h files from src/app/test/ to the new src/test/suites/ directory.
|
||||
* Move z3ed_test_suite.cc to src/test/suites/.
|
||||
|
||||
4. Update CMake Configuration:
|
||||
* `src/test/framework/CMakeLists.txt`: Create this file to define the yaze_test_framework static library.
|
||||
* `src/test/suites/CMakeLists.txt`: Create this file to define the yaze_test_suites static library, linking it
|
||||
against yaze_test_framework and other necessary yaze libraries.
|
||||
* `src/app/gui/testing/CMakeLists.txt`: Create this file to define the yaze_test_dashboard static library.
|
||||
* Root `CMakeLists.txt`: Introduce a new option: option(YAZE_WITH_TEST_DASHBOARD "Build the in-application test
|
||||
dashboard" ON).
|
||||
* `src/app/app.cmake`: Modify the yaze executable's target_link_libraries to conditionally link yaze_test_dashboard
|
||||
based on the YAZE_WITH_TEST_DASHBOARD flag.
|
||||
* `test/CMakeLists.txt`: Update the test executables to link against yaze_test_framework and yaze_test_suites.
|
||||
* Remove `src/app/test/test.cmake`: The old yaze_test_support library will be completely replaced by this new
|
||||
structure.
|
||||
|
||||
5. Expected Outcomes
|
||||
|
||||
This plan will resolve the current architectural issues by:
|
||||
* Enabling Clean Builds: Release and CI builds can set YAZE_WITH_TEST_DASHBOARD=OFF, which will prevent the
|
||||
test_dashboard and test_suites libraries from being compiled or linked into the final yaze executable, resulting in a
|
||||
smaller, cleaner binary.
|
||||
* Simplifying Dependencies: The main application will no longer have a convoluted dependency on its own test suites. The
|
||||
dependency graph will be clear and acyclic.
|
||||
* Improving Developer Experience: Developers can enable the dashboard for convenient in-app testing, while the core test
|
||||
infrastructure remains robust and decoupled for command-line execution.
|
||||
66
docs/internal/plans/ui-infrastructure-proposals.md
Normal file
66
docs/internal/plans/ui-infrastructure-proposals.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# UI Infrastructure Technical Improvement Proposals
|
||||
|
||||
These proposals address the infrastructure changes needed to support the YAZE Design Language.
|
||||
|
||||
## Proposal A: Unified Panel System
|
||||
**Problem:** `PanelManager` currently has hardcoded logic for specific panels, making it hard for users to create custom layouts or for plugins to register new views.
|
||||
|
||||
**Solution:** Refactor `PanelManager` to use a Registry pattern.
|
||||
|
||||
```cpp
|
||||
// Concept
|
||||
struct PanelDef {
|
||||
std::string id;
|
||||
std::string display_name;
|
||||
std::function<void()> draw_fn;
|
||||
PanelCategory category; // Editor, Debug, Agent
|
||||
ImGuiDir default_dock; // Left, Bottom, Center
|
||||
};
|
||||
|
||||
PanelRegistry::Register("dungeon_properties", { ... });
|
||||
```
|
||||
|
||||
**Benefit:** Allows the `LayoutManager` to generically save/restore *any* panel's open state and position without hardcoded checks.
|
||||
|
||||
## Proposal B: Theme Abstraction Layer Refactor
|
||||
**Problem:** `src/app/gui/core/style.cc` contains `ColorsYaze()` with hardcoded definitions (e.g., `alttpDarkGreen`).
|
||||
|
||||
**Solution:**
|
||||
1. Deprecate `ColorsYaze`.
|
||||
2. Expand `EnhancedTheme` to include a "Game Palette" section (e.g., `GameCol_LinkGreen`, `GameCol_GanonBlue`).
|
||||
3. Update `ThemeManager` to populate these from configuration files (JSON/TOML), allowing users to "skin" the editor to look like different Zelda games (e.g., Minish Cap style).
|
||||
|
||||
## Proposal C: Layout Persistence Engine
|
||||
**Problem:** Layouts are currently stuck in `imgui.ini` (binary/opaque to user) or hardcoded presets.
|
||||
|
||||
**Solution:**
|
||||
1. Create a `LayoutService` that wraps `ImGui::SaveIniSettingsToMemory`.
|
||||
2. Allow users to "Save Current Layout As..." which writes the INI data to a named file in `user/layouts/`.
|
||||
3. Add a "Reset Layout" command that forces a reload of the default preset for the current context.
|
||||
|
||||
## Proposal D: Input Widget Standardization
|
||||
**Problem:** Scroll wheel support on Hex inputs is inconsistent.
|
||||
|
||||
**Solution:**
|
||||
Modify `src/app/gui/core/input.cc`:
|
||||
|
||||
```cpp
|
||||
bool InputHexByte(const char* label, uint8_t* v) {
|
||||
// ... existing input logic ...
|
||||
if (ImGui::IsItemHovered()) {
|
||||
float wheel = ImGui::GetIO().MouseWheel;
|
||||
if (wheel != 0) {
|
||||
if (wheel > 0) *v += 1; else *v -= 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
## Proposal E: State Management Audit
|
||||
**Problem:** `ActivityBar` and `StatusBar` often hold their own state or read global statics.
|
||||
|
||||
**Solution:**
|
||||
* **Context Injection:** UI components should receive a `EditorContext*` or `ProjectState*` in their `Draw()` method rather than accessing singletons.
|
||||
* **Reactive UI:** Implement a simple `EventBus` for UI updates (e.g., `Event::ProjectLoaded`, `Event::SelectionChanged`) so the Status Bar updates only when necessary, rather than polling every frame.
|
||||
@@ -1,56 +0,0 @@
|
||||
# UI Modernization & Architecture Plan
|
||||
|
||||
## Overview
|
||||
This document outlines the standard for UI development in `yaze`, focusing on the transition to a component-based architecture and full utilization of ImGui Docking.
|
||||
|
||||
## Core Architecture
|
||||
|
||||
### 1. The "Modern Editor" Standard
|
||||
New editors should follow the pattern established by `DungeonEditorV2`.
|
||||
|
||||
**Key Characteristics:**
|
||||
- **Component-Based**: The Editor class acts as a coordinator. Logic is delegated to specialized components (e.g., `RoomSelector`, `CanvasViewer`).
|
||||
- **Dependency Injection**: Use `EditorDependencies` struct for passing core systems (`Rom`, `EditorCardRegistry`, `Renderer`).
|
||||
- **ImGui Docking**: Use `ImGuiWindowClass` to group related windows (e.g., all Dungeon Editor tool windows dock together).
|
||||
- **No "Mega-Functions"**: Avoid massive `Draw()` methods. Each component handles its own drawing.
|
||||
|
||||
### 2. Window Management
|
||||
- **DockSpace**: The main application DockSpace is managed by `Controller` and `DockSpaceRenderer`.
|
||||
- **Editor Windows**: Editors should create their own top-level windows using `ImGui::Begin()` with appropriate flags.
|
||||
- **Card System**: Use `EditorCardRegistry` for auxiliary tool windows (e.g., "Room List", "Object Properties"). This allows users to toggle them via the "View" menu or Sidebar.
|
||||
|
||||
### 3. UI Coordinator
|
||||
`UICoordinator` is the central hub for application-level UI.
|
||||
- **Responsibilities**:
|
||||
- Drawing global UI (Command Palette, Welcome Screen, Dialogs).
|
||||
- Managing global popups.
|
||||
- coordinating focus between editors.
|
||||
- **Future Goal**: Move the main DockSpace creation from `Controller` to `UICoordinator` to centralize all UI logic.
|
||||
|
||||
## Immediate Improvements (Implemented)
|
||||
|
||||
### 1. Fix DockSpace Lifecycle
|
||||
`Controller::OnLoad` was missing the call to `DockSpaceRenderer::EndEnhancedDockSpace()`. This has been corrected to ensure proper cleanup and potential future post-processing effects.
|
||||
|
||||
### 2. Branch Organization
|
||||
Unstaged changes have been analyzed and a plan for organizing them into feature branches has been created (`docs/internal/plans/branch_organization.md`).
|
||||
|
||||
## Future Work
|
||||
|
||||
### 1. Centralize Main Window Logic
|
||||
Move the "DockSpaceWindow" creation from `Controller` to `UICoordinator::BeginFrame()`. This will allow `Controller` to remain agnostic of the specific UI implementation details.
|
||||
|
||||
### 2. Standardize Editor Flags
|
||||
Create a helper method `Editor::BeginWindow(const char* name, bool* p_open, ImGuiWindowFlags flags)` that automatically applies standard flags (like `ImGuiWindowFlags_UnsavedDocument` if dirty).
|
||||
|
||||
### 3. Visual Polish
|
||||
- **Background**: Enhance `DockSpaceRenderer` to support more dynamic backgrounds (currently supports grid/gradient).
|
||||
- **Theming**: Fully utilize `ThemeManager` for all new components. Avoid hardcoded colors.
|
||||
|
||||
## Migration Guide for Legacy Editors
|
||||
To convert a legacy editor (e.g., `GraphicsEditor`) to the new system:
|
||||
1. Identify distinct functional areas (e.g., "Tile Viewer", "Palette Selector").
|
||||
2. Extract these into separate classes/components.
|
||||
3. Update the main Editor class to initialize and update these components.
|
||||
4. Register the components as "Cards" in `EditorCardRegistry`.
|
||||
5. Remove the monolithic `Draw()` method.
|
||||
993
docs/internal/plans/ui_ux_improvement.md
Normal file
993
docs/internal/plans/ui_ux_improvement.md
Normal file
@@ -0,0 +1,993 @@
|
||||
# UI/UX Improvement Plan: IDE-like Interface
|
||||
|
||||
> Terminology update: ongoing refactor renames Card → Panel. References to
|
||||
> `CardInfo`/`EditorCardRegistry` should be read as
|
||||
> `PanelDescriptor`/`PanelManager` going forward.
|
||||
|
||||
**Created**: 2025-01-25
|
||||
**Status**: Design Phase
|
||||
**Priority**: High
|
||||
**Target**: Make yaze feel like VSCode/JetBrains IDEs
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document outlines comprehensive UI/UX improvements to transform yaze into a professional, IDE-like application with consistent theming, responsive layouts, proper disabled states, and Material Design principles throughout.
|
||||
|
||||
**Key Improvements**:
|
||||
1. Enhanced sidebar system with responsive sizing, badges, and disabled states
|
||||
2. Improved menu bar with proper precondition checks and consistent spacing
|
||||
3. Responsive panel system that adapts to window size
|
||||
4. Extended AgentUITheme for application-wide consistency
|
||||
5. Status cluster enhancements for better visual feedback
|
||||
|
||||
---
|
||||
|
||||
## 1. Sidebar System Improvements
|
||||
|
||||
### Current Issues
|
||||
- No visual feedback for disabled cards (when ROM not loaded)
|
||||
- Fixed sizing doesn't respond to window height changes
|
||||
- No badge indicators for notifications/counts
|
||||
- Hover effects are basic (only tooltip)
|
||||
- Missing selection state visual feedback
|
||||
- No category headers/separators for large card lists
|
||||
|
||||
### Proposed Solutions
|
||||
|
||||
#### 1.1 Disabled State System
|
||||
|
||||
**File**: `src/app/editor/system/editor_card_registry.h`
|
||||
|
||||
```cpp
|
||||
struct CardInfo {
|
||||
// ... existing fields ...
|
||||
std::function<bool()> enabled_condition; // NEW: Card enable condition
|
||||
int notification_count = 0; // NEW: Badge count (0 = no badge)
|
||||
};
|
||||
```
|
||||
|
||||
**File**: `src/app/editor/system/editor_card_registry.cc` (DrawSidebar)
|
||||
|
||||
```cpp
|
||||
// In the card drawing loop:
|
||||
bool is_active = card.visibility_flag && *card.visibility_flag;
|
||||
bool is_enabled = card.enabled_condition ? card.enabled_condition() : true;
|
||||
|
||||
if (!is_enabled) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.4f); // Dim disabled cards
|
||||
}
|
||||
|
||||
// ... draw button ...
|
||||
|
||||
if (!is_enabled) {
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (!is_enabled) {
|
||||
ImGui::SetTooltip("%s\nRequires ROM to be loaded", card.display_name.c_str());
|
||||
} else {
|
||||
// Normal tooltip
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 Notification Badges
|
||||
|
||||
**New Helper Function**: `src/app/editor/system/editor_card_registry.cc`
|
||||
|
||||
```cpp
|
||||
void EditorCardRegistry::DrawCardWithBadge(const CardInfo& card, bool is_active) {
|
||||
const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
|
||||
|
||||
// Draw the main button
|
||||
// ... existing button code ...
|
||||
|
||||
// Draw notification badge if count > 0
|
||||
if (card.notification_count > 0) {
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 button_max = ImGui::GetItemRectMax();
|
||||
|
||||
// Badge position (top-right corner of button)
|
||||
float badge_radius = 8.0f;
|
||||
ImVec2 badge_pos(button_max.x - badge_radius, button_max.y - 32.0f + badge_radius);
|
||||
|
||||
// Draw badge circle
|
||||
ImVec4 error_color = gui::ConvertColorToImVec4(theme.error);
|
||||
draw_list->AddCircleFilled(badge_pos, badge_radius, ImGui::GetColorU32(error_color));
|
||||
|
||||
// Draw count text
|
||||
if (card.notification_count < 100) {
|
||||
char badge_text[4];
|
||||
snprintf(badge_text, sizeof(badge_text), "%d", card.notification_count);
|
||||
|
||||
ImVec2 text_size = ImGui::CalcTextSize(badge_text);
|
||||
ImVec2 text_pos(badge_pos.x - text_size.x * 0.5f,
|
||||
badge_pos.y - text_size.y * 0.5f);
|
||||
|
||||
draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 255), badge_text);
|
||||
} else {
|
||||
draw_list->AddText(
|
||||
ImVec2(badge_pos.x - 6, badge_pos.y - 6),
|
||||
IM_COL32(255, 255, 255, 255), "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.3 Enhanced Hover Effects
|
||||
|
||||
**Style Improvements**:
|
||||
|
||||
```cpp
|
||||
// In DrawSidebar, replace existing button style:
|
||||
if (is_active) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button,
|
||||
ImVec4(accent_color.x, accent_color.y, accent_color.z, 0.6f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
ImVec4(accent_color.x, accent_color.y, accent_color.z, 0.8f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, accent_color);
|
||||
|
||||
// Add glow effect
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, button_bg);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
ImVec4(accent_color.x, accent_color.y, accent_color.z, 0.3f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
|
||||
gui::ConvertColorToImVec4(theme.button_active));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.4 Responsive Sizing
|
||||
|
||||
**Current code calculates fixed heights**. Improve with dynamic calculations:
|
||||
|
||||
```cpp
|
||||
// Replace fixed utility_section_height calculation:
|
||||
const float utility_section_height = 4 * 40.0f + 80.0f;
|
||||
|
||||
// With dynamic calculation:
|
||||
const float button_height = 40.0f * theme.widget_height_multiplier;
|
||||
const float spacing = ImGui::GetStyle().ItemSpacing.y;
|
||||
const float utility_button_count = 4;
|
||||
const float utility_section_height =
|
||||
(utility_button_count * (button_height + spacing)) +
|
||||
80.0f * theme.panel_padding_multiplier;
|
||||
|
||||
const float current_y = ImGui::GetCursorPosY();
|
||||
const float available_height = viewport_height - current_y - utility_section_height;
|
||||
```
|
||||
|
||||
#### 1.5 Category Headers/Separators
|
||||
|
||||
**For editors with many cards**, add collapsible sections:
|
||||
|
||||
```cpp
|
||||
void EditorCardRegistry::DrawSidebarWithSections(
|
||||
size_t session_id,
|
||||
const std::string& category,
|
||||
const std::map<std::string, std::vector<CardInfo>>& card_sections) {
|
||||
|
||||
for (const auto& [section_name, cards] : card_sections) {
|
||||
if (ImGui::CollapsingHeader(section_name.c_str(),
|
||||
ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
for (const auto& card : cards) {
|
||||
DrawCardWithBadge(card, /* is_active */ ...);
|
||||
}
|
||||
}
|
||||
ImGui::Spacing();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Menu Bar System Improvements
|
||||
|
||||
### Current Issues
|
||||
- Many menu items don't gray out when preconditions not met
|
||||
- Inconsistent spacing/padding between menu items
|
||||
- Status cluster feels cramped
|
||||
- No visual separation between menu groups
|
||||
|
||||
### Proposed Solutions
|
||||
|
||||
#### 2.1 Comprehensive Enabled Conditions
|
||||
|
||||
**File**: `src/app/editor/system/menu_orchestrator.cc`
|
||||
|
||||
Add helper methods:
|
||||
|
||||
```cpp
|
||||
// Existing helpers (keep these):
|
||||
bool MenuOrchestrator::HasActiveRom() const;
|
||||
bool MenuOrchestrator::CanSaveRom() const;
|
||||
bool MenuOrchestrator::HasCurrentEditor() const;
|
||||
bool MenuOrchestrator::HasMultipleSessions() const;
|
||||
|
||||
// NEW helpers:
|
||||
bool MenuOrchestrator::HasActiveSelection() const {
|
||||
// Check if current editor has selected entities/objects
|
||||
// Delegate to EditorManager to query active editor
|
||||
}
|
||||
|
||||
bool MenuOrchestrator::CanUndo() const {
|
||||
// Check if undo stack has entries
|
||||
return HasCurrentEditor() && editor_manager_->CanUndo();
|
||||
}
|
||||
|
||||
bool MenuOrchestrator::CanRedo() const {
|
||||
return HasCurrentEditor() && editor_manager_->CanRedo();
|
||||
}
|
||||
|
||||
bool MenuOrchestrator::HasClipboardData() const {
|
||||
// Check if clipboard has paste-able data
|
||||
return HasCurrentEditor() && editor_manager_->HasClipboardData();
|
||||
}
|
||||
|
||||
bool MenuOrchestrator::IsRomModified() const {
|
||||
return HasActiveRom() && rom_manager_.GetCurrentRom()->dirty();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 Apply Conditions to All Menu Items
|
||||
|
||||
**File**: `src/app/editor/system/menu_orchestrator.cc`
|
||||
|
||||
```cpp
|
||||
void MenuOrchestrator::BuildFileMenu() {
|
||||
menu_builder_.BeginMenu("File", ICON_MD_FOLDER);
|
||||
|
||||
menu_builder_.Item(
|
||||
"Open ROM", ICON_MD_FILE_OPEN,
|
||||
[this]() { OnOpenRom(); },
|
||||
"Ctrl+O",
|
||||
[]() { return true; } // Always enabled
|
||||
);
|
||||
|
||||
menu_builder_.Item(
|
||||
"Save ROM", ICON_MD_SAVE,
|
||||
[this]() { OnSaveRom(); },
|
||||
"Ctrl+S",
|
||||
[this]() { return CanSaveRom(); } // EXISTING
|
||||
);
|
||||
|
||||
menu_builder_.Item(
|
||||
"Save ROM As...", ICON_MD_SAVE_AS,
|
||||
[this]() { OnSaveRomAs(); },
|
||||
"Ctrl+Shift+S",
|
||||
[this]() { return HasActiveRom(); } // NEW
|
||||
);
|
||||
|
||||
menu_builder_.Separator();
|
||||
|
||||
menu_builder_.Item(
|
||||
"Create Project", ICON_MD_CREATE_NEW_FOLDER,
|
||||
[this]() { OnCreateProject(); },
|
||||
"Ctrl+Shift+N",
|
||||
[this]() { return HasActiveRom(); } // NEW - requires ROM first
|
||||
);
|
||||
|
||||
// ... continue for all items
|
||||
|
||||
menu_builder_.EndMenu();
|
||||
}
|
||||
|
||||
void MenuOrchestrator::BuildEditMenu() {
|
||||
menu_builder_.BeginMenu("Edit", ICON_MD_EDIT);
|
||||
|
||||
menu_builder_.Item(
|
||||
"Undo", ICON_MD_UNDO,
|
||||
[this]() { OnUndo(); },
|
||||
"Ctrl+Z",
|
||||
[this]() { return CanUndo(); } // NEW
|
||||
);
|
||||
|
||||
menu_builder_.Item(
|
||||
"Redo", ICON_MD_REDO,
|
||||
[this]() { OnRedo(); },
|
||||
"Ctrl+Y",
|
||||
[this]() { return CanRedo(); } // NEW
|
||||
);
|
||||
|
||||
menu_builder_.Separator();
|
||||
|
||||
menu_builder_.Item(
|
||||
"Cut", ICON_MD_CONTENT_CUT,
|
||||
[this]() { OnCut(); },
|
||||
"Ctrl+X",
|
||||
[this]() { return HasActiveSelection(); } // NEW
|
||||
);
|
||||
|
||||
menu_builder_.Item(
|
||||
"Copy", ICON_MD_CONTENT_COPY,
|
||||
[this]() { OnCopy(); },
|
||||
"Ctrl+C",
|
||||
[this]() { return HasActiveSelection(); } // NEW
|
||||
);
|
||||
|
||||
menu_builder_.Item(
|
||||
"Paste", ICON_MD_CONTENT_PASTE,
|
||||
[this]() { OnPaste(); },
|
||||
"Ctrl+V",
|
||||
[this]() { return HasClipboardData(); } // NEW
|
||||
);
|
||||
|
||||
menu_builder_.EndMenu();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 Menu Spacing and Visual Grouping
|
||||
|
||||
**File**: `src/app/editor/ui/menu_builder.h`
|
||||
|
||||
Add spacing control methods:
|
||||
|
||||
```cpp
|
||||
class MenuBuilder {
|
||||
public:
|
||||
// ... existing methods ...
|
||||
|
||||
// NEW: Visual spacing
|
||||
void SeparatorWithSpacing(float height = 4.0f) {
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Dummy(ImVec2(0, height));
|
||||
}
|
||||
|
||||
// NEW: Menu section header (for long menus)
|
||||
void SectionHeader(const char* label) {
|
||||
const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||
gui::ConvertColorToImVec4(theme.text_disabled));
|
||||
ImGui::TextUnformatted(label);
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Spacing();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
|
||||
```cpp
|
||||
void MenuOrchestrator::BuildToolsMenu() {
|
||||
menu_builder_.BeginMenu("Tools", ICON_MD_BUILD);
|
||||
|
||||
menu_builder_.SectionHeader("ROM Analysis");
|
||||
menu_builder_.Item("ROM Info", ICON_MD_INFO, ...);
|
||||
menu_builder_.Item("Validate ROM", ICON_MD_CHECK_CIRCLE, ...);
|
||||
|
||||
menu_builder_.SeparatorWithSpacing();
|
||||
|
||||
menu_builder_.SectionHeader("Utilities");
|
||||
menu_builder_.Item("Global Search", ICON_MD_SEARCH, ...);
|
||||
menu_builder_.Item("Command Palette", ICON_MD_TERMINAL, ...);
|
||||
|
||||
menu_builder_.EndMenu();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4 Status Cluster Improvements
|
||||
|
||||
**File**: `src/app/editor/ui/ui_coordinator.cc`
|
||||
|
||||
```cpp
|
||||
void UICoordinator::DrawMenuBarExtras() {
|
||||
const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
|
||||
|
||||
// Calculate cluster width dynamically
|
||||
float cluster_width = 0.0f;
|
||||
cluster_width += 30.0f; // Dirty badge
|
||||
cluster_width += 30.0f; // Notification bell
|
||||
if (session_coordinator_.HasMultipleSessions()) {
|
||||
cluster_width += 80.0f; // Session button with name
|
||||
}
|
||||
cluster_width += 60.0f; // Version
|
||||
cluster_width += 20.0f; // Padding
|
||||
|
||||
// Right-align with proper spacing
|
||||
ImGui::SameLine(ImGui::GetWindowWidth() - cluster_width);
|
||||
|
||||
// Add subtle separator before status cluster
|
||||
ImGui::PushStyleColor(ImGuiCol_Separator,
|
||||
gui::ConvertColorToImVec4(theme.border));
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(8.0f, 0)); // Spacing
|
||||
ImGui::SameLine();
|
||||
|
||||
// 1. Dirty badge (with animation)
|
||||
Rom* current_rom = rom_manager_.GetCurrentRom();
|
||||
if (current_rom && current_rom->dirty()) {
|
||||
DrawDirtyBadge();
|
||||
}
|
||||
|
||||
// 2. Notification bell
|
||||
DrawNotificationBell();
|
||||
|
||||
// 3. Session button (if multiple)
|
||||
if (session_coordinator_.HasMultipleSessions()) {
|
||||
DrawSessionButton();
|
||||
}
|
||||
|
||||
// 4. Version
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||
gui::ConvertColorToImVec4(theme.text_disabled));
|
||||
ImGui::TextUnformatted(ICON_MD_INFO " v0.1.0");
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
void UICoordinator::DrawDirtyBadge() {
|
||||
const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
|
||||
|
||||
// Pulsing animation
|
||||
static float pulse_time = 0.0f;
|
||||
pulse_time += ImGui::GetIO().DeltaTime;
|
||||
float pulse_alpha = 0.7f + 0.3f * sin(pulse_time * 3.0f);
|
||||
|
||||
ImVec4 warning_color = gui::ConvertColorToImVec4(theme.warning);
|
||||
warning_color.w = pulse_alpha;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
ImVec4(warning_color.x, warning_color.y, warning_color.z, 0.3f));
|
||||
|
||||
if (ImGui::SmallButton(ICON_MD_CIRCLE)) {
|
||||
// Quick save on click
|
||||
OnSaveRom();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Unsaved changes\nClick to save (Ctrl+S)");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. AgentUITheme Extensions
|
||||
|
||||
### New Theme Properties Needed
|
||||
|
||||
**File**: `src/app/editor/agent/agent_ui_theme.h`
|
||||
|
||||
```cpp
|
||||
struct AgentUITheme {
|
||||
// ... existing fields ...
|
||||
|
||||
// NEW: Sidebar specific colors
|
||||
ImVec4 sidebar_bg;
|
||||
ImVec4 sidebar_border;
|
||||
ImVec4 sidebar_icon_active;
|
||||
ImVec4 sidebar_icon_inactive;
|
||||
ImVec4 sidebar_icon_disabled;
|
||||
ImVec4 sidebar_icon_hover;
|
||||
ImVec4 sidebar_badge_bg;
|
||||
ImVec4 sidebar_badge_text;
|
||||
|
||||
// NEW: Menu bar specific colors
|
||||
ImVec4 menu_separator;
|
||||
ImVec4 menu_section_header;
|
||||
ImVec4 menu_item_disabled;
|
||||
|
||||
// NEW: Panel sizing (responsive)
|
||||
float sidebar_width_base = 48.0f;
|
||||
float sidebar_icon_size = 40.0f;
|
||||
float sidebar_icon_spacing = 6.0f;
|
||||
float panel_padding = 8.0f;
|
||||
float status_cluster_spacing = 8.0f;
|
||||
|
||||
// NEW: Animation timing
|
||||
float hover_transition_speed = 0.15f;
|
||||
float badge_pulse_speed = 3.0f;
|
||||
|
||||
static AgentUITheme FromCurrentTheme();
|
||||
};
|
||||
```
|
||||
|
||||
**File**: `src/app/editor/agent/agent_ui_theme.cc`
|
||||
|
||||
```cpp
|
||||
AgentUITheme AgentUITheme::FromCurrentTheme() {
|
||||
AgentUITheme theme;
|
||||
const auto& current = gui::ThemeManager::Get().GetCurrentTheme();
|
||||
|
||||
// ... existing code ...
|
||||
|
||||
// NEW: Sidebar colors
|
||||
theme.sidebar_bg = ConvertColorToImVec4(current.surface);
|
||||
theme.sidebar_border = ConvertColorToImVec4(current.border);
|
||||
theme.sidebar_icon_active = ConvertColorToImVec4(current.accent);
|
||||
theme.sidebar_icon_inactive = ConvertColorToImVec4(current.button);
|
||||
theme.sidebar_icon_disabled = ImVec4(0.3f, 0.3f, 0.3f, 1.0f);
|
||||
theme.sidebar_icon_hover = ConvertColorToImVec4(current.button_hovered);
|
||||
theme.sidebar_badge_bg = ConvertColorToImVec4(current.error);
|
||||
theme.sidebar_badge_text = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
// NEW: Menu bar colors
|
||||
theme.menu_separator = ConvertColorToImVec4(current.border);
|
||||
theme.menu_section_header = ConvertColorToImVec4(current.text_disabled);
|
||||
theme.menu_item_disabled = ImVec4(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
|
||||
// NEW: Responsive sizing from theme
|
||||
theme.sidebar_width_base = 48.0f * current.compact_factor;
|
||||
theme.sidebar_icon_size = 40.0f * current.widget_height_multiplier;
|
||||
theme.sidebar_icon_spacing = 6.0f * current.spacing_multiplier;
|
||||
theme.panel_padding = 8.0f * current.panel_padding_multiplier;
|
||||
|
||||
return theme;
|
||||
}
|
||||
```
|
||||
|
||||
### Helper Functions
|
||||
|
||||
**File**: `src/app/editor/agent/agent_ui_theme.h`
|
||||
|
||||
```cpp
|
||||
namespace AgentUI {
|
||||
|
||||
// ... existing helpers ...
|
||||
|
||||
// NEW: Sidebar helpers
|
||||
void PushSidebarStyle();
|
||||
void PopSidebarStyle();
|
||||
|
||||
void RenderSidebarButton(const char* icon, bool is_active, bool is_enabled,
|
||||
int notification_count = 0);
|
||||
|
||||
// NEW: Menu helpers
|
||||
void PushMenuSectionStyle();
|
||||
void PopMenuSectionStyle();
|
||||
|
||||
// NEW: Status cluster helpers
|
||||
void RenderDirtyIndicator(bool dirty);
|
||||
void RenderNotificationBadge(int count);
|
||||
void RenderSessionIndicator(const char* session_name, bool is_active);
|
||||
|
||||
} // namespace AgentUI
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Right Panel System Integration
|
||||
|
||||
### Current State
|
||||
- `RightPanelManager` exists and handles agent chat, proposals, settings, help
|
||||
- Uses fixed widths per panel type
|
||||
- No animation (animating_ flag exists but unused)
|
||||
- Good theme integration already
|
||||
|
||||
### Improvements Needed
|
||||
|
||||
#### 4.1 Slide Animation
|
||||
|
||||
**File**: `src/app/editor/ui/right_panel_manager.cc`
|
||||
|
||||
```cpp
|
||||
void RightPanelManager::Draw() {
|
||||
if (active_panel_ == PanelType::kNone && panel_animation_ <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
const float viewport_height = viewport->WorkSize.y;
|
||||
const float viewport_width = viewport->WorkSize.x;
|
||||
|
||||
// Animate panel expansion/collapse
|
||||
if (animating_) {
|
||||
const float animation_speed = 6.0f * ImGui::GetIO().DeltaTime;
|
||||
|
||||
if (active_panel_ != PanelType::kNone) {
|
||||
// Expanding
|
||||
panel_animation_ = std::min(1.0f, panel_animation_ + animation_speed);
|
||||
if (panel_animation_ >= 1.0f) {
|
||||
animating_ = false;
|
||||
}
|
||||
} else {
|
||||
// Collapsing
|
||||
panel_animation_ = std::max(0.0f, panel_animation_ - animation_speed);
|
||||
if (panel_animation_ <= 0.0f) {
|
||||
animating_ = false;
|
||||
return; // Fully collapsed, don't draw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eased animation curve (smooth in/out)
|
||||
float eased_progress = panel_animation_ * panel_animation_ * (3.0f - 2.0f * panel_animation_);
|
||||
|
||||
const float target_width = GetPanelWidth();
|
||||
const float current_width = target_width * eased_progress;
|
||||
|
||||
// ... rest of drawing code, use current_width instead of GetPanelWidth()
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2 Responsive Width Calculation
|
||||
|
||||
```cpp
|
||||
float RightPanelManager::GetPanelWidth() const {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
const float viewport_width = viewport->WorkSize.x;
|
||||
|
||||
// Calculate max panel width (30% of viewport, clamped)
|
||||
const float max_panel_width = std::min(600.0f, viewport_width * 0.3f);
|
||||
|
||||
float base_width = 0.0f;
|
||||
switch (active_panel_) {
|
||||
case PanelType::kAgentChat:
|
||||
base_width = agent_chat_width_;
|
||||
break;
|
||||
case PanelType::kProposals:
|
||||
base_width = proposals_width_;
|
||||
break;
|
||||
case PanelType::kSettings:
|
||||
base_width = settings_width_;
|
||||
break;
|
||||
case PanelType::kHelp:
|
||||
base_width = help_width_;
|
||||
break;
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return std::min(base_width, max_panel_width);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.3 Docking Space Adjustment
|
||||
|
||||
**File**: `src/app/editor/editor_manager.cc`
|
||||
|
||||
When drawing the main docking space, reserve space for the right panel:
|
||||
|
||||
```cpp
|
||||
void EditorManager::UpdateMainDockingSpace() {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
|
||||
float sidebar_width = 0.0f;
|
||||
if (ui_coordinator_->IsCardSidebarVisible() &&
|
||||
!card_registry_.IsSidebarCollapsed()) {
|
||||
sidebar_width = EditorCardRegistry::GetSidebarWidth();
|
||||
}
|
||||
|
||||
// NEW: Reserve space for right panel
|
||||
float right_panel_width = right_panel_manager_->GetPanelWidth();
|
||||
if (right_panel_manager_->IsPanelExpanded()) {
|
||||
right_panel_width *= right_panel_manager_->GetAnimationProgress();
|
||||
}
|
||||
|
||||
// Docking space occupies the remaining space
|
||||
ImVec2 dockspace_pos(viewport->WorkPos.x + sidebar_width, viewport->WorkPos.y);
|
||||
ImVec2 dockspace_size(
|
||||
viewport->WorkSize.x - sidebar_width - right_panel_width,
|
||||
viewport->WorkSize.y
|
||||
);
|
||||
|
||||
ImGui::SetNextWindowPos(dockspace_pos);
|
||||
ImGui::SetNextWindowSize(dockspace_size);
|
||||
|
||||
// ... rest of docking space setup
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Overall Layout System
|
||||
|
||||
### 5.1 Layout Zones
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────────┐
|
||||
│ Menu Bar (Full Width) [●][🔔][📄][v]│
|
||||
├─┬─────────────────────────────────────────────────────────┬───┤
|
||||
│S│ │ R │
|
||||
│i│ │ i │
|
||||
│d│ Main Docking Space │ g │
|
||||
│e│ │ h │
|
||||
│b│ (Editor Cards) │ t │
|
||||
│a│ │ │
|
||||
│r│ │ P │
|
||||
│ │ │ a │
|
||||
│ │ │ n │
|
||||
│ │ │ e │
|
||||
│ │ │ l │
|
||||
│ │ │ │
|
||||
└─┴─────────────────────────────────────────────────────────┴───┘
|
||||
```
|
||||
|
||||
### 5.2 Responsive Breakpoints
|
||||
|
||||
**Add to EditorManager or new LayoutManager class**:
|
||||
|
||||
```cpp
|
||||
enum class LayoutMode {
|
||||
kCompact, // < 1280px width
|
||||
kNormal, // 1280-1920px
|
||||
kWide // > 1920px
|
||||
};
|
||||
|
||||
LayoutMode GetLayoutMode() const {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
float width = viewport->WorkSize.x;
|
||||
|
||||
if (width < 1280.0f) return LayoutMode::kCompact;
|
||||
if (width < 1920.0f) return LayoutMode::kNormal;
|
||||
return LayoutMode::kWide;
|
||||
}
|
||||
|
||||
// Adjust UI based on mode:
|
||||
void ApplyLayoutMode(LayoutMode mode) {
|
||||
switch (mode) {
|
||||
case LayoutMode::kCompact:
|
||||
// Auto-collapse sidebar on small screens?
|
||||
// Reduce panel widths
|
||||
right_panel_manager_->SetPanelWidth(PanelType::kAgentChat, 300.0f);
|
||||
break;
|
||||
case LayoutMode::kNormal:
|
||||
right_panel_manager_->SetPanelWidth(PanelType::kAgentChat, 380.0f);
|
||||
break;
|
||||
case LayoutMode::kWide:
|
||||
right_panel_manager_->SetPanelWidth(PanelType::kAgentChat, 480.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Implementation Priority Order
|
||||
|
||||
### Phase 1: Critical Foundation (Week 1)
|
||||
**Priority: P0 - Immediate**
|
||||
|
||||
1. **Extend AgentUITheme** with sidebar/menu colors and sizing
|
||||
- Files: `agent_ui_theme.h`, `agent_ui_theme.cc`
|
||||
- Effort: 2 hours
|
||||
- Benefit: Foundation for all other improvements
|
||||
|
||||
2. **Add CardInfo enabled_condition field**
|
||||
- Files: `editor_card_registry.h`, `editor_card_registry.cc`
|
||||
- Effort: 1 hour
|
||||
- Benefit: Enables disabled state system
|
||||
|
||||
3. **Implement disabled state rendering in sidebar**
|
||||
- Files: `editor_card_registry.cc` (DrawSidebar)
|
||||
- Effort: 3 hours
|
||||
- Benefit: Immediate visual feedback improvement
|
||||
|
||||
### Phase 2: Menu Bar Improvements (Week 1-2)
|
||||
**Priority: P1 - High**
|
||||
|
||||
4. **Add helper methods to MenuOrchestrator**
|
||||
- Files: `menu_orchestrator.h`, `menu_orchestrator.cc`
|
||||
- Methods: `CanUndo()`, `CanRedo()`, `HasActiveSelection()`, etc.
|
||||
- Effort: 4 hours
|
||||
- Benefit: Foundation for proper menu item states
|
||||
|
||||
5. **Apply enabled conditions to all menu items**
|
||||
- Files: `menu_orchestrator.cc` (all Build*Menu methods)
|
||||
- Effort: 6 hours
|
||||
- Benefit: Professional menu behavior
|
||||
|
||||
6. **Improve status cluster layout and animations**
|
||||
- Files: `ui_coordinator.cc` (DrawMenuBarExtras)
|
||||
- Effort: 4 hours
|
||||
- Benefit: Polished status area
|
||||
|
||||
### Phase 3: Sidebar Enhancements (Week 2)
|
||||
**Priority: P1 - High**
|
||||
|
||||
7. **Add notification badge system**
|
||||
- Files: `editor_card_registry.h`, `editor_card_registry.cc`
|
||||
- Effort: 4 hours
|
||||
- Benefit: Visual notification system
|
||||
|
||||
8. **Enhance hover effects and animations**
|
||||
- Files: `editor_card_registry.cc` (DrawSidebar)
|
||||
- Effort: 3 hours
|
||||
- Benefit: More polished interactions
|
||||
|
||||
9. **Implement responsive sidebar sizing**
|
||||
- Files: `editor_card_registry.cc` (DrawSidebar)
|
||||
- Effort: 2 hours
|
||||
- Benefit: Better UX on different screen sizes
|
||||
|
||||
### Phase 4: Right Panel System (Week 2-3)
|
||||
**Priority: P2 - Medium**
|
||||
|
||||
10. **Add slide-in/out animation**
|
||||
- Files: `right_panel_manager.cc`
|
||||
- Effort: 4 hours
|
||||
- Benefit: Smooth panel transitions
|
||||
|
||||
11. **Implement responsive panel widths**
|
||||
- Files: `right_panel_manager.cc`
|
||||
- Effort: 2 hours
|
||||
- Benefit: Adapts to screen size
|
||||
|
||||
12. **Integrate panel with docking space**
|
||||
- Files: `editor_manager.cc`
|
||||
- Effort: 3 hours
|
||||
- Benefit: Proper space reservation
|
||||
|
||||
### Phase 5: Polish and Refinement (Week 3-4)
|
||||
**Priority: P3 - Nice to Have**
|
||||
|
||||
13. **Add category headers/separators to sidebar**
|
||||
- Files: `editor_card_registry.h`, `editor_card_registry.cc`
|
||||
- Effort: 4 hours
|
||||
- Benefit: Better organization for large card lists
|
||||
|
||||
14. **Implement layout breakpoints**
|
||||
- Files: New `layout_manager.h/cc` or in `editor_manager.cc`
|
||||
- Effort: 6 hours
|
||||
- Benefit: Professional responsive design
|
||||
|
||||
15. **Add menu section headers**
|
||||
- Files: `menu_builder.h`, `menu_orchestrator.cc`
|
||||
- Effort: 3 hours
|
||||
- Benefit: Better menu organization
|
||||
|
||||
---
|
||||
|
||||
## 7. New Classes/Methods Summary
|
||||
|
||||
### New Classes
|
||||
- None required (all improvements extend existing classes)
|
||||
|
||||
### New Methods
|
||||
|
||||
**EditorCardRegistry**:
|
||||
- `void DrawCardWithBadge(const CardInfo& card, bool is_active)`
|
||||
- `void DrawSidebarWithSections(size_t session_id, const std::string& category, const std::map<std::string, std::vector<CardInfo>>& card_sections)`
|
||||
|
||||
**MenuOrchestrator**:
|
||||
- `bool HasActiveSelection() const`
|
||||
- `bool CanUndo() const`
|
||||
- `bool CanRedo() const`
|
||||
- `bool HasClipboardData() const`
|
||||
- `bool IsRomModified() const`
|
||||
|
||||
**MenuBuilder**:
|
||||
- `void SeparatorWithSpacing(float height = 4.0f)`
|
||||
- `void SectionHeader(const char* label)`
|
||||
|
||||
**UICoordinator**:
|
||||
- `void DrawDirtyBadge()`
|
||||
|
||||
**RightPanelManager**:
|
||||
- `float GetAnimationProgress() const { return panel_animation_; }`
|
||||
|
||||
**AgentUI namespace**:
|
||||
- `void PushSidebarStyle()`
|
||||
- `void PopSidebarStyle()`
|
||||
- `void RenderSidebarButton(const char* icon, bool is_active, bool is_enabled, int notification_count = 0)`
|
||||
- `void PushMenuSectionStyle()`
|
||||
- `void PopMenuSectionStyle()`
|
||||
- `void RenderDirtyIndicator(bool dirty)`
|
||||
- `void RenderNotificationBadge(int count)`
|
||||
- `void RenderSessionIndicator(const char* session_name, bool is_active)`
|
||||
|
||||
---
|
||||
|
||||
## 8. Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
1. **CardInfo enabled_condition**: Test cards with/without conditions
|
||||
2. **Badge rendering**: Test badge count display (0, 1-99, 100+)
|
||||
3. **Menu item enabling**: Test all enabled condition helpers
|
||||
4. **Panel animation**: Test animation state transitions
|
||||
|
||||
### Integration Tests
|
||||
1. **Sidebar disabled states**: Open/close ROM, verify card states
|
||||
2. **Menu bar preconditions**: Test menu items with various editor states
|
||||
3. **Right panel animation**: Test panel open/close/switch
|
||||
4. **Responsive layout**: Test at different window sizes (1024, 1920, 2560)
|
||||
|
||||
### Visual Regression Tests
|
||||
1. **Sidebar appearance**: Screenshot tests for active/inactive/disabled states
|
||||
2. **Menu bar appearance**: Screenshot tests for enabled/disabled items
|
||||
3. **Status cluster**: Screenshot tests for dirty/clean, notifications
|
||||
4. **Panel transitions**: Record video of animations for smoothness verification
|
||||
|
||||
---
|
||||
|
||||
## 9. Migration Notes
|
||||
|
||||
### Backward Compatibility
|
||||
- All changes are additive (new fields/methods)
|
||||
- Existing code continues to work
|
||||
- `enabled_condition` is optional (defaults to always enabled)
|
||||
|
||||
### Editor Migration
|
||||
Editors should register cards with enabled conditions:
|
||||
|
||||
```cpp
|
||||
// OLD:
|
||||
card_registry.RegisterCard(session_id, {
|
||||
.card_id = "dungeon.room_selector",
|
||||
.display_name = "Room Selector",
|
||||
.icon = ICON_MD_GRID_VIEW,
|
||||
.category = "Dungeon",
|
||||
.visibility_flag = &show_room_selector_
|
||||
});
|
||||
|
||||
// NEW (with enabled condition):
|
||||
card_registry.RegisterCard(session_id, {
|
||||
.card_id = "dungeon.room_selector",
|
||||
.display_name = "Room Selector",
|
||||
.icon = ICON_MD_GRID_VIEW,
|
||||
.category = "Dungeon",
|
||||
.visibility_flag = &show_room_selector_,
|
||||
.enabled_condition = [this]() { return rom_->is_loaded(); } // NEW
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Future Enhancements
|
||||
|
||||
### Beyond Initial Implementation
|
||||
1. **Command Palette Integration**: Quick access to all cards/menus
|
||||
2. **Keyboard Navigation**: Full keyboard control of sidebar/panels
|
||||
3. **Custom Layouts**: Save/restore sidebar configurations
|
||||
4. **Accessibility**: Screen reader support, high-contrast mode
|
||||
5. **Theming**: Allow users to customize sidebar colors
|
||||
6. **Gesture Support**: Swipe to open/close panels on touch devices
|
||||
|
||||
---
|
||||
|
||||
## 11. Success Metrics
|
||||
|
||||
### Measurable Goals
|
||||
1. **User feedback**: "Feels like VSCode" in user testing
|
||||
2. **Discoverability**: New users find features without documentation
|
||||
3. **Efficiency**: Power users can navigate faster with keyboard
|
||||
4. **Consistency**: Zero hardcoded colors, all theme-based
|
||||
5. **Responsiveness**: Smooth at 60fps on all supported platforms
|
||||
|
||||
### Acceptance Criteria
|
||||
- [ ] All sidebar cards show disabled state when ROM not loaded
|
||||
- [ ] All menu items properly gray out based on preconditions
|
||||
- [ ] Status cluster is visible and informative
|
||||
- [ ] Right panel animates smoothly
|
||||
- [ ] No visual glitches during window resize
|
||||
- [ ] Theme changes apply to all new UI elements
|
||||
- [ ] Keyboard shortcuts work for all major actions
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Code Snippets Repository
|
||||
|
||||
All code snippets from this document are reference implementations. Actual implementation may vary based on:
|
||||
- Performance profiling results
|
||||
- User feedback
|
||||
- Platform-specific considerations
|
||||
- Integration with existing systems
|
||||
|
||||
## Appendix B: Visual Design References
|
||||
|
||||
### IDE Inspirations
|
||||
- **VSCode**: Sidebar icon layout, status bar clusters
|
||||
- **JetBrains IDEs**: Menu organization, tool window badges
|
||||
- **Sublime Text**: Minimap, distraction-free mode
|
||||
- **Atom**: Theme system, package management UI
|
||||
|
||||
### Material Design Principles
|
||||
- **Elevation**: Use shadows/borders for depth
|
||||
- **Motion**: Meaningful animations (not decorative)
|
||||
- **Color**: Semantic color usage (error=red, success=green)
|
||||
- **Typography**: Clear hierarchy, readable at all sizes
|
||||
160
docs/internal/plans/web_runtime_refactor.md
Normal file
160
docs/internal/plans/web_runtime_refactor.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# YAZE Web Runtime Refactoring & Optimization Plan
|
||||
|
||||
**Date:** November 25, 2025
|
||||
**Target Component:** `src/web` (WASM Runtime & UI Layer)
|
||||
**Status:** Draft
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
The YAZE web runtime is a sophisticated application bridging C++ (via Emscripten) with modern Web APIs. It features advanced capabilities like PWA support, touch gestures, and a DOM-mirroring system for AI agents.
|
||||
|
||||
However, the current codebase suffers from **initialization fragility** (reliance on `setInterval` polling) and **architectural coupling** (massive inline scripts in `shell.html`, duplicate logic modules). This plan outlines the steps to stabilize the startup sequence, modularize the UI logic, and consolidate redundant features.
|
||||
|
||||
---
|
||||
|
||||
## 2. Current State Analysis
|
||||
|
||||
### 2.1. Strengths
|
||||
* **Namespace Architecture:** `src/web/core/namespace.js` provides a solid foundation for organizing globals.
|
||||
* **Agent Readiness:** The `widget_overlay.js` and `agent_automation.js` components are forward-thinking, enabling DOM-based agents to "see" the canvas.
|
||||
* **Performance:** Excellent implementation of Service Workers (`stale-while-revalidate`) and AudioWorklets.
|
||||
|
||||
### 2.2. Critical Issues
|
||||
1. **Initialization Race Conditions:** Components like `FilesystemManager` and `terminal.js` poll for `Module` readiness using `setInterval`. This is non-deterministic and wastes cycles.
|
||||
2. **`shell.html` Bloat:** The main HTML file contains ~500 lines of inline JavaScript handling UI settings, menus, and AI tools. This creates circular dependencies (Terminal depends on Shell) and violates CSP best practices.
|
||||
3. **Logic Duplication:**
|
||||
* **Collaboration:** `collab_console.js` (JS WebSocket) vs `collaboration_ui.js` (C++ Bindings).
|
||||
* **Drag & Drop:** `drop_zone.js` (JS Implementation) vs `WasmDropHandler` (C++ Implementation).
|
||||
4. **Global Namespace Pollution:** Despite having `window.yaze`, many components still attach directly to `window` or rely on Emscripten's global `Module`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Improvement Plan
|
||||
|
||||
### Phase 1: Stabilization (Initialization Architecture)
|
||||
**Goal:** Replace polling with a deterministic Event/Promise chain.
|
||||
|
||||
1. **Centralize Boot Sequence:**
|
||||
* Modify `src/web/core/namespace.js` to expose a `yaze.core.boot()` Promise.
|
||||
* Refactor `app.js` to resolve this Promise only when `Module.onRuntimeInitialized` fires.
|
||||
2. **Refactor Dependent Components:**
|
||||
* Update `FilesystemManager` to await `yaze.core.boot()` instead of polling.
|
||||
* Update `terminal.js` to listen for the `yaze:ready` event instead of checking `isModuleReady` via interval.
|
||||
|
||||
### Phase 2: Decoupling (Shell Extraction)
|
||||
**Goal:** Remove inline JavaScript from `shell.html`.
|
||||
|
||||
1. **Extract UI Controller:**
|
||||
* Create `src/web/core/ui_controller.js`.
|
||||
* Move Settings modal logic, Theme switching, and Layout toggling from `shell.html` to this new file.
|
||||
2. **Relocate AI Tools:**
|
||||
* Move the `aiTools` object definitions from `shell.html` to `src/web/core/agent_automation.js`.
|
||||
* Ensure `terminal.js` references `window.yaze.ai` instead of the global `aiTools`.
|
||||
3. **Clean `shell.html`:**
|
||||
* Replace inline `onclick` handlers with event listeners attached in `ui_controller.js`.
|
||||
|
||||
### Phase 3: Consolidation (Redundancy Removal)
|
||||
**Goal:** Establish "Single Sources of Truth".
|
||||
|
||||
1. **Collaboration Unification:**
|
||||
* Designate `components/collaboration_ui.js` (C++ Bindings) as the primary implementation.
|
||||
* Deprecate `collab_console.js` or repurpose it strictly as a UI view for the C++ backend, removing its direct WebSocket networking code.
|
||||
2. **Drop Zone Cleanup:**
|
||||
* Modify `drop_zone.js` to act purely as a visual overlay.
|
||||
* Pass drop events directly to the C++ `WasmDropHandler` via `Module.ccall`, removing the JS-side file parsing logic unless it serves as a specific fallback.
|
||||
|
||||
---
|
||||
|
||||
## 4. Technical Implementation Steps
|
||||
|
||||
### Step 4.1: Create UI Controller
|
||||
**File:** `src/web/core/ui_controller.js`
|
||||
|
||||
```javascript
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.yaze.ui.controller = {
|
||||
init: function() {
|
||||
this.bindEvents();
|
||||
this.loadSettings();
|
||||
},
|
||||
|
||||
bindEvents: function() {
|
||||
// Move event listeners here
|
||||
document.getElementById('settings-btn').addEventListener('click', this.showSettings);
|
||||
// ...
|
||||
},
|
||||
|
||||
// Move settings logic here
|
||||
showSettings: function() { ... }
|
||||
};
|
||||
|
||||
// Auto-init on DOM ready
|
||||
document.addEventListener('DOMContentLoaded', () => window.yaze.ui.controller.init());
|
||||
})();
|
||||
```
|
||||
|
||||
### Step 4.2: Refactor Initialization (Namespace)
|
||||
**File:** `src/web/core/namespace.js`
|
||||
|
||||
Add a boot promise mechanism:
|
||||
|
||||
```javascript
|
||||
window.yaze.core.bootPromise = new Promise((resolve) => {
|
||||
window.yaze._resolveBoot = resolve;
|
||||
});
|
||||
|
||||
window.yaze.core.ready = function() {
|
||||
return window.yaze.core.bootPromise;
|
||||
};
|
||||
```
|
||||
|
||||
**File:** `src/web/app.js`
|
||||
|
||||
Trigger the boot:
|
||||
|
||||
```javascript
|
||||
Module.onRuntimeInitialized = function() {
|
||||
// ... existing initialization ...
|
||||
window.yaze._resolveBoot(Module);
|
||||
window.yaze.events.emit('ready', Module);
|
||||
};
|
||||
```
|
||||
|
||||
### Step 4.3: Clean Shell HTML
|
||||
Remove the `<script>` block at the bottom of `src/web/shell.html` and replace it with:
|
||||
```html
|
||||
<script src="core/ui_controller.js"></script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Verification Strategy
|
||||
|
||||
1. **Startup Test:**
|
||||
* Load the page with Network throttling (Slow 3G).
|
||||
* Verify no errors appear in the console regarding "Module not defined" or "FS not ready".
|
||||
* Confirm `FilesystemManager` initializes without retries.
|
||||
|
||||
2. **Feature Test:**
|
||||
* Open "Settings" modal (verifies `ui_controller.js` migration).
|
||||
* Type `/ai app-state` in the terminal (verifies `aiTools` migration).
|
||||
* Drag and drop a ROM file (verifies Drop Zone integration).
|
||||
|
||||
3. **Agent Test:**
|
||||
* Execute `window.yaze.gui.discover()` in the console.
|
||||
* Verify it returns the JSON tree of ImGui widgets.
|
||||
|
||||
---
|
||||
|
||||
## 6. Action Checklist
|
||||
|
||||
- [ ] **Create** `src/web/core/ui_controller.js`.
|
||||
- [ ] **Refactor** `src/web/core/namespace.js` to include boot Promise.
|
||||
- [ ] **Modify** `src/web/app.js` to resolve boot Promise on init.
|
||||
- [ ] **Move** `aiTools` from `shell.html` to `src/web/core/agent_automation.js`.
|
||||
- [ ] **Move** Settings/UI logic from `shell.html` to `src/web/core/ui_controller.js`.
|
||||
- [ ] **Clean** `src/web/shell.html` (remove inline scripts).
|
||||
- [ ] **Refactor** `src/web/core/filesystem_manager.js` to await boot Promise.
|
||||
- [ ] **Update** `src/web/pwa/service-worker.js` to cache new `ui_controller.js`.
|
||||
Reference in New Issue
Block a user