Canvas Rendering (Web)
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The Canvas Rendering system in Dotorixel is responsible for translating pixel data from the Rust-based core into a visual representation within a web browser. It utilizes the HTML5 Canvas2D API for the initial MVP scope, with future plans to migrate to WebGL2 for enhanced performance. The rendering pipeline is decoupled from the WebAssembly (WASM) implementation via local interfaces, allowing the UI to remain agnostic of the underlying data storage format.
The system handles real-time updates of the pixel grid, viewport transformations (zoom and pan), and interactive elements like grid overlays. It serves as the bridge between the core pixel buffer and the user's display, ensuring that pixel art is rendered with sharp, non-interpolated edges appropriate for the medium.
Sources: CLAUDE.md:10, tasks/records/005-ts-wasm-migration.md:12-14
Architecture and Components
Rendering Pipeline
The rendering process is triggered by changes in the canvas state or viewport. A dedicated renderPixelCanvas function acts as the primary entry point, taking a 2D rendering context and a "RenderableCanvas" object. To prevent tight coupling, the renderer interacts with the pixel data through a specific interface rather than directly accessing WASM types.
The pipeline uses a Svelte $effect to monitor renderVersion and pixelCanvas changes, ensuring the DOM canvas is updated whenever the underlying data or viewport parameters are modified.
Sources: src/lib/canvas/PixelCanvasView.svelte:61-71, tasks/records/005-ts-wasm-migration.md:14
Component Breakdown
| Component | Responsibility |
|---|---|
PixelCanvasView.svelte | Manages the <canvas> DOM element, handles user input (pointer/wheel), and orchestrates rendering cycles. |
renderer.ts | Contains the core logic for drawing pixels and grid overlays onto the canvas context. |
WasmPixelCanvas | The Rust-backed source of truth for pixel data, exposed via WASM bindings. |
WasmViewport | Handles coordinate transformations and viewport math (zoom level, panning). |
Sources: src/lib/canvas/PixelCanvasView.svelte:1-35, CLAUDE.md:12, tasks/records/005-ts-wasm-migration.md:15-20
Implementation Details
Viewport and Scaling
Rendering is heavily dependent on the ViewportState, which defines how pixels are projected onto the screen. Key parameters include zoom (scaling factor) and pan (XY offsets). The renderer ensures that the drawing is sharp by utilizing image-rendering: pixelated on the canvas element.
The viewport logic supports discrete zoom levels and specialized "pinch-zoom" calculations for trackpads and touch devices.
Sources: src/lib/canvas/PixelCanvasView.svelte:165-170, src/lib/canvas/PixelCanvasView.svelte:85-95, src/lib/wasm/wasm-canvas.test.ts:109-115
Pixel Data Handling
Pixel data is typically handled as a Uint8Array of RGBA values. The WASM-backed canvas provides a bulk pixels() method to retrieve this buffer, which is then used by the renderer to draw the image. For performance, the system supports "restore" operations to quickly revert the canvas state from a snapshot, which is essential for the Undo/Redo system.
Sources: src/lib/wasm/wasm-canvas.test.ts:20-24, tasks/records/005-ts-wasm-migration.md:9-10
Performance Benchmarking
The project includes a benchmarking tool to measure the frame time of renderPixelCanvas across various canvas sizes (8x8 to 128x128) and zoom levels. This identifies the performance ceiling of the Canvas2D implementation.
| Canvas Size | Zoom | Median Frame Time (ms) | Target |
|---|---|---|---|
| 32x32 | 16x | Measured in Bench | < 16ms (60 FPS) |
| 128x128 | 1x | Measured in Bench | < 16ms (60 FPS) |
Sources: src/routes/bench/+page.svelte:6-15, src/routes/bench/+page.svelte:78-85
Conclusion
Canvas Rendering on the web for Dotorixel is a structured pipeline that prioritizes modularity by decoupling the Svelte UI and Rust core. By utilizing the Canvas2D API with sharp scaling and efficient viewport math, the system provides a responsive environment for pixel art creation. The presence of integrated benchmarking ensures that as the project moves toward WebGL2, the performance gains can be quantifiably verified.