The guide
How this site
was made.
An honest write-up of the stack, the measurement method and the design decisions behind GLOWUP — specific enough that you could reproduce the approach this weekend.
01 — The stackTwo HTML files, no build step
GLOWUP is a static site: one index.html carrying all markup, CSS and JavaScript inline, plus this guide page. No framework, no bundler, no external dependencies at all — even the three typefaces are self-hosted woff2 files. It deploys to Cloudflare Pages by dragging a folder into the dashboard.
- Rendering: vanilla JS writing innerHTML into a handful of containers — the whole app is under 70 KB of markup, styles and script.
- State: five variables (selected aesthetic, quiz answers, the selfie canvas, the last reading, the chosen retailer). No store, no router.
- Privacy by architecture: there is no backend to send a photo to. The selfie is drawn onto a
<canvas>, read withgetImageData(), and discarded.
02 — The measurementSkin, read in CIELAB
The diagnostic converts skin pixels from sRGB to CIELAB, the color space used in dermatology, because distances there roughly match how humans perceive color difference. Two angles do the diagnostic work:
// Depth — the Individual Typology Angle (ITA°), // dermatology's standard for skin lightness: ita = atan2(L − 50, b) · 180/π // fair > 55° · light > 41° · medium > 28° · tan > 10° · deep ≤ 10° // Undertone — the hue angle in the a/b plane: hue = atan2(b, a) · 180/π // warm ≥ 54° · neutral 46–54° · cool ≤ 46°
Before measuring, pixels are filtered with a coarse skin-mask (red dominant over green over blue, enough chroma, enough warmth) so hair, background and clothing don't skew the average. The center crop of the photo (25–75% wide, 18–72% tall) biases sampling toward the face. Depth × undertone then indexes into a 9-season matrix — the classic seasonal color system — and into a Shade iD: the foundation family expressed in shopping language like "golden honey · caramel".
03 — The designEditorial warmth, lab precision
The visual language plays two registers against each other: a beauty-editorial voice and an instrument-panel voice, because the product itself is "taste, measured".
- Type: Instrument Serif (display, with true italics) for the editorial voice; Bricolage Grotesque for reading text; Spline Sans Mono for everything that sounds like a measurement — eyebrows, codes, diagnostic labels.
- Palette: warm shell pink (
#F6E7DF) instead of default cream, espresso-plum ink (#2B1017) instead of black, and a cherry accent (#B01E3C) doing all the pointing. Antique gold appears only on index numbers and the dark panels. - The 3D moment: the arched mirror tilts in real 3D perspective toward your cursor, with a specular glare that follows the pointer — CSS transforms driven by a dozen lines of JS. Disabled for touch devices and
prefers-reduced-motion. - The mirror: holds a generated editorial portrait until your selfie replaces it — the "before" state sells the register the way an empty dropzone never could.
- Texture: an inline SVG turbulence filter lays a subtle paper grain over the page; a rotating mono "seal" and a serif marquee of the six aesthetics keep the page from feeling templated.
04 — The assetsOne image, by budget
The performance budget came first: ≤ 1.5 MB total, LCP under 2 seconds on 4G. Exactly one raster asset earned its place: the editorial portrait inside the mirror, generated with Higgsfield's Soul model on a prompt written for the site's palette, then resized and compressed to a 24 KB WebP. Everything else is CSS gradients or inline SVG — the seal, the favicon, the grain — and the fonts are self-hosted woff2, so the whole page ships in roughly 250 KB with zero third-party requests.
The product edit is data, not images: a JSON catalog with a clean search term (q) per product and a per-retailer urls override, designed to be refreshed by an Apify scrape with exact product URLs. Until an override exists, links fall back to each retailer's public search on the clean term — never broken, never brand-paid.
05 — Reproduce itThe checklist
- Put every feature in one HTML file first; make it work, then make it beautiful.
- Do the color math on-device —
canvas → getImageData → CIELAB— and say so plainly; privacy is a feature you can architect, not just promise. - Pick two type voices with a real point of view and one accent color that does all the work.
- Write the structured data (
WebApplication+FAQPage) and mirror the FAQ visibly on the page. - Set the performance budget before designing, and cut assets — never the budget.
- Deploy as a static folder to Cloudflare Pages; iterate in three passes: design, conversion, performance.