Frontend tooling case study

Web Paint

No-build Canvas editor with pencil, eraser, fill, shapes, text, selection, undo/redo, PNG import/export, local save, zoom, fullscreen, and responsive controls.

Project type
Canvas drawing editor
Status
Live tool / frontend prototype / case study
Stack
HTML Canvas, vanilla JavaScript, CSS Grid
Role
Solo builder: UI, drawing engine, state, import/export
Last updated
May 2026

Quick summary

Web Paint in 30 seconds.

Frontend state, Canvas tools, browser interaction, and static app polish.

What this proves

Canvas state, pointer input, undo/redo, import/export, and no-build UI.

Core technical work

Canvas tools, pointer capture, tool/color/brush state, capped history, flood fill, file validation, PNG export, localStorage, and mobile controls.

Best path

Open the tool, then scan state, history, import/export, input, and testing.

Known limits

No layers, autosave recovery, full shortcuts, pixel regression tests, memory-aware history, or semantic canvas model.

Try this demo

Try this in 2 minutes.

Runs in the browser. These steps exercise state, pointer input, history, files, and responsive controls.

  1. Draw.Pick Pencil, color, and size.
  2. Add shape or text.Place it from the toolbar.
  3. Use undo/redo.Verify history and toolbar state.
  4. Try files.Open, save, copy/cut, and local save/load.
Web Paint browser canvas tool showing toolbar commands, brush controls, keyboard and touch guidance, and drawing workspace
Toolbar state, Canvas workspace, guidance, and local file controls.

Visual proof

The tool is a working canvas editor.

The screenshot is the live browser UI: toolbar, canvas, status bar, and guide.

What to notice

  • Tools, sizes, shapes, colors, sizing, zoom, and files live in one toolbar.
  • The canvas keeps a stable workspace for input, selection, resize, and undo/redo.
  • Browser APIs handle import, export, clipboard, fullscreen, and storage.

TL;DR

Web Paint in 15 seconds.

Problem
Drawing tools need reliable state, history, imports, and resizing.
Built
No-build Canvas editor with drawing tools, undo/redo, import/export, local save, zoom, fullscreen, and mobile panels.
Stack
HTML, CSS, JavaScript, Canvas 2D, Pointer Events, Clipboard, File APIs, LocalStorage, GitHub Pages.
Demo
Live Web Paint tool running entirely in the browser.
Source
paint.js and paint.css
Result
Working editor with predictable state, capped history, PNG export, localStorage save/load, and responsive controls.
Current limitation
No layers, autosave recovery, full shortcuts, pixel regression tests, or semantic canvas representation.

01 / Project summary

A real canvas tool.

Web Paint uses Canvas 2D, vanilla JavaScript state, pointer events, flood fill, capped history, PNG import/export, localStorage, resizing, zoom, and responsive controls.

Technical problem

Canvas tools must coordinate pixels, tool state, pointer input, history, imports, exports, zoom, and resizing.

Constraints

No framework or backend; browser APIs handle files, storage, clipboard, and fullscreen.

Approach

I used vanilla JS state, Canvas paths, pointer capture, typed-array flood fill, and capped snapshots.

Tradeoff

ImageData history is simple, but memory-heavy on large canvases.

Next improvement

Next: command/dirty-region history, workers, selection movement, shortcuts, and nonvisual output.

What it demonstrates: DOM wiring, events, state, Canvas APIs, storage, clipboard, file validation, mobile layout, and nonvisual tradeoffs.

Why this matters

It makes browser drawing usable.

Tool problem

Drawing tasks need predictable tools, undo/redo, import, export, zoom, and mobile controls.

Useful approach

Canvas 2D, pointer events, bounded history, and browser file/clipboard/storage APIs avoid a backend.

Employer signal

Shows state modeling, DOM events, browser APIs, performance tradeoffs, mobile layout, and labels.

Production readiness

Works now; larger documents need more.

Already solid

Working modes, pointer input, undo/redo, import/export, local save/load, zoom, resizing, status, and responsive panels.

Prototype-only

History uses full snapshots. No semantic model, layers, document names, or full shortcuts.

