Files
yaze/docs/internal/archive/completed_features/web-drag-drop-implementation.md

267 lines
7.3 KiB
Markdown

# Drag & Drop ROM Loading for WASM
This document describes the drag & drop ROM loading feature for the WASM/web build of yaze.
## Overview
The drag & drop system allows users to drag ROM files (`.sfc`, `.smc`, or `.zip`) directly onto the web page to load them into the editor. This provides a seamless and intuitive way to open ROMs without using file dialogs.
## Features
- **Visual Feedback**: Full-screen overlay with animations when dragging files
- **File Validation**: Only accepts valid ROM file types (`.sfc`, `.smc`, `.zip`)
- **Progress Indication**: Shows loading progress for large files
- **Error Handling**: Clear error messages for invalid files
- **Responsive Design**: Works on desktop and tablet devices
- **Accessibility**: Supports keyboard navigation and screen readers
## Architecture
### Components
1. **C++ Backend** (`wasm_drop_handler.h/cc`)
- Singleton pattern for global drop zone management
- Callback system for ROM data handling
- JavaScript interop via Emscripten's EM_JS
- Integration with Rom::LoadFromData()
2. **JavaScript Handler** (`drop_zone.js`)
- DOM event handling (dragenter, dragover, dragleave, drop)
- File validation and reading
- Progress tracking
- Module integration
3. **CSS Styling** (`drop_zone.css`)
- Full-screen overlay with glassmorphism effect
- Smooth animations and transitions
- Dark mode support
- High contrast mode support
## Implementation
### C++ Integration
```cpp
#ifdef __EMSCRIPTEN__
#include "app/platform/wasm/wasm_drop_handler.h"
// In your initialization code:
auto& drop_handler = yaze::platform::WasmDropHandler::GetInstance();
drop_handler.Initialize(
"", // Use document body as drop zone
[this](const std::string& filename, const std::vector<uint8_t>& data) {
// Handle dropped ROM
auto rom = std::make_unique<Rom>();
auto status = rom->LoadFromData(data);
if (status.ok()) {
// Load into editor
LoadRomIntoEditor(std::move(rom), filename);
}
},
[](const std::string& error) {
// Handle errors
ShowErrorMessage(error);
}
);
#endif
```
### HTML Integration
```html
<!DOCTYPE html>
<html>
<head>
<!-- Include the drop zone styles -->
<link rel="stylesheet" href="drop_zone.css">
</head>
<body>
<!-- Your application canvas -->
<canvas id="canvas"></canvas>
<!-- Include the drop zone script -->
<script src="drop_zone.js"></script>
<!-- Your Emscripten module -->
<script src="yaze.js"></script>
</body>
</html>
```
### JavaScript Customization
```javascript
// Optional: Customize the drop zone after Module is ready
Module.onRuntimeInitialized = function() {
YazeDropZone.init({
config: {
validExtensions: ['sfc', 'smc', 'zip', 'sfc.gz'],
maxFileSize: 8 * 1024 * 1024, // 8MB
messages: {
dropHere: 'Drop A Link to the Past ROM',
loading: 'Loading ROM...',
supported: 'Supported: .sfc, .smc, .zip'
}
},
callbacks: {
onDrop: function(filename, data) {
console.log('ROM dropped:', filename, data.length + ' bytes');
},
onError: function(error) {
console.error('Drop error:', error);
}
}
});
};
```
## User Experience
### Workflow
1. User opens yaze in a web browser
2. User drags a ROM file from their file manager
3. When the file enters the browser window:
- Full-screen overlay appears with drop zone
- Visual feedback indicates valid drop target
4. User drops the file:
- Loading animation shows progress
- File is validated and loaded
- ROM opens in the editor
5. If there's an error:
- Clear error message is displayed
- User can try again
### Visual States
- **Idle**: No overlay visible
- **Drag Enter**: Semi-transparent overlay with dashed border
- **Drag Over**: Green glow effect, scaled animation
- **Loading**: Blue progress bar with file info
- **Error**: Red border with error message
## Build Configuration
The drag & drop feature is automatically included when building for WASM:
```bash
# Install Emscripten SDK
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
# Build yaze with WASM preset
cd /path/to/yaze
cmake --preset wasm-release
cmake --build build --target yaze
# Serve the files
python3 -m http.server 8000 -d build
# Open http://localhost:8000/yaze.html
```
## Browser Compatibility
| Browser | Version | Support |
|---------|---------|---------|
| Chrome | 90+ | ✅ Full |
| Firefox | 88+ | ✅ Full |
| Safari | 14+ | ✅ Full |
| Edge | 90+ | ✅ Full |
| Mobile Chrome | Latest | ⚠️ Limited (no drag & drop on mobile) |
| Mobile Safari | Latest | ⚠️ Limited (no drag & drop on mobile) |
## Performance Considerations
- Files are read into memory completely before processing
- Large files (>4MB) may take a few seconds to load
- Progress indication helps with user feedback
- Consider implementing streaming for very large files
## Security
- Files are processed entirely in the browser
- No data is sent to any server
- File validation prevents loading non-ROM files
- Cross-origin restrictions apply to drag & drop
## Testing
### Manual Testing
1. Test with valid ROM files (.sfc, .smc)
2. Test with invalid files (should show error)
3. Test with large files (>4MB)
4. Test drag enter/leave behavior
5. Test multiple file drops (should handle first only)
6. Test with compressed files (.zip)
### Automated Testing
```javascript
// Example test using Playwright or Puppeteer
test('drag and drop ROM loading', async ({ page }) => {
await page.goto('http://localhost:8000/yaze.html');
// Create a DataTransfer object with a file
await page.evaluateHandle(async () => {
const dt = new DataTransfer();
const file = new File(['rom data'], 'zelda3.sfc', {
type: 'application/octet-stream'
});
dt.items.add(file);
// Dispatch drag events
const dropEvent = new DragEvent('drop', {
dataTransfer: dt,
bubbles: true,
cancelable: true
});
document.body.dispatchEvent(dropEvent);
});
// Verify ROM loaded
await expect(page).toHaveText('ROM loaded successfully');
});
```
## Troubleshooting
### Common Issues
1. **Overlay doesn't appear**
- Check browser console for JavaScript errors
- Verify drop_zone.js is loaded
- Ensure Module is initialized
2. **ROM doesn't load after drop**
- Check if file is a valid ROM format
- Verify file size is within limits
- Check console for error messages
3. **Styles are missing**
- Ensure drop_zone.css is included
- Check for CSS conflicts with other stylesheets
4. **Performance issues**
- Consider reducing file size limit
- Implement chunked reading for large files
- Use Web Workers for processing
## Future Enhancements
- [ ] Support for IPS/BPS patches via drag & drop
- [ ] Multiple file selection for batch operations
- [ ] Drag & drop for graphics/palette files
- [ ] Preview ROM information before loading
- [ ] Integration with cloud storage providers
- [ ] Touch device support via file input fallback
## References
- [MDN Drag and Drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API)
- [Emscripten EM_JS Documentation](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-ccall-cwrap)
- [File API Specification](https://www.w3.org/TR/FileAPI/)