Canvas Rendering System
Relevant source files
The following files were used as context for generating this wiki page:
The Canvas Rendering System in Rocreate is a hybrid architecture designed to provide high-performance digital painting and image manipulation. It utilizes a multi-layered approach that combines standard HTML5 Canvas 2D for stable data management, WebGL-powered fx-canvas for real-time filter processing, and Google's CanvasKit (Skia WASM) for GPU-accelerated compositing and brush rendering.
The system is designed to handle complex layer stacks, including clipping masks and various blend modes, while maintaining 60fps performance through specialized renderers and viewports. The primary entry point for managing these operations is the KlCanvas class, which serves as the central hub for pixel data, layer manipulation, and drawing commands.
Sources: src/app/script/app/kl-app.ts:25-30, src/app/script/klecks/canvas/kl-canvas.ts, src/app/script/canvaskit/canvaskit-compositor.ts:13-18
Core Architectural Components
The rendering system is partitioned into several specialized modules, each handling a specific part of the graphics pipeline.
1. Central Canvas Controller (KlCanvas)
The KlCanvas manages the state of the digital artwork. It maintains an array of layers, each consisting of an HTMLCanvasElement and metadata such as visibility, opacity, and blend modes. It is responsible for high-level operations like adding layers, merging, and performing basic drawing tasks like flood fills and text rendering.
Sources: src/app/script/klecks/canvas/kl-canvas.ts, src/app/script/app/kl-app.ts:121-125
2. Viewport and Display (ProjectViewport)
The viewport system is responsible for projecting the multi-layered canvas onto the user's screen. It handles transformations including translation, rotation, and scaling. It supports both standard 2D context rendering and GPU-accelerated rendering via GPUProjectViewport.
Sources: src/app/script/klecks/ui/project-viewport/project-viewport.ts:80-90, src/app/script/app/kl-app.ts:145-155
3. GPU Compositor (CanvasKitCompositor)
This component uses CanvasKit (Skia WASM) to perform the heavy lifting of layer blending on the GPU. It maps standard CSS blend modes (e.g., "multiply", "screen") to Skia BlendMode enums and handles complex clipping stacks.
Sources: src/app/script/canvaskit/canvaskit-compositor.ts:13-52
4. Filter Pipeline (fx-canvas)
Real-time image adjustments (brightness, contrast, hue/saturation) are handled by fx-canvas. It wraps WebGL shaders to process image textures efficiently without blocking the main UI thread.
Sources: src/app/script/fx-canvas/fx-canvas.ts:40-60
Data Flow and Rendering Pipeline
The system follows a specific flow when updating the display. When a user draws a stroke, the system manages a "live" layer that is composited in real-time before being committed to the permanent layer data.
The diagram above illustrates the path from user input to the final screen output, highlighting where GPU acceleration via CanvasKit is utilized.
Sources: src/app/script/app/kl-app.ts:820-850, src/app/script/canvaskit/canvaskit-compositor.ts:140-160
Advanced Rendering Features
Layer Compositing and Blending
The system supports a wide range of Porter-Duff and standard blend modes. The CanvasKitCompositor uses a specific mapping to ensure consistency between the 2D fallback and the GPU path.
| Canvas 2D Mode | CanvasKit BlendMode | Description |
|---|---|---|
source-over | SrcOver | Standard alpha blending |
multiply | Multiply | Multiplies colors; darkens the result |
screen | Screen | Inverse multiply; lightens the result |
source-atop | SrcATop | Used primarily for Clipping Masks |
destination-out | DstOut | Used for eraser operations |
Sources: src/app/script/canvaskit/canvaskit-compositor.ts:21-48, src/app/script/klecks/ui/project-viewport/project-viewport.ts:25-35
GPU-Accelerated Brush Rendering
The CanvasKitBrushRenderer provides high-fidelity strokes using Skia's Path and Paint APIs. It supports:
- Bezier Interpolation: Smooth quadratic curves between pointer events.
- Pressure Sensitivity: Dynamic adjustment of brush size and opacity.
- Tilt Dynamics: Modifying stroke appearance based on stylus tilt magnitude.
Sources: src/app/script/canvaskit/canvaskit-brush-renderer.ts:110-150, src/app/script/canvaskit/canvaskit-brush-renderer.ts:180-205
Clipping Masks and Groups
The compositor handles clipping stacks by creating temporary save layers. If a layer is marked as a clipping mask, it is composited using the SrcATop blend mode against the base layer of its group.
Sequence of operations for rendering a clipping mask stack in the GPU compositor.
Sources: src/app/script/canvaskit/canvaskit-compositor.ts:175-200
Implementation Details: KlCanvas Layer Management
The KlCanvas manages layers through an internal array. Each layer entry contains the pixel buffer and its compositing state.
// From src/app/script/klecks/canvas/kl-canvas.ts
export type TKlCanvasLayer = {
id: string;
image: HTMLCanvasElement;
context: CanvasRenderingContext2D;
isVisible: boolean;
opacity: number;
mixModeStr: TMixMode; // e.g., 'multiply', 'screen'
name: string;
};
Key methods in KlCanvas for rendering include:
layerFill(layerIndex, color): Fills a layer or selection with a specific color.floodFillAsync(...): Performs a non-blocking bucket fill operation using a worker.setComposite(layerIndex, composite): Sets a temporary live composite function (used for brush stroke previews).
Sources: src/app/script/klecks/canvas/kl-canvas.ts, src/app/script/app/kl-app.ts:220-230
Viewport Transformation Logic
The ProjectViewport calculates the final pixel position on the screen based on a TViewportTransform object. This includes complex logic to handle device pixel ratios (DPR) and anti-aliasing.
The logic flow for calculating transformations and drawing the project onto the visible screen viewport.
Sources: src/app/script/klecks/ui/project-viewport/project-viewport.ts:114-150, src/app/script/klecks/ui/project-viewport/project-viewport.ts:160-185
Summary
The Rocreate Canvas Rendering System effectively bridges high-level user tools with low-level GPU hardware. By leveraging CanvasKit for the heavy compositing and brush operations, while maintaining a flexible HTMLCanvasElement back-end, the system ensures responsiveness during complex painting tasks while remaining compatible with standard web APIs for import/export.