Next engineering work

Larger editor needs memory-aware history, autosave, selection movement, shortcuts, workers, tests, and nonvisual descriptions.

Security and privacy

Drawings stay local. Cloud save would need validation, privacy controls, retention rules, upload limits, and abuse handling.

02 / What I built

Editor surface and interaction model.

  • Implemented pencil, eraser, shapes, fill, text, selection, and previews.
  • Built undo/redo, import validation, PNG export, local save/load, zoom, and resizing.
  • Managed tool settings, colors, brush size, shapes, selection, drafts, pointer capture, and status in vanilla JS.
  • Added paste, copy, cut, fullscreen, canvas sizing, mobile panels, and mobile guidance.
  • Added guardrails for MIME type, size, pixels, canvas dimensions, animation-frame drawing, and history limits.

Uses browser APIs: Canvas 2D, File, Clipboard, Fullscreen, object URLs, and LocalStorage. Logic/UI are vanilla JavaScript.

03 / Tool list

Features map to drawing tasks.

Primary Web Paint controls and implementation responsibilities.
Area Tools Implementation detail
Drawing Pencil, brush, eraser, text, fill bucket. Pointer events convert screen coordinates to canvas coordinates; brush settings map to stroke style.
Shapes Line, rectangle, rounded rectangle, circle, triangle, right triangle, star, polygon. Saved draft image previews drag geometry before commit.
Color and size Palette swatches, active color preview, 2px, 6px, 12px, and 20px brush controls. Buttons update shared state and active classes.
Canvas operations New canvas, erase canvas, width/height controls, drag resize handle, zoom, fullscreen. Dimensions clamp from 64 to 4096; resize preserves overlapping pixels and resets history.
File and clipboard Open image, paste image/text, copy selection, cut selection, save PNG, local save. File APIs, ClipboardItem, object URLs, blobs, LocalStorage, and PNG URLs power open, paste, copy, export, and save.

04 / Canvas rendering model

Pointer input becomes canvas drawing.

Web Paint canvas editor architecture diagram Toolbar controls update a shared JavaScript state object. Pointer and touch events use that state to draw on the Canvas 2D surface. Canvas pixels feed undo history, import and export flows, browser storage, and status updates. TOOLBAR Controls Tool, color, size STATE Editor model Tool + draft data INPUT Pointer events Mouse, pen, touch CANVAS 2D Pixel renderer Strokes, fill, text IMPORT Files / paste Validate and fit HISTORY ImageData stack Undo and redo EXPORT Browser APIs PNG / local save
Control state, pointer handling, rendering, history, and import/export flows stay separate.
  1. Capture pointer pointerdown captures the pointer and start coordinate.
  2. Pick behavior by tool Fill, text, selection, freehand, and shapes use separate paths.
  3. Render freehand strokes Pencil, brush, and eraser draw segments with current brush settings.
  4. Preview shapes from a draft Shapes restore a draft during drag, then render current geometry.
  5. Commit a history snapshot On release, final pixels enter bounded undo history.

Pointer movement is throttled with requestAnimationFrame so high-frequency input stays fluid.

05 / Tool state management

A focused state object coordinates the editor.

Active mode

activeTool and activeShape choose freehand, fill, text, selection, or shape preview.

Drawing session

Drawing fields separate live drag from committed canvas state.

Selection and view

Selection, zoom, and cached rectangles support overlays, clipboard, and scaled coordinates.

Canvas pixels are the image source of truth; JavaScript state describes the current interaction.

Selecting a tool updates shared state, clears selection, and syncs controls.
function setTool(tool) {
  if (tool !== "select") clearSelection();
  state.activeTool = tool;
  state.activeShape = "";
  toolStatus.textContent = `Tool: ${titleCase(tool)}`;
  syncActiveControls();
}

Bridge between DOM toolbar and canvas handlers.

06 / Undo and redo strategy

History stores bounded ImageData snapshots.

Undo/redo use ImageData snapshots and a history index. New edits discard redo states, save latest pixels, and cap history at 24 snapshots.

The model is simple but memory-heavy on large canvases. Production would use commands, dirty regions, compression, or workers.

