BoardKitFrontend
Rendering Engine
Canvas2DRenderer, InputPipeline, viewport utilities, and element renderers
The rendering engine powers the whiteboard canvas with dual-layer rendering and normalized input processing.
Canvas2DRenderer
The main renderer manages two stacked <canvas> elements:
- Static layer — Renders all elements. Re-renders only when the scene changes (nonce invalidation). Two-pass rendering: non-connectors first, then connectors on top.
- Interactive layer — Renders every animation frame for cursors, selections, previews, alignment guides, and grid.
class Canvas2DRenderer {
constructor();
mount(container: HTMLElement): void;
destroy(): void;
requestRender(): void;
toDataURL(type?: string, quality?: number): string;
}| Method | Description |
|---|---|
mount | Attaches two canvas elements to the given container |
destroy | Removes canvases and stops animation loop |
requestRender | Marks the static layer as dirty for next frame |
toDataURL | Exports the static layer as a data URL (used by useExport) |
InputPipeline
Translates raw DOM PointerEvents into normalized InputEvents that feed into the active tool.
class InputPipeline {
constructor(canvas: HTMLCanvasElement);
setViewport(viewport: ViewportState): void;
setTool(tool: Tool): void;
destroy(): void;
}The pipeline:
- Listens for
pointerdown,pointermove,pointerup,pointercancelon the canvas - Converts screen coordinates to world coordinates using the current viewport
- Extracts pressure, tilt, button, and modifier state
- Feeds the normalized
InputEventinto the active tool - Applies the tool's resulting mutations and previews
Viewport Utilities
interface ViewportState {
offset: Point;
zoom: number;
}
const MIN_ZOOM = 0.1;
const MAX_ZOOM = 5.0;
function createViewport(): ViewportState;
function screenToWorld(point: Point, viewport: ViewportState): Point;
function worldToScreen(point: Point, viewport: ViewportState): Point;
function applyViewportTransform(ctx: CanvasRenderingContext2D, viewport: ViewportState): void;
function zoomToPoint(viewport: ViewportState, point: Point, zoomDelta: number): ViewportState;| Function | Description |
|---|---|
createViewport | Creates a default viewport (zoom: 1, offset: 0,0) |
screenToWorld | Converts screen pixel coordinates to world coordinates |
worldToScreen | Converts world coordinates to screen pixel coordinates |
applyViewportTransform | Applies the viewport transform to a canvas 2D context |
zoomToPoint | Zooms in/out centered on a specific point (smooth zoom-to-cursor) |
Element Renderers
Each element type has a dedicated renderer:
function renderStroke(ctx: CanvasRenderingContext2D, element: StrokeElement): void;
function renderShape(ctx: CanvasRenderingContext2D, element: ShapeElement): void;
function renderText(ctx: CanvasRenderingContext2D, element: TextElement): void;
function renderImage(ctx: CanvasRenderingContext2D, element: ImageElement): void;
function renderStickyNote(ctx: CanvasRenderingContext2D, element: StickyNoteElement): void;
function renderConnector(ctx: CanvasRenderingContext2D, element: ConnectorElement, scene: SceneState): void;Rendering Details
| Renderer | Notes |
|---|---|
renderStroke | Draws polyline with StrokeStyle; supports pressure-based variable width |
renderShape | Supports rectangle, ellipse, line, arrow, triangle with fill and stroke |
renderText | Multi-line text with word wrap, alignment, and font styling |
renderImage | Renders from loaded Image objects; shows placeholder while loading |
renderStickyNote | Colored rectangle with rounded corners + centered text |
renderConnector | Line between two element anchors with optional arrow heads |
Layer Renderers
function renderStaticLayer(ctx: CanvasRenderingContext2D, scene: SceneState): void;
function renderElement(ctx: CanvasRenderingContext2D, element: Element): void;
function renderInteractiveLayer(ctx: CanvasRenderingContext2D, state: BoardStoreState): void;
function renderGrid(ctx: CanvasRenderingContext2D, viewport: ViewportState, config: GridConfig): void;
function renderAlignmentGuides(ctx: CanvasRenderingContext2D, guides: AlignmentGuide[]): void;Gesture Recognition
The gesture system normalizes mouse, touch, and pen input:
class GestureRecognizer {
constructor();
process(event: PointerEvent): GestureTarget;
}
class MouseHandler { /* ... */ }
class TouchHandler { /* ... */ }
class PenHandler { /* ... */ }type GestureType = 'tap' | 'drag' | 'pinch' | 'longPress';
type GestureState = 'possible' | 'began' | 'changed' | 'ended' | 'cancelled';The PenHandler extracts additional pressure and tilt data from stylus input for pressure-sensitive drawing.