Color Analysis
Upload a portrait and get a personalized 12-season color analysis, palette, hair, and makeup direction, from Claude vision.
Seasonal color analysis is one of those things that's genuinely useful and almost impossible to get without paying a consultant. The advice is real (which colors make you look healthy versus washed out, what to do with your hair, how to approach makeup), but it's locked behind an appointment and a fair amount of jargon about undertones and contrast levels. I wanted to see how far a vision model could get on its own from a single photo.
Color Analysis is the answer. You drop in a portrait, the app sends it to Claude with vision, and you get back a structured read written against the 12-season system: a season, a wearable palette, hair direction, and optional makeup notes. Your photo goes to Claude for the read and isn't kept anywhere; there's no account, and the backend exists only to pass the image through and hand the result straight back.
The read
- Upload one photo or several: up to five, 10 MB each, JPEG, PNG or WebP. More than one and the prompt asks Claude to reconcile them into a single read rather than analysing each. A checkbox before you run it decides whether makeup advice comes back at all.
- Claude does the vision read: an Express server holds the uploads in memory, writes them to temp files, and spawns the Claude CLI in print mode with the
Readtool as its only permission, handing it the file path rather than an attachment. It gets 90 seconds before it is killed. - The answer is a fixed shape: the system prompt asks for raw JSON with ten top-level fields, and pins the counts. Exactly eight colors to wear and four to avoid, each with a name, a hex value and a sentence on why it works against your skin. Hair comes back as a face shape, three cuts, three color options and three styling notes. Accessories are a metal tone and three jewellery directions. Makeup, if you asked for it, is a foundation undertone, three eyeshadows, two lip colors and a blush.
- Two cards you can save: a colour card and a hair card, both exported as PNGs at triple pixel density. Fonts are self-hosted rather than loaded from a CDN specifically so the saved image keeps its typography.
- Your photo isn't kept: the temp files are deleted in a
finallyblock as soon as the CLI process closes, whether it succeeded or not. Results live only in your own browser's local storage, newest first, capped at thirty and trimmed further if the browser runs out of quota. Only the first photo of a set is kept with the result; the rest are dropped after the analysis.
What it does not do
The twelve seasons are a request, not a rule. The prompt names the 12-season system and gives four examples, but nothing in the code enumerates the seasons or checks the answer against them, so the season it returns is whatever Claude writes. Every hex value in the palette is generated by the model as well; no pixel of the photo is measured, and there is no ground truth anywhere in the project to score a read against. If the JSON comes back malformed the server reruns the whole analysis once, which doubles the wait rather than repairing the response. And no model is pinned: it runs on whatever the installed CLI defaults to, so the same photo can read differently a release later.
Running it
There is nothing hosted. It needs the Claude CLI installed and logged in on the machine running
the server, and npm run dev brings up the API on 3001 and the interface on 5173
together. Every request forks its own claude process with no queue and no rate
limit, and the analysis is billed to whoever's login is on that machine, which is the honest
reason there is no public demo. An optional Pexels key adds example photographs to the hairstyle
suggestions; without it, everything else still works.
Built with
React 19 · Vite 8 · TypeScript · Tailwind v4 on the frontend, with a single-file Express 5 server that drives the Claude CLI. Card export is html-to-image. No database, no auth, and the only test is a live end-to-end script that spends a real Claude call per case.