A website aimed at miniature painting hobbyists. Featuring a database of miniature paints with hex colour values — searchable, filterable, and able to find visually similar colours across brands. Plus the ability to design and visualise a miniature's colour scheme, using the database to pick paints and preview how they read together. Optional user accounts let you save your schemes, sync them across devices, and share them by link.
- Searchable, filterable database of 4,900+ paints across 11 brands — Citadel, Vallejo, AK Interactive, The Army Painter, Duncan Rhodes, Green Stuff World, Liquitex, Mig, P3, Scale 75 and Tamiya. Filter by brand, product range, finish type, colour family and metallic finish.
- Perceptual colour matching. Every paint page lists the closest colours ranked by CIEDE2000 (ΔE) — the industry-standard perceptual colour distance — with filters to narrow the matches by brand, product range, finish type, metallic finish and whether to include discontinued paints. Those are the same filters as the main database page, and they carry between the two. Great for comparing paints across brands.
- Alternatives plot. The same matches, arranged spatially instead of as a ranked list: the paint you're on sits at the centre and every alternative is placed by how it differs from it — hue shift across, lightness up. So when you want something slightly different to the paint you have, you can see which way each option moves rather than just how close it is. For greys and other near-neutrals, where a hue angle carries no real information, the horizontal axis switches to saturation. Marks are keyboard-navigable in ΔE order, and the plot always reports what it couldn't fit. Filters stay applied as you click through — narrow to a brand and you can explore that whole range swatch by swatch, and the same filters carry between the full list and an individual paint in both directions, so nothing is lost on the round trip. They live in the URL, so a filtered view is a shareable link.
- Paint scheme visualiser. Plan a miniature's colour scheme on
/visualiser: Group your paints by element (armour, robes, lenses, etc) and preview every element's colours as aligned, optionally-blended vertical bars. Paints carry a role (base, layer, highlight, drybrush, wash, glaze, weathering) and a weight; each element's bar is sized by its order — largest-area element first. Search the database to add a paint or enter a custom name + hex. Schemes autosave in your browser and export/import as JSON — or sync to your account when signed in. - Example schemes. The homepage carousels through a few real, recognisable schemes — rendered by the same component the visualiser uses, not a mock-up — and any of them opens straight into the designer to tweak. Each stores catalogue paint ids rather than colours, so a hex correction in the paint data updates the examples automatically.
- Accounts (optional). Sign in with Google to sync your saved schemes across
devices; without an account, schemes save to your browser. A My schemes
page (
/my-schemes) manages your schemes — rename, duplicate, delete and share. A placeholder My paints page (/my-paints) marks where owned-paint inventories will go. - Shareable scheme links. Publish any saved scheme to an unguessable
/scheme/<slug>link that anyone can open — no login — to see the visual and the full paint recipe, with a rich colour preview when pasted on social sites. Signed-in viewers can save a copy to their own account. - Share images. Turn a scheme plus a photo of your model into a 4:5 PNG for social media: drop a marker on each part of the model and it gets a callout with that element's colour ramp and paint names, joined by a leader line. Frame the photo, add your handle, and optionally show manufacturers and roles.
- Light & dark mode, following your system preference.
- Responsive desktop and mobile layouts.
- Plain-JSON data. The paint database is plain JSON, one file per brand.
Intended to be easy to maintain and update. See
data/paints/README.mdfor the schema andCONTRIBUTING.mdfor the workflow.
- Next.js (App Router) + TypeScript, statically generated
- Tailwind CSS v4
- next-themes for theming
- zod for data validation
- Vitest for unit tests
- Supabase for optional accounts (sign-in + saved schemes), called directly from the browser
- Hosted on Vercel
The core site (paint database, matching, visualiser) needs no backend — it's statically generated and the paint data ships in the repo. Accounts are optional: the browser talks to Supabase directly, so the site stays static and free to host.
The project targets Node 24 (the version CI runs — see .nvmrc).
With nvm or
fnm, run nvm use to switch to it.
nvm use # select Node 24 (optional, if you use nvm/fnm)
npm ci # clean, reproducible install from package-lock.json
npm run dev # http://localhost:3000Use npm ci for setup: it installs exactly what's in package-lock.json and
never rewrites it. Reach for npm install only when you're intentionally adding
or updating a dependency (commit the resulting package.json and
package-lock.json together).
| Command | Description |
|---|---|
npm run dev |
Start the dev server |
npm run build |
Production build (statically generates every paint page) |
npm run lint |
ESLint |
npm run test |
Unit and component tests (colour maths, filtering, plot layout, URL state, schemes) |
npm run validate:data |
Validate data/paints/*.json against the schema |
npm run build:index |
Precompute the browse index + similar-colour lists (runs automatically before dev/build) |
npm run import:source |
(Re)import paint data from the upstream dataset |
This is a standard Next.js project that deploys with zero configuration — nothing to configure for the core site, and no server to keep warm since everything is static. The public instance at paintdex.app is hosted on Vercel, but any host that runs Next.js — or serves a static export — works just as well.
The paint database lives in data/paints/ as one JSON file per
brand. Edits are just JSON: see data/paints/README.md
for the schema and CONTRIBUTING.md for the workflow.
Corrections and additions are welcome via pull request. npm run validate:data
checks changes, and CI runs it on every PR.
The initial paint data was imported from the MIT-licensed
Arcturus5404/miniature-paints
dataset (© 2022 Rick Fleuren / the Miniature Painter Pro team). Hex values are
best-effort and community-correctable. See
data/paints/README.md for details.
Paintdex is not affiliated with or endorsed by Games Workshop, Vallejo, AK Interactive, The Army Painter, Duncan Rhodes, Green Stuff World, Liquitex, AMMO by Mig Jimenez, Privateer Press, Scale 75, Tamiya, or any paint manufacturer. Brand and product names are trademarks of their respective owners.
Ideas for future features.
Generating a labelled share image has shipped — see Share images above. What is left of that idea:
- Store the uploaded photo against the scheme (Supabase Storage) rather than
in the browser only, so it follows you across devices and can appear on
the public
/scheme/<slug>page. - More aspect ratios for the share image — 1:1 for a square feed post, 9:16 for stories. It is 4:5 only today.
- Add more paint brands and ranges
- If the catalogue grows a lot, revisit how the browse index is delivered.
public/browse-index.jsonis a single file covering the whole catalogue (~1MB uncompressed at 4,961 paints, well compressed on the wire) and it's fetched by four views: browse, the homepage search, the visualiser's paint picker and the alternatives panel. Both the download and the client-side CIEDE2000 re-rank scale linearly with the catalogue, so adding brands in bulk is what would make this bite. Not a current problem — Core Web Vitals are fine, and this is a note for later, not a todo. When it does matter, the options are roughly: drop fields the client never reads, split the index (by brand, or a small search subset plus on-demand detail), or move the parse and the ΔE pass into a Web Worker so they stop touching the main thread. Each trades away some of the current "one static file, no backend" simplicity, so it wants measuring first. Per-page derived work is already memoized at module scope (src/lib/paints/browse-index.ts,lab-index.ts) — that part is done. - Interactive colour wheel (à la
Canva's colour wheel) that
suggests matching paints based on colours you pick. Would be useful if
you're looking to design custom schemes with colours that work well
together. Could also be a different way to visualise colour schemes in
/visualise. The LCh helpers insrc/lib/color(labToLch,hueDelta) are the reusable part of the alternatives plot for this — but note the wheel wants absolute polar hue/chroma over the whole catalogue, not one paint's ΔE neighbourhood, so it needs its own scales rather thanscatter.ts's. - Hue and luminance relationships between paints — shipped as the
alternatives plot on each paint page (see Features above). Still open:
the same treatment for the whole catalogue on
/paints, which needs a different axis model (absolute rather than relative to one paint) and has to cope with ~4,900 points instead of ~120.
- Save the paints you own
- Paint schemes can suggest only paints from your collection
- Wishlist for paints you don't own yet but want to buy