SketchFlow

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

RoleLead Developer
TypeCreative Tool
StackReact / Canvas API / Rough.js
StatusActive
01Overview

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 an immutable element state, making undo/redo trivial to implement.

02Key Features
Hand-Drawn Shapes
Rough.js renders rectangles, ellipses, lines, and arrows with a natural hand-drawn style that gives diagrams personality.
Pressure-Sensitive Drawing
perfect-freehand converts pointer input into smooth, variable-width strokes that respond to pen pressure and velocity.
Undo / Redo
Full history stack with keyboard shortcuts. Every action is reversible, supporting both element creation and property changes.
PNG Export
Export the canvas to a high-resolution PNG file with transparent or white background options for easy sharing.
Tool Palette
Selection, freehand, rectangle, ellipse, line, arrow, and eraser tools with customizable stroke color and width.
Infinite Canvas
Pan and zoom across an unbounded canvas with smooth transitions, supporting both mouse wheel and trackpad gestures.
03Technical Architecture

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 stored as an immutable array. Each user action produces a new array reference pushed onto a history stack. Undo pops the stack and restores the previous state; redo re-applies from a parallel redo stack. This pattern eliminates complex mutation tracking.

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.

04Tech Stack
ReactUI framework
TypeScriptType safety
ViteBuild tool
Rough.jsHand-drawn rendering
perfect-freehandStroke smoothing
Canvas API2D rendering
Pointer EventsInput handling
ESLintCode quality