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

7.3 KiB

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

#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

<!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

// 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:

# 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

// 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