Nº 268 of 520
Hero with a live browser card
A SaaS hero: marker-highlighted headline, hard-shadow buttons, and a browser mockup whose schedule card ticks up, adds a post and pops a toast every 4.2s.
Preview
Use it
Free to use · credit appreciated1 Once, in your project
npx skills add SusanAcharya/Design-Lounge 2 Then ask
Using the Design Lounge skill, build "Hero with a live browser card" (piece hero-live-browser-card) in my stack. Match its brief; restyle it onto my product's theme.
No skill? Paste the brief instead. It carries the numbers, tokens and behaviour.
<!-- Design Lounge Nº 268 · "Hero with a live browser card" · www.designlounge.live -->
# Hero with a live browser card
> **Build brief for a coding agent.** Rebuild this piece in the reader's stack. If they haven't said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don't "improve" them. When a kit is locked, map colours onto the kit tokens and keep the hard 0-blur shadows.
## What it is
Studied from usearticle.com: the first screen, where the product is shown working inside a drawn browser window instead of as a static screenshot. This version is Ovenlight, a fictional service that publishes a recipe blog on a schedule. Left: a green live badge, a 64px headline with "cooking itself." in cobalt on a yellow marker stripe, a lede, two big hard-shadow buttons and three feature chips. Right: a browser frame with an 8px ink shadow, a tilted yellow sticker on its corner, and a schedule card that is visibly running: every 4.2 seconds the post count goes up by one, the progress bar grows, a new title drops into Recent posts and a "New post live" toast pops over the window's lower-left edge. The detail worth copying is that the mockup is alive but calm, with a real pause button, so the hero shows the product's promise ("it runs while you sleep") instead of claiming it.
## Reference behaviour
1. First frame: nav (logo, four links, cobalt "Start a kitchen" button), badge "Recipe autopublish · live" with a pulsing white dot, headline "Your recipe blog, cooking itself. Fresh every morning.", lede, buttons "Start a 14-day kitchen" (cobalt) and "Watch a post get made" (surface), chips "Daily at 7:00", "11 recipe formats", "9 languages", and mono fine print.
2. The browser shows "app.ovenlight.co/schedules" in the URL pill. The card: Live pill, pause and Edit buttons, "Weeknight Suppers", "weeknightsuppers.blog", progress "18 / 40 posts" at 45%, three stats (6 formats, 14 pans linked, 1/d for 40 days). Recent posts lists four titles with green dots and "1d ago" to "4d ago".
3. 1.6s after load, then every 4.2s: count +1, bar width animates, percentage updates, a new title is prepended with "just now", the older times shift (1d, 2d, 3d…), the list keeps four rows, and the toast shows for 2.2s.
4. At 40 / 40 the next tick wraps back to 18. Titles cycle through a list of eight.
5. Pause button: toggles `aria-pressed`, swaps the icon to a play triangle, the Live pill turns grey and reads "Paused", ticking stops. Pressing again resumes.
6. When the tab is hidden the interval is cleared; it restarts when visible unless paused.
7. Buttons press into their shadow on hover and flat on active. The sticker straightens from 9° to -3° and scales 1.06 on hover.
## Structure
```
1280 × 800, bg #EEF3EA with a 24px dot grid
nav max 1180, padding 20/40 [logo Ovenlight] ............ links ×4 [Start a kitchen →]
hero max 1180, padding 28/40/48, grid minmax(0,1fr) | minmax(0,560px), gap 56, centred
┌ copy ──────────────────────────────┐ ┌ stage (padding 18 right/top) ─────────[sticker 9°]
│ [● RECIPE AUTOPUBLISH · LIVE] │ │ ┌ window 2px ink, r14, shadow 8/8/0 ─────────────┐
│ Your recipe blog, 64/700 │ │ │ ● ● ● [ app.ovenlight.co/schedules ] │
│ cooking itself. ← cobalt+marker │ │ ├────────────────────────────────────────────────┤
│ Fresh every morning. │ │ │ ┌ schedule card ───────────────────────────┐ │
│ lede 19px 46ch │ │ │ │ (● LIVE) [II] [Edit] │ │
│ [Start a 14-day kitchen][Watch…]56 │ │ │ │ Weeknight Suppers 22/700 │ │
│ [◷ Daily at 7:00][≡ 11…][◍ 9…] │ │ │ │ PROGRESS 18 / 40 posts│ │
│ fine print mono 12 │ │ │ │ [█████████░░░░░░░░░] 10px │ │
└────────────────────────────────────┘ │ │ │ [6 formats][14 pans][1/d] │ │
│ │ └──────────────────────────────────────────┘ │
[toast]───┤ │ RECENT POSTS ALL PUBLISHED │
│ │ ● title ………………………………… just now (4 rows × 30)│
│ └────────────────────────────────────────────────┘
… 167 more lines. Copy or download for the full brief. Loading the source…Brief
207 linesBuild brief for a coding agent. Rebuild this piece in the reader’s stack. If they haven’t said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don’t “improve” them. When a kit is locked, map colours onto the kit tokens and keep the hard 0-blur shadows.
What it is
Studied from usearticle.com: the first screen, where the product is shown working inside a drawn browser window instead of as a static screenshot. This version is Ovenlight, a fictional service that publishes a recipe blog on a schedule. Left: a green live badge, a 64px headline with “cooking itself.” in cobalt on a yellow marker stripe, a lede, two big hard-shadow buttons and three feature chips. Right: a browser frame with an 8px ink shadow, a tilted yellow sticker on its corner, and a schedule card that is visibly running: every 4.2 seconds the post count goes up by one, the progress bar grows, a new title drops into Recent posts and a “New post live” toast pops over the window’s lower-left edge. The detail worth copying is that the mockup is alive but calm, with a real pause button, so the hero shows the product’s promise (“it runs while you sleep”) instead of claiming it.
Reference behaviour
- First frame: nav (logo, four links, cobalt “Start a kitchen” button), badge “Recipe autopublish · live” with a pulsing white dot, headline “Your recipe blog, cooking itself. Fresh every morning.”, lede, buttons “Start a 14-day kitchen” (cobalt) and “Watch a post get made” (surface), chips “Daily at 7:00”, “11 recipe formats”, “9 languages”, and mono fine print.
- The browser shows “app.ovenlight.co/schedules” in the URL pill. The card: Live pill, pause and Edit buttons, “Weeknight Suppers”, “weeknightsuppers.blog”, progress “18 / 40 posts” at 45%, three stats (6 formats, 14 pans linked, 1/d for 40 days). Recent posts lists four titles with green dots and “1d ago” to “4d ago”.
- 1.6s after load, then every 4.2s: count +1, bar width animates, percentage updates, a new title is prepended with “just now”, the older times shift (1d, 2d, 3d…), the list keeps four rows, and the toast shows for 2.2s.
- At 40 / 40 the next tick wraps back to 18. Titles cycle through a list of eight.
- Pause button: toggles
aria-pressed, swaps the icon to a play triangle, the Live pill turns grey and reads “Paused”, ticking stops. Pressing again resumes. - When the tab is hidden the interval is cleared; it restarts when visible unless paused.
- Buttons press into their shadow on hover and flat on active. The sticker straightens from 9° to -3° and scales 1.06 on hover.
Structure
1280 × 800, bg #EEF3EA with a 24px dot grid
nav max 1180, padding 20/40 [logo Ovenlight] ............ links ×4 [Start a kitchen →]
hero max 1180, padding 28/40/48, grid minmax(0,1fr) | minmax(0,560px), gap 56, centred
┌ copy ──────────────────────────────┐ ┌ stage (padding 18 right/top) ─────────[sticker 9°]
│ [● RECIPE AUTOPUBLISH · LIVE] │ │ ┌ window 2px ink, r14, shadow 8/8/0 ─────────────┐
│ Your recipe blog, 64/700 │ │ │ ● ● ● [ app.ovenlight.co/schedules ] │
│ cooking itself. ← cobalt+marker │ │ ├────────────────────────────────────────────────┤
│ Fresh every morning. │ │ │ ┌ schedule card ───────────────────────────┐ │
│ lede 19px 46ch │ │ │ │ (● LIVE) [II] [Edit] │ │
│ [Start a 14-day kitchen][Watch…]56 │ │ │ │ Weeknight Suppers 22/700 │ │
│ [◷ Daily at 7:00][≡ 11…][◍ 9…] │ │ │ │ PROGRESS 18 / 40 posts│ │
│ fine print mono 12 │ │ │ │ [█████████░░░░░░░░░] 10px │ │
└────────────────────────────────────┘ │ │ │ [6 formats][14 pans][1/d] │ │
│ │ └──────────────────────────────────────────┘ │
[toast]───┤ │ RECENT POSTS ALL PUBLISHED │
│ │ ● title ………………………………… just now (4 rows × 30)│
│ └────────────────────────────────────────────────┘
header.navwith ana.logo, anavlabelled “Main”, and a CTA link.main.herowith the copydivanddiv.stage.- The window is
role=regionlabelled “Product preview: a running recipe schedule”. The traffic lights and URL arearia-hidden. - Recent posts is an
olwitharia-live="polite"andaria-relevant="additions". - The toast and sticker are
aria-hiddendecoration; the list announcement carries the news.
Tokens
:root {
--bg: #eef3ea; /* page, pale sage, with a #d3ddd0 1px dot every 24px */
--surface: #fcfdf9; /* window, cards, secondary button */
--ink: #0f1e19; /* text, borders, shadows */
--ink-2: #44524c; /* lede, nav links */
--ink-3: #6b7871; /* mono meta */
--rule: #d7e0d4; /* stat and list borders */
--primary: #2443f0; /* cobalt: headline accent, primary buttons, focus */
--mark: #ffe14d; /* marker stripe, sticker */
--live: #15a05c; /* badge, progress, dots, toast check */
--live-soft: #d6f2e2; /* live pill */
--sans: "Familjen Grotesk", system-ui, sans-serif;
--mono: "Fragment Mono", ui-monospace, monospace;
--hard-sm: 3px 3px 0 var(--ink);
--hard: 5px 5px 0 var(--ink);
--hard-lg: 8px 8px 0 var(--ink);
--r-btn: 10px; --r-cta: 12px; --r-win: 14px; --r-card: 12px;
--micro: 150ms;
--ease: cubic-bezier(.2,.7,.2,1);
--expo: cubic-bezier(.16,1,.3,1);
--tick: 4200ms; --toast-hold: 2200ms;
}
Typography
| Role | Family | Size | Weight | Line-height | Tracking |
|---|---|---|---|---|---|
| Logo | Familjen Grotesk | 21px | 700 | 1 | -0.02em |
| Nav link | Familjen Grotesk | 15px | 500 | 1.5 | 0 |
| Badge | Fragment Mono | 12px | 400 | 1 | 0.06em, upper |
| H1 | Familjen Grotesk | 64px | 700 | 0.98 | -0.035em |
| Lede | Familjen Grotesk | 19px | 400, bold run 600 | 1.55 | 0 |
| Hero buttons | Familjen Grotesk | 17px | 700 | 1 | 0 |
| Feature chip | Familjen Grotesk | 14px | 600 | 1 | 0 |
| Card title | Familjen Grotesk | 22px | 700 | 1.2 | -0.02em |
| Count | Familjen Grotesk | 15px | 700 | 1 | 0 |
| Labels, URL, times, domain | Fragment Mono | 11–12px | 400 | 1.4 | 0.06em when upper |
| List row | Familjen Grotesk | 13.5px | 500 | 30px rows | 0 |
Motion
| Thing | Trigger | Property | From → to | Duration | Easing |
|---|---|---|---|---|---|
| Badge and Live dots | always | opacity | 1 → 0.35 → 1 | 2s loop | standard |
| Progress fill | tick | width | n/40 → (n+1)/40 | 500ms | expo out |
| New list row | tick | opacity, translateY | 0, -14px → 1, 0 | 500ms | expo out |
| Toast | tick | opacity, translateY, scale | 0, 10px, .96 → 1, 0, 1 | 300ms / 400ms | standard / expo |
| Toast hide | 2.2s after show | same, reversed | 300ms | standard | |
| Button hover | pointer | transform, shadow | 5px shadow → translate(3px,3px), 2px shadow | 150ms | standard |
| Button active | press | transform, shadow | → translate(5px,5px), none | 150ms | standard |
| Sticker hover | pointer | transform | rotate(9deg) → rotate(-3deg) scale(1.06) | 300ms | expo out |
Reduced motion: all transitions and keyframes are removed. Ticking continues so the content stays current, but numbers and rows change without movement, and the toast appears and disappears without sliding. The pause button is always available.
States
- Primary button: cobalt fill, white text, 2px ink border, hard shadow. Secondary: surface fill, ink text.
- Hover: presses partway into the shadow. Active: flat, no shadow. Focus-visible: 2px cobalt outline, 3px offset.
- Live: green pill, pulsing dot. Paused: grey pill (
#eef0ec,--ruleborder), static grey dot, text “Paused”, play icon in the button. - Toast: hidden (opacity 0) by default, shown for 2.2s per tick.
- Complete: at 40 / 40 the next tick wraps to 18; there is no separate done state in the hero.
Accessibility
- Pause control is a
buttonwitharia-pressedand a label that flips between “Pause the live preview” and “Resume the live preview”. This is the WCAG 2.2.2 control for auto-updating content. - Recent posts
olisaria-live="polite"witharia-relevant="additions", so only the new title is read. - Progress is
role=progressbarwith min 0, max 40,aria-valuenow. - The nav CTA keeps an
aria-labelbecause its text hides below 420px. - Decorative pieces (traffic lights, URL, sticker, toast) are
aria-hidden. - Contrast:
#44524con#eef3ea≈ 7:1; white on#2443f0≈ 6.9:1;#6b7871on#fcfdf9≈ 4.7:1. - Hero buttons are 56px tall; nav button and card controls at least 34–44px.
Responsive rules
- ≥1280: as drawn.
- 1100 and below: one column; the browser stage sits under the copy, max 560px wide.
- ≤720: nav links hide; padding 16px 20px; h1 44px; lede 17px; toast moves inside the window edge (left 8px); sticker sits flush right.
- ≤420: the nav CTA becomes an arrow-only button; hero buttons go full width.
- Never let the toast or sticker cause horizontal scroll;
body { overflow-x: hidden }is a guard, not the fix. Keep their offsets inside the stage padding.
Acceptance checklist
Always
- Two columns at desktop, copy left, live product mockup right.
- One accent word in the headline with a marker stripe behind it.
- All elevated items use 0-blur ink shadows; buttons press into them.
- The mockup changes on a timer that is no faster than every 4s.
- A visible pause button stops all ticking, with
aria-pressed. - Ticking stops while the tab is hidden.
- New list items are announced politely; the list never grows past four rows.
- Reduced motion keeps the content but removes movement.
- No horizontal scroll at 375px.
This demo
- First frame shows “18 / 40 posts” at 45%; first tick at 1.6s makes it “19 / 40” and adds “Crispy rice salad with herbs and lime”.
- Headline accent “cooking itself.” is
#2443f0on a#ffe14dstripe. - Window shadow 8px 8px 0
#0f1e19; sticker rotated 9°. - Toast reads “New post live / Email sent · just now”.
Implementation notes
The tick. Keep it one function so pause and visibility only start and stop the interval:
let n = 18, timer;
function tick() {
n = n >= 40 ? 18 : n + 1;
setProgress(n);
list.querySelectorAll('time').forEach((t, i) => t.textContent = `${i + 1}d ago`);
const li = document.createElement('li');
li.className = 'in';
li.innerHTML = `<span>${titles[qi++ % titles.length]}</span><time>just now</time>`;
list.prepend(li);
while (list.children.length > 4) list.lastElementChild.remove();
showToast(2200);
}
const start = () => { timer = setInterval(tick, 4200); };
Update the old times before prepending, so the new row is the only “just now”.
The marker highlight is a background gradient, not a pseudo element, so it wraps with the text:
h1 .hl { color: var(--primary);
background: linear-gradient(transparent 62%, var(--mark) 62% 90%, transparent 90%); }
The list must have a fixed height (4 × 30px = 120px, overflow: hidden) or the window grows by a row for 500ms on each tick and the whole hero jumps.
Common mistakes:
- A static screenshot in the frame. The point is that it moves.
- Ticking every second. It reads as a slot machine; 4.2s reads as “running”.
- Soft drop shadows on the window. Use the 8px hard offset.
- Drawing a fake cursor clicking around. One loop: count, row, toast.
- No pause button. Auto-updating content needs one.
- Putting
aria-liveon the whole card, so the count, percent and title are all read every 4 seconds.
Rebuild order:
- Nav and two-column grid.
- Headline, lede, buttons, chips.
- Browser frame, sticker, schedule card, list (static).
- Tick function and interval.
- Toast.
- Pause and visibility handling.
- Reduced motion and the narrow layout.
Details
- Palette
- Type
- Familjen Grotesk · Fragment Mono
- Motion
- Subtle motion
- Build
- One session
- Tags
Studied
UseArticleLet the visitor press the controls and watch the card change. Thick black edges and hard shadows keep it friendly.
All sources