075
LVL 03 — MID DEVELOPERSESSION 075DAY 75

DRAWING TOOL

🎫 PIXELCRAFT-062
Feature | 🟠 Hard | Priority: 🟠 High

Users want to draw directly on their images — annotations, doodles, signatures. Build a brush engine: freehand drawing with customizable color, size, opacity, and undo support.
CONCEPTS.UNLOCKED
🖊️
Canvas Paths
beginPath(), moveTo(), lineTo(), stroke(). A path is a series of connected points. Mouse down starts the path, mouse move draws it, mouse up ends it.
🌊
Bézier Curves
quadraticCurveTo() for smooth lines. Instead of straight segments between points, Bézier curves create smooth, natural-looking strokes. The secret to good drawing tools.
🎨
Compositing
globalCompositeOperation controls blending. 'source-over' draws on top. 'destination-out' erases. 'multiply' darkens. 12 blend modes — same as Photoshop.
🖌️
Brush Engine
Size, opacity, color, smoothing. The brush engine combines lineWidth, strokeStyle, globalAlpha, and lineCap:'round' to simulate real brushes.
🖱️
Mouse Event Tracking
mousedown, mousemove, mouseup. Track the pointer position relative to the canvas. getClientBoundingRect() converts page coordinates to canvas coordinates.
↩️
Undo with Snapshots
Save canvas state before each stroke. getImageData() captures the pixel data. Undo = restore the previous snapshot with putImageData(). Simple and reliable.
HANDS-ON.TASKS
01
Basic Freehand Drawing
function useDrawing(canvasRef) { const [isDrawing, setIsDrawing] = useState(false); const getPos = (e) => { const rect = canvasRef.current .getBoundingClientRect(); return { x: e.clientX - rect.left, y: e.clientY - rect.top }; }; const startStroke = (e) => { const ctx = canvasRef.current .getContext('2d'); const { x, y } = getPos(e); ctx.beginPath(); ctx.moveTo(x, y); setIsDrawing(true); }; const draw = (e) => { if (!isDrawing) return; const ctx = canvasRef.current .getContext('2d'); const { x, y } = getPos(e); ctx.lineTo(x, y); ctx.stroke(); }; const endStroke = () => { setIsDrawing(false); }; return { startStroke, draw, endStroke }; }
02
Smooth Bézier Curves
// Instead of lineTo (jagged), // use quadraticCurveTo (smooth) let lastPoint = null; function drawSmooth(ctx, newPoint) { if (!lastPoint) { lastPoint = newPoint; return; } // Midpoint between last and current const mid = { x: (lastPoint.x + newPoint.x) / 2, y: (lastPoint.y + newPoint.y) / 2 }; // Curve from last point through // midpoint to current ctx.quadraticCurveTo( lastPoint.x, lastPoint.y, mid.x, mid.y ); ctx.stroke(); lastPoint = newPoint; }
The difference is dramatic. lineTo creates jagged angles between points. quadraticCurveTo creates buttery smooth curves — the secret behind every professional drawing app.
03
Brush Engine: Size, Color, Opacity
function configureBrush(ctx, settings) { ctx.lineWidth = settings.size; ctx.strokeStyle = settings.color; ctx.globalAlpha = settings.opacity; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; } // Eraser = draw with composite mode function setEraser(ctx, size) { ctx.globalCompositeOperation = 'destination-out'; ctx.lineWidth = size; } // Reset to normal drawing function setBrush(ctx) { ctx.globalCompositeOperation = 'source-over'; }
04
Undo/Redo with Canvas Snapshots
const history = []; let historyIndex = -1; function saveSnapshot(canvas) { const ctx = canvas.getContext('2d'); const snapshot = ctx.getImageData( 0, 0, canvas.width, canvas.height); // Remove any "future" states history.splice(historyIndex + 1); history.push(snapshot); historyIndex++; } function undo(canvas) { if (historyIndex <= 0) return; historyIndex--; const ctx = canvas.getContext('2d'); ctx.putImageData( history[historyIndex], 0, 0); } function redo(canvas) { if (historyIndex >= history.length - 1) return; historyIndex++; const ctx = canvas.getContext('2d'); ctx.putImageData( history[historyIndex], 0, 0); }
05
Close the Ticket
git switch -c feature/PIXELCRAFT-062-drawing-tool git add src/ git commit -m "Add freehand drawing with brush engine + undo (PIXELCRAFT-062)" git push origin feature/PIXELCRAFT-062-drawing-tool # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

Bézier curves are everywhere in computing.

Invented by Pierre Bézier for car body design at Renault (1962). Now they're in every font, every vector graphic, every animation curve.

// Bézier curves by degree:

Linear (2 points)
  A straight line. lerp(P0, P1, t)

Quadratic (3 points)
  One control point. Smooth curves.
  Canvas: quadraticCurveTo()

Cubic (4 points)
  Two control points. S-curves.
  Canvas: bezierCurveTo()
  CSS: cubic-bezier() for animations
  Fonts: every glyph is cubic Béziers

// The math: recursive interpolation.
// De Casteljau's algorithm: subdivide
// until you reach a point on the curve.
"Drawing Lab"
[A]Add pressure sensitivity: if the browser supports PointerEvent.pressure (stylus/tablet), vary brush width based on pressure. pointerdown/pointermove instead of mouse events.
[B]Add shape tools: hold Shift while drawing to constrain to straight lines. Add rectangle and ellipse tools using Canvas rect() and arc(). Preview the shape while dragging.
[C]Research: how does Procreate handle drawing? What is "stroke stabilization"? Implement a simple version: average the last 5 mouse positions to smooth out jittery input.
REF.MATERIAL
ARTICLE
MDN Web Docs
Paths, arcs, Bézier curves, rectangles. The complete guide to drawing on Canvas. Start here for Canvas fundamentals.
CANVASMDNESSENTIAL
VIDEO
Freya Holmér
The most beautiful math video on YouTube. Visualizes Bézier curves from first principles — interpolation, De Casteljau, and why they're everywhere.
BÉZIERVISUALESSENTIAL
ARTICLE
MDN Web Docs
All 12 compositing modes visualized. source-over, destination-out, multiply, screen — the Canvas equivalent of Photoshop blend modes.
COMPOSITINGMDN
VIDEO
Dev Ed
Practical Canvas drawing tutorial: brush, color picker, size slider, and eraser. Build a functional drawing app step by step.
CANVASTUTORIAL
ARTICLE
Wikipedia
The mathematics, history, and applications of Bézier curves. From car body design at Renault to every font and vector graphic in computing.
BÉZIERTHEORYCS
// LEAVE EXCITED BECAUSE
You built a real drawing tool. Pick a color, choose brush size, draw on the canvas — smooth Bézier curves, not jagged lines. Undo works for every stroke. This is how Photoshop started.