The Weekly App→
Meal-kit POC that turns Coles recipes into a consolidated trolley.
Refinement of v3 based on three pieces of feedback. (1) Visual types were drifting in size and padding — numeral felt huge, monogram felt cramped, icon sat somewhere in the middle. Fixed by a shared shell across centred types, so numeral / icon / monogram are now sibling sizes in the same frame. (2) Text marks were using royal-10 / violet-10, which lost the weight of the original gradient. Moved to royal-8 / violet-8 — the exact anchor shades from the gradient — so text marks keep that deeper, saturated presence without being the gradient. (3) Monogram was in Geist Mono which clashed with Fraunces numerals — unified on Fraunces so they read as sibling typographic marks.
Also in this pass: the screenshot auto-tint is deepened (opacity 0.55 → 0.9) so it locks fully to the card's register colour instead of bleeding source hues through. And the mobile-screenshot section gains a combined M5 + M6 exploration — my read is yes, use both, with rules for hierarchy.
Each pair shows a work card (royal) beside a writing card (violet). The strip is 160px tall, spanning full card width. Content below is identical across pairs so the only thing that varies is the imagery treatment. Same hover state across all six: background lift + border change to the card's register colour. No per-type one-offs.
mix-blend-mode: color. Author drops in any screenshot, component forces it into palette.Meal-kit POC that turns Coles recipes into a consolidated trolley.
Why every portfolio image should be captured at render time, never baked in.
GTD planner with persistent SMS, four-layer spend protection, and a killswitch that works.
Convention-based spend discipline fails under pressure. Structural choke points don't.
When no screenshot or diagram fits the brief, the numeral carries the card on typography alone.
Writing-register numeral in violet only — never the gradient. Pure register signal, no dilution.
Tokens-first architecture applied across three projects. Gradient-mark carries the abstract weight.
When the content IS the palette — gradient-mark is the only imagery that makes sense here.
Quarter-by-quarter breakdown of a two-year B2B sales cycle from raw Salesforce exports.
The posts that forced me to understand what I was actually claiming about the systems I was building.
Short-code lockup — the fallback when diagram and screenshot both feel forced.
Monogram in violet only. Good for index pages where many cards need to feel like siblings.
v2 rendered the numeral with background: var(--grad-rv); -webkit-background-clip: text. That looked great on a single card. It looked muddy on a 2×2 grid because every text mark became the same gradient, regardless of whether the card was work or writing. The register split collapsed into visual noise.
The rule now: text marks inherit the card's register colour. Work gets royal-10. Writing gets violet-10. Nothing in between. The gradient still exists — it lives on the gradient-mark type and on featured card borders (see v2 §4) — but it doesn't leak into every card that happens to use a numeral.
Gradient fill. Pretty in isolation; works against register signal in context.
Writing card — but the gradient is indistinguishable from the work card on the left.
Royal-10 numeral — same colour family as the kicker and the arrow. The card reads as one thing.
Violet-10 numeral. The writing register is now carried by three coordinated signals, not one gradient.
Layout A's strip is ~420px × 160px on a 2×2 landing grid (~2.6:1). A mobile screenshot is ~390 × 844 (~1:2.16). The strip is about six times wider than tall, relative to the phone. Cover-cropping shows ~18% of the screen; contain-sizing leaves a 72×156 phone floating in a sea of padding. Neither reads as intentional.
Six options below, each rendered as a real strip so you can judge them directly. Same fake phone markup in all of them — the only variable is how it's placed inside the frame.
Feels fine in isolation. Weakness: the phone looks cut off, not framed.
M2 — the phone is honest about being a phone. Reads as "here is the product".
Weakness: the phone is small — UI detail reads as "something" but not "this specific thing".
M3 — the tilt converts "cropped phone" into "composed phone". Most editorial.
Weakness: applies one "art direction" gesture per card — starts to feel like a trick if every work card uses it.
M4 — good for products with a two-screen story. Overkill for single-screen apps.
Weakness: requires two screens that pair cleanly. The author has to do art direction, not just capture.
M5 — strongest editorial feel. Meta label anchors the card, phone supplies proof.
Weakness: the numeral now duplicates the kicker number. Redundant if both are shown.
M6 — doesn't pretend to show the whole app. Shows the exact moment the card is about.
Weakness: requires a crop decision per card. No automatic answer from "here's the screenshot".
| Option | Author effort | Honest to UI | Grid rhythm | Read |
|---|---|---|---|---|
| M1 · Top slice | low | partial | clean | Safe default. Reads as "cut off" when the app bar isn't load-bearing. |
| M2 · Contained | none | yes | clean | Honest but tiny. UI detail disappears at grid scale. |
| M3 · Tilted bleed | medium | partial | clean | Best balance. Composition signals "this is a product shot", phone reads as intentional. |
| M4 · Dual cascade | high | yes | mixed | Great for two-screen stories, heavy otherwise. Save for hero cards. |
| M5 · Meta split | medium | yes | mixed | Strong editorial feel, but duplicates kicker number if the meta shows the same digit. |
| M6 · Detail zoom | high | yes | clean | Highest craft ceiling, highest author cost — requires a crop decision per card. |
Your question: can we use both M5 and M6 for visual variety, or is that too busy? My view: yes, use both, but with rules. The risk isn't visual busy-ness — both compositions are clean. The risk is that both want to be the standout card, so putting them next to each other without intention flattens the hierarchy they're supposed to create.
M5 anchors this card as the first piece in a sequence — the big 01 carries the ordering.
M6 pulls a specific UI detail — the trolley list — into focus without pretending to show the whole app.
Anchor card — M5 signals "start here" without needing a featured border.
Secondary card — detail zoom points at the trolley consolidation feature.
Secondary card — detail zoom points at the quarterly breakdown table.
Secondary card — detail zoom points at the token playground.
/work and /writing index pages where every card is part of one flat list, skip M5 entirely and use M6 throughout. The point of M5 is that it anchors one card — if there's no obvious "first" card in the list, M5 has nothing to anchor and the numbers become noise. Restrict M5 to the landing grid (four cards, one featured) and the related-work footer inside case studies (where the current case study is the anchor by absence).
Lock Layout A (top third strip, content below) as the card spec. All six visual types render cleanly at sibling sizing in the shared centred-mark shell, and the content-below pattern is the most familiar scan order.
Adopt the deep text-mark colour rule: numerals and monograms use royal-8 for work and violet-8 for writing — the exact anchor shades of the original gradient. Text marks keep the weight the gradient gave them without collapsing register differentiation. Monogram moves to Fraunces so it reads as a sibling of the numeral.
Adopt the deep screenshot tint: mix-blend-mode: color at opacity: 0.9, background royal-8 / violet-8. Any source image is pulled fully into the card's register colour with no gradient bleed-through. Author effort stays at zero.
For mobile screenshots, combine M5 (meta split) + M6 (UI detail zoom) with a single hierarchy rule: "Max one M5 per grid, M6 for the rest." On /work and /writing index pages, use M6 only — M5 anchors the landing grid and related-work footer, nowhere else.
Open questions still to resolve:
image.kind sub-types in the Card props API, or do they live as capture-time decisions in the imagery standards doc? Sub-typing in TS makes misuse harder — but it also bakes the M5/M6 split into the component surface, which is harder to evolve. My lean is no sub-types: keep the Card API simple (kind: "screenshot") and handle M5/M6 composition in the <Screenshot> helper component instead. That keeps the presentation decision in one place and the Card component focused on layout.