PaintPlay

Project Case Study

PaintPlay

A free browser-based coloring app: upload an image, auto-generate line art, and paint with brush, eraser, and bucket fill. Built as a static Next.js export with hand-written Canvas 2D tooling, no login, no database, and no server.

View Live Project
Category
Web App / Creative Tool
Client
SERVITH (Internal product)
Type
Web App (PWA, Client-Only)
Role
Solo: line-extraction algorithm, canvas engine, tooling and brush design, PWA, and SEO content structure.
Goal
Turn any photo into something colorable and let anyone paint it in the browser, with no install, no account, and nothing uploaded.
Scope
18 static routes including the painting surface, themed coloring page galleries, tool guides, and policy pages.

Overview

PaintPlay is a free, browser-based coloring app. The hero states the whole workflow in one line: "Upload an image, auto-generate line art, and paint with brush, eraser, and bucket fill. Export your result as a PNG."

The architectural position is as important as the feature set: no login, no database, no server actions, no API routes. The entire app is a static Next.js export, and every image the user brings stays on their own device. Nothing is uploaded, because there is nowhere to upload it to.

The Design Constraint

A coloring tool for casual users and children has a short patience budget. Every step between "I have a picture" and "I am painting" is a place to lose someone. That produced three rules:

*

No account. The app opens straight into the tool.

*

No upload. Privacy is structural rather than promised — the architecture has no server to send an image to.

*

No leaking. Bucket fill must respect line art the user never drew, which is the hard part.

Technical Implementation

Stack

AreaImplementationNotes
FrameworkNext.js 16.1.1, output: 'export'Fully static; Turbopack builds
UIReact 19.1.0 + Tailwind CSS 4Only four runtime dependencies in total
StateNone (no library)Hand-rolled stores plus React hooks
GraphicsRaw HTML Canvas 2DNo canvas or image library
AudioWeb AudioBGM loop and click sounds
OfflineService worker + generated precacheRegistered client-side; offline fallback page

The dependency list is worth stating plainly: next, react, react-dom, and lucide-react. That is all of it. The drawing engine is written by hand.

Line extraction

Converting a photo into line art runs as pure JavaScript over ImageData — a configurable edge threshold plus a hand-written alpha dilation pass. No OpenCV, no WASM, no model call. It runs on the client, immediately, on whatever device the user already has.

Layered canvases

The painting surface composites separate canvases — source, line, paint, mask, and overlay. Separating them is what makes the tooling tractable:

*

Bucket fill floods against the thresholded and dilated line mask, so paint stops at the lines instead of leaking through antialiased gaps

*

Undo/redo is a capped history stack rather than a full-image snapshot per stroke

*

Export composites paint under the line layer, so strokes never smear the outline, and downloads locally as a PNG

Brushes with texture

Six presets — paint, marker, pencil, crayon, ink, and glow — implemented over pattern textures rather than plain strokes, so the output looks drawn rather than filled.

PWA

A generated precache manifest, a custom service worker, an offline page, and a fullscreen display mode. On a tablet it installs and behaves like a native coloring app, which is the device most of its users are actually holding.

Content structure for discovery

Beyond the tool itself, the app ships themed coloring page galleries with per-theme and per-page static routes, plus intent-targeted landing pages (photo-to-coloring, doodle-to-coloring, free-coloring, online-coloring) and guides. Static export means every one of them is prerendered HTML.

What This Case Study Demonstrates

*

Building real graphics tooling on the raw Canvas API instead of reaching for a library

*

Making privacy an architectural property rather than a policy paragraph

*

Solving the actual hard problem in a coloring app — fill containment against generated line art

*

Shipping an installable, offline-capable PWA from a static export

*

Keeping a dependency surface small enough to audit in one sitting


Live: https://paintplay.app/

Role: Solo delivery (line extraction → canvas engine → tooling → PWA → content/SEO)

PortalContact