- docs/image-brief.md: one treatment for every image, keyed to the site palette - tools/images/treat.py: cutout (rembg) and treat (Pillow) as separate, re-runnable steps - tools/images/README.md: how to run it without polluting the NixOS python
3.6 KiB
Image brief
Every image on this site gets the same treatment. Consistency is what makes a set look designed; six images treated six ways look worse than six treated identically.
The palette is fixed by internal/web/static/site.css:
| Token | Value | Use |
|---|---|---|
--bg |
#0b0d10 |
canvas and fade colour. Never pure black |
--surface |
#12161b |
screenshot backgrounds |
--line |
#242c35 |
screenshot borders |
--line-strong |
#33404d |
diagram strokes |
--text-dim |
#b3bcc8 |
diagram labels |
--link |
#8ecbff |
rim glow |
--accent |
#6ee7c6 |
sparing emphasis only |
Why white-background product shots fail here
#FFFFFF on a #0b0d10 page is roughly twenty times the brightness of everything around
it. The brightest thing in the frame becomes the backdrop rather than the object, and the
eye lands on the backdrop first. One reads as an accident; six read as a scrapbook.
Photographs
- Canvas 1600×1000 for hero images, 1200×1200 for detail. Landscape unless the object demands otherwise.
- Background
#0b0d10, the page colour. Not black — pure black always looks like a void. - Subject cut out, placed right of centre, occupying 55–70% of the canvas height. Off-centre because the fade comes from the left.
- Fade a
#0b0d10gradient, 100% opacity at the left edge to 0% at about 55% across. The object emerges from the page and dissolves to the right. This is the move that stops an image looking pasted on. - Rim glow
#8ecbffat 25–40% opacity, 8–14px blur, derived from the cut-out's own alpha channel so it follows real edges. Enough to lift the object off the background. Not enough to look like a gaming mouse. - Shadow lift 5–8% on the subject itself. Cut-outs on dark backgrounds lose their dark detail and read as flat stickers otherwise.
- Format WebP, quality 82, plus a JPEG fallback. Target under 120 KB for a hero.
Screenshots
Never cut out. Frame them like the site's own panels:
- corner radius
10px(--radius) - 1px border in
--line - edges darkened 8%
- soft drop shadow
- crop out browser chrome where possible
Diagrams
Stay SVG and stay in the palette: --line-strong strokes, --text-dim labels, --accent
and --link for emphasis. No white fills, no default Mermaid blues.
Logos
One colour, inheriting currentColor from the surrounding text. Forty-six client logos in
full colour would shriek. If one deserves emphasis, give it --accent; the rest stay muted.
Prohibited
White boxes · stock photography · lens flares · 3D renders of objects not owned · glow strong enough to be the point · any image containing a family member, an address, a credential, or a screen showing personal data.
Capture guidance
Treatment rescues a product shot; it cannot rescue a photograph of a white wall in daylight.
- dark surface, one light source from one side
- shoot slightly above the object
- keep the object off-centre in frame
- no overhead lighting, no visible background clutter
- a phone is fine
Rack and cabinet shots are the exception: keep them whole and wide, framed like screenshots rather than cut out.
Output contract
Every image lands in content/assets/images/, named lowercase and hyphenated with no
spaces or dates. Every image used on a page carries a caption naming the object; a product
photograph additionally states that it is a product image and where it came from. The
original, if it is Sam's own photograph or a sourced product image, is also filed in the
repository of the project it belongs to, under docs/images/, with provenance recorded in
that folder's README.md.