SketchFlow
A freeform canvas drawing and whiteboard application with hand-drawn aesthetics

SketchFlow is a browser-based drawing tool that combines the charm of hand-drawn illustrations with the precision of digital tools. Inspired by Excalidraw, the goal was to build a whiteboard experience that feels natural and organic rather than sterile and mechanical.
The application uses Rough.js to render shapes with a sketchy, hand-drawn quality, and perfect-freehand to capture pressure-sensitive strokes from pen and touch input. The result is a drawing tool where even simple rectangles and arrows look like they were drawn by hand on paper.
Everything runs client-side in the browser using the Canvas API. There's no server component — drawings can be exported to PNG for sharing. The architecture is designed around a Zustand store with discriminated union types, making state management predictable and type-safe.
The rendering pipeline has two layers: a static canvas for committed elements and a dynamic canvas for the element currently being drawn. This dual-canvas approach means only the active stroke needs per-frame rendering, while the background canvas is only repainted when the element list changes.
Element state is managed through a Zustand store organized into slices, with elements stored in a Map keyed by ID for O(1) lookups. Each element uses a discriminated union type where the tool field determines which properties are available, making it impossible to access shape-specific data on a freehand element, or vice versa. Immer handles immutable updates inside the store, keeping mutation logic readable.
Pointer events are normalized across mouse, touch, and pen inputs using the Pointer Events API. For freehand strokes, raw pointer data is fed through perfect-freehand's algorithm, which outputs SVG path data rendered onto the canvas. Shape elements use Rough.js's generator to produce randomized path data that mimics hand drawing.