Web Integration (WASM)
Relevant source files
The following files were used as context for generating this wiki page:
The Web Integration module serves as the bridge between the high-performance Rust core logic and the TypeScript/Svelte frontend of Dotorixel. By utilizing WebAssembly (WASM), the project moves computationally intensive tasks—such as pixel manipulation, coordinate transformations, and undo/redo history management—into a compiled environment while maintaining a seamless API for the web shell.
This integration is achieved via wasm-pack and wasm-bindgen, which generate the necessary bindings to expose Rust structures as JavaScript-compatible classes and functions. The system is designed to be self-contained, ensuring that the core logic remains independent of the DOM or specific web frameworks.
Sources: CLAUDE.md, tasks/records/004-wasm-bindings.md
Architecture and Data Flow
The architecture follows a wrapper pattern where Rust core entities are wrapped in Wasm* prefixed structures specifically for the web. This prevents the primary core logic from being tightly coupled to wasm-bindgen and allows for easier maintenance of other platform bindings, such as UniFFI for Apple native targets.
Initialization Flow
The WASM module requires asynchronous initialization before it can be used by Svelte components or test runners. In the browser, this is handled at the SvelteKit layout level or during app startup to ensure all components have access to the underlying WASM memory.
The following diagram illustrates the lifecycle of a WASM operation initiated from the TypeScript UI:
Core WASM Components
The integration exposes several key classes that replicate the editor's internal state machine within the WASM environment.
WasmPixelCanvas
This is the primary data structure for pixel storage. It manages an RGBA buffer and provides methods for direct manipulation, resizing, and coordinate validation.
| Feature | Description |
|---|---|
| Pixel Access | Provides get_pixel and set_pixel using WasmColor objects. |
| Bulk Data | Exposes the raw buffer as a Uint8Array via the pixels() method. |
| Resize | Supports resizing with various WasmResizeAnchor options (e.g., Center, TopLeft). |
| Constraints | Enforces min_dimension (1) and max_dimension (256). |
Sources: wasm/src/lib.rs, src/lib/wasm/wasm-canvas.test.ts:77-83
WasmViewport
Handles the mathematics of rendering the canvas on screen. It calculates transforms for zooming and panning, ensuring that the canvas remains within user-friendly boundaries.
| Method | Description |
|---|---|
zoom_at_point | Adjusts scale relative to a specific screen coordinate. |
pan | Shifts the canvas offset based on user movement. |
clamp_pan | Prevents the canvas from being moved entirely out of the visible area. |
screen_to_canvas | Translates screen-space coordinates to pixel-space coordinates. |
Sources: wasm/src/lib.rs, tasks/records/004-wasm-bindings.md
Interface and Bindings Logic
The integration layer performs critical type conversions to ensure compatibility between Rust's strict type system and JavaScript's dynamic nature.
Type Mapping
- Colors: Rust
Colorstructs are mapped toWasmColorclasses with RGBA getters/setters. - Collections:
Vec<u8>buffers are converted toUint8Arrayfor efficient transfer to the HTML5 Canvas2D context. - Enums: Tool types and resize anchors are exposed as C-style enums for straightforward consumption in TypeScript.
Implementation Details: Canvas Resize
The resize logic demonstrates the coordination between the layers. The UI provides a ResizeAnchor string, which the EditorState maps to a WASM-compatible enum before calling the Rust core.
// wasm/src/lib.rs
#[wasm_bindgen]
pub enum WasmResizeAnchor {
TopLeft,
Top,
TopRight,
Center,
// ... other variants
}
#[wasm_bindgen]
impl WasmPixelCanvas {
pub fn resize_with_anchor(&self, width: u32, height: u32, anchor: WasmResizeAnchor) -> WasmPixelCanvas {
// Core logic invocation
}
}
Sources: wasm/src/lib.rs, tasks/records/057-canvas-resize-ux.md
Testing and Setup
To support unit testing in Node.js (via Vitest), a specialized setup is used to inject the WASM binary manually, as Node does not natively support the same browser-based WASM loading mechanisms.
Vitest WASM Initialization
The file src/lib/wasm/setup.ts uses fs.readFileSync to load the .wasm file and initSync from the generated bindings to prepare the environment before tests execute. This allows 231+ tests (both TS and Rust-based) to run in a unified pipeline.
// src/lib/wasm/setup.ts
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import init from '$wasm/dotorixel_wasm';
const wasmPath = resolve(__dirname, '../../../wasm/pkg/dotorixel_wasm_bg.wasm');
const wasmBuffer = readFileSync(wasmPath);
init(wasmBuffer);
Sources: src/lib/wasm/setup.ts, tasks/records/004-wasm-bindings.md
Summary
The Web Integration (WASM) module is the backbone of Dotorixel's performance. It encapsulates complex pixel art algorithms—including Bresenham line drawing, flood fill, and viewport transforms—into a high-performance binary. By decoupling the core logic into Rust and exposing it via a structured WASM interface, the project achieves cross-platform parity with the Apple native shell while maintaining the accessibility of a web-based editor.