Undo/redo use committed pixel snapshots; new edits discard redo states.
function saveHistory() {
  state.history = state.history.slice(0, state.historyIndex + 1);
  state.history.push(context.getImageData(0, 0, canvas.width, canvas.height));
  if (state.history.length > maxHistory) state.history.shift();
  state.historyIndex = state.history.length - 1;
}

function restoreHistory(index) {
  const snapshot = state.history[index];
  if (!snapshot) return;
  context.putImageData(snapshot, 0, 0);
}

Simple snapshot model with a clear memory tradeoff.

07 / Import and export flow

Browser APIs replace a backend.

  1. Open image Validate MIME type and size before loading through an object URL.
  2. Validate dimensions Reject missing dimensions or images over 48 million pixels.
  3. Fit to canvas Scale to fit, preserve aspect ratio, center, then commit history.
  4. Clipboard flow Copy/cut export canvas or selection with clipboard and download fallback.
  5. Export and local save Save downloads PNG; local save stores a PNG data URL in localStorage.

08 / Keyboard, mouse, and touch

Pointer events keep input device-agnostic.

Mouse and pen

Pointer capture and canvas-space coordinates keep drag behavior stable.

Touch devices

touch-action: none prevents drawing gestures from becoming page scrolls.

Keyboard access

Native buttons and inputs support keyboard use; richer shortcuts remain future work.

09 / Nonvisual limits and improvements

Keyboard shell; visual canvas.

The interface uses semantic buttons, labels, focus states, ARIA labels, and toolbar groups. Canvas content remains visual pixel data.

Current support

Buttons and inputs focus, tool groups are labeled, swatches announce value, and selection/resize controls are named.

Known limitations

No semantic drawing model, full keyboard drawing commands, or inline text tool yet.

Next improvements

Add shortcuts, command palette, stronger status, high-contrast toolbar, and text descriptions.

10 / Performance considerations

Large canvases drive the constraints.

Web Paint clamps canvases to 4096x4096, caps imports, uses typed-array flood fill, schedules resize previews with requestAnimationFrame, and limits history.

The main limit is full ImageData history. Production would add memory-aware limits, workers, region invalidation, import feedback, and low-memory mobile handling.

11 / Testing and QA notes

QA focuses on state, APIs, and mobile input.

Automated tests

No automated suite yet. Manual checks cover tools, state transitions, import/export, and responsive controls.

Manual checklist

Check tools, previews, undo/redo, reset, resize, zoom, fullscreen, import, paste, copy/cut, export, local save/load, and status.

Browser and device checks

Test mouse/keyboard, touch, tablet widths, high-DPI, clipboard, fullscreen, focus, and reduced motion.

Edge cases

Exercise invalid files, huge images, blocked clipboard, missing LocalStorage, canvas limits, mid-drag switches, empty selections, and history limits.

Known limitations

No regression tests yet for pixels, pointer sequences, memory pressure, cross-browser clipboard, or nonvisual canvas content.

12 / Deployment and run notes

Runs as a browser tool.

Hosted/run location

Hosted on GitHub Pages at zacbatten.me/paint.html. HTML, CSS, and paint.js; no backend.

Environment/config

No env vars. Settings and local saves use browser state; imports stay in the active session.

External APIs/services

No external drawing APIs. Uses Canvas 2D, Pointer Events, File, Clipboard, Fullscreen, object URLs, and LocalStorage.

Local development

Run python -m http.server 8000, then open /paint.html. A local server avoids file:// quirks.

Secrets and privacy

No uploads or secrets. Cloud save would need auth, upload validation, quotas, retention rules, and privacy controls.

13 / Screenshot

Live browser-tool screenshot.

14 / What I would improve next

Next editor improvements.

  • Add shortcuts for undo, redo, save, tools, zoom, and canvas movement.
  • Move and resize selected regions.
  • Replace prompt text with inline editable text.
  • Add autosave/reopen and document names.
  • Improve large-canvas memory with region or command history.

Next step

Try the tool, then compare.

Web Paint shows browser UI and Canvas mechanics. TraverseOps and MovieBot show maps and Python automation.