Brush Engine
Relevant source files
The following files were used as context for generating this wiki page:
- src/app/script/klecks/brushes/brush.interface.ts
- src/app/script/klecks/brushes/pen-brush.ts
- src/app/script/klecks/brushes/smudge-brush.ts
- src/app/script/klecks/brushes/pen-brush-hybrid.ts
- src/app/script/canvaskit/canvaskit-brush-renderer.ts
- src/app/script/klecks/brushes-ui/pen-brush-ui.ts
- src/app/script/klecks/brushes/brushes.ts
The Brush Engine is the core graphics subsystem of Rocreate, responsible for transforming user input (pointer position, pressure, and tilt) into visual strokes on a digital canvas. It utilizes a modular architecture where individual brush implementations adhere to standardized interfaces, allowing for diverse behaviors ranging from traditional pixel-based pens to complex smudging tools.
The engine employs a hybrid rendering strategy, primarily utilizing the HTML5 Canvas 2D API for stable, software-based rendering while integrating CanvasKit (Skia WASM) for GPU-accelerated performance. This dual approach ensures broad compatibility with a high-performance fallback for demanding operations.
Sources: src/app/script/klecks/brushes/pen-brush-hybrid.ts:8-16, src/app/script/klecks/brushes/brush.interface.ts
Core Architecture
The Brush Engine is built on a series of specialized interfaces that define brush capabilities. Every brush must implement a core set of methods for stroke management, while optional interfaces provide support for dynamics like pressure sensitivity, tilt, and scatter.
Interface Hierarchy
The system uses granular interfaces to ensure that brushes only implement the features they support.
The IBrushCore interface defines the lifecycle of a stroke, while IBrushSettings handles the environmental state such as the drawing context and history tracking.
Sources: src/app/script/klecks/brushes/brush.interface.ts:10-90, src/app/script/klecks/brushes/pen-brush-hybrid.ts:47-57
Rendering Engines
Rocreate implements two distinct rendering paths for brushes: a Canvas 2D path and a CanvasKit (Skia) path.
Canvas 2D Rendering
Traditional brushes like PenBrush and SmudgeBrush operate by drawing "stamps" or "dabs" along a path. They use quadratic bezier interpolation to ensure smooth curves even when input events are sparse.
- Stamping Logic: Calculates the distance between the current and last point; if it exceeds a spacing threshold (fraction of brush size), a new dab is drawn.
- Interpolation: Uses midpoints as control points for smoother quadratic bezier segments.
Sources: src/app/script/klecks/brushes/pen-brush.ts, src/app/script/canvaskit/canvaskit-brush-renderer.ts:167-200
CanvasKit (Skia) GPU Rendering
The CanvasKitBrushRenderer provides GPU-accelerated rendering. It mirrors the stamping logic of the 2D brushes but executes operations via the Skia WASM backend.
The HybridPenBrush attempts to use CanvasKit for circle-shaped brushes without complex blending, falling back to Canvas 2D for specialized features like "Lock Alpha" or custom dabs.
Sources: src/app/script/klecks/brushes/pen-brush-hybrid.ts:11-30, src/app/script/canvaskit/canvaskit-brush-renderer.ts:25-50
Brush Dynamics and Settings
Brushes support various parameters that alter the stroke appearance based on device capabilities (e.g., Apple Pencil or Wacom tablet).
| Parameter | Interface | Description |
|---|---|---|
| Size | IBrushSettings | Base radius of the brush dab. |
| Opacity | IBrushSettings | Transparency of the brush stroke (0.0 to 1.0). |
| Spacing | IBrushSpacing | Distance between dabs, often scaled by brush size. |
| Pressure | IBrushPressure | Maps stylus pressure to size or opacity. |
| Tilt | IBrushTilt | Maps pen tilt angle to size, opacity, or brush angle. |
| Scatter | IBrushScatter | Randomizes the position of dabs around the input path. |
Sources: src/app/script/klecks/brushes/brush.interface.ts:46-120, src/app/script/klecks/brushes-ui/pen-brush-ui.ts:133-160
Implementation: Smudge Brush
The SmudgeBrush is a specialized implementation that does not draw color. Instead, it picks up pixels from the current context and "moves" them along the path.
- Pick-up: On
startLineandgoLine, it samples an area of the canvas into an internal buffer. - Transformation: It applies a blur or alpha manipulation to the sampled pixels.
- Deposit: It draws the sampled pixels back onto the canvas at the new coordinate.
Sources: src/app/script/klecks/brushes/smudge-brush.ts
Stroke Lifecycle
The drawing process follows a strict sequence to ensure consistency and proper undo/redo history.
When endLine is called, the brush calculates the bounding box of the entire stroke and records the changed pixels into the KlHistory system.
Sources: src/app/script/klecks/brushes/pen-brush-hybrid.ts:223-265, src/app/script/klecks/brushes/brush.interface.ts:12-16
Summary
The Rocreate Brush Engine provides a flexible and high-performance framework for digital painting. By abstracting brush behaviors into interfaces and supporting hybrid rendering, it balances the need for complex artistic tools (like smudging and textured pens) with the performance requirements of modern high-resolution canvases. The system's reliance on quadratic interpolation and standardized dynamics ensures a responsive and professional drawing experience.