Nº 311 of 520
Microblog post card
A short-post card with verified handle, highlighted links and hashtags, a map image, rolling digit counters, and a seven-dot like burst.
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 "Microblog post card" (piece social-microblog-post) 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º 311 · "Microblog post card" · www.designlounge.live -->
# Microblog post 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.
## What it is
One post from a short-form feed, for an invented network called Chirrup. It reads instantly as the familiar format: round avatar, display name with a scalloped verified mark, @handle and age, a few lines of text with a mention, a link and two hashtags picked out in the brand teal, a 16:9 image, a mono timestamp line with a view count, and a four-button action row. The image is an inline SVG transit map, not a photo, so the piece has zero assets. The detail worth copying is the counters: every digit is its own vertical strip of 0–9, so 8,402 becomes 8,403 by rolling only the last digit, and the like fires a ring plus seven particles behind the heart.
## Reference behaviour
1. First frame: the card sits centred on a pale sage stage. Likes 8,402, reposts 1,186, replies 214, nothing pressed. The Baixa interchange stop on the map pulses slowly (scale 1 → 1.35 → 1 over 2.4s).
2. Hover any action: icon and count turn the action's colour, and a 34px circular tint appears behind the icon. Reply and share use teal, repost green, like pink-red.
3. Click Like: `aria-pressed` becomes true, the heart fills, pops from scale 0.4 to 1.2 to 1 in 420ms, a ring expands from the heart and fades, seven dots fly outward 26px. The count rolls 8,402 → 8,403. The button label updates to "Like, 8,403 likes".
4. Click Like again: unfills, count rolls back. No burst on unlike.
5. Click Repost: icon turns green and spins in from −180°, count rolls up by one, and a dark pill toast says "Reposted to your followers" for 1.8s. Clicking again says "Repost removed".
6. Click Reply: toast "Replying to @miraokafor". (In a product this opens the composer.)
7. Click Share: a menu rises from the button (fade + 6px lift, 220ms) with Copy link, Bookmark, Send via message. Focus moves to the first item. Arrow Up/Down move, Escape closes and returns focus to Share, click outside closes. Choosing an item closes the menu and shows a matching toast.
8. When the digit count of a number changes (999 → 1,000), the counter rebuilds its strips and then rolls.
## Structure
```
stage 1280×800, card centred
┌──────────────── card 598px, radius 18, pad 18/20/8 ────────────────┐
│ (44 av) Mira Okafor [✓18] [ ⋯ 36 ]│
│ @miraokafor · 2h │
│ │
│ text 17/1.48, mention + link + #tags in teal │
│ │
│ ┌──────────── media 16:9, radius 14, 1px line ─────────────┐ │
│ │ SVG transit map, four lines, ten stops, five labels │ │
│ │ [28 · 14 stops · 9 chimes] mono caption, bottom-left │ │
│ └──────────────────────────────────────────────────────────┘ │
│ 9:41 AM · Oct 3, 2026 · 48.2K views mono 12.5 │
│ ───────────────────────────── 1px ──────────────────────────────── │
│ [◯ 214] [⟲ 1,186] [♡ 8,402] [⇪] │
└────────────────────────────────────────────────────────────────────┘
toast: fixed, centred, 28px from bottom
… 199 more lines. Copy or download for the full brief. Loading the source…Brief
239 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.
What it is
One post from a short-form feed, for an invented network called Chirrup. It reads instantly as the familiar format: round avatar, display name with a scalloped verified mark, @handle and age, a few lines of text with a mention, a link and two hashtags picked out in the brand teal, a 16:9 image, a mono timestamp line with a view count, and a four-button action row. The image is an inline SVG transit map, not a photo, so the piece has zero assets. The detail worth copying is the counters: every digit is its own vertical strip of 0–9, so 8,402 becomes 8,403 by rolling only the last digit, and the like fires a ring plus seven particles behind the heart.
Reference behaviour
- First frame: the card sits centred on a pale sage stage. Likes 8,402, reposts 1,186, replies 214, nothing pressed. The Baixa interchange stop on the map pulses slowly (scale 1 → 1.35 → 1 over 2.4s).
- Hover any action: icon and count turn the action’s colour, and a 34px circular tint appears behind the icon. Reply and share use teal, repost green, like pink-red.
- Click Like:
aria-pressedbecomes true, the heart fills, pops from scale 0.4 to 1.2 to 1 in 420ms, a ring expands from the heart and fades, seven dots fly outward 26px. The count rolls 8,402 → 8,403. The button label updates to “Like, 8,403 likes”. - Click Like again: unfills, count rolls back. No burst on unlike.
- Click Repost: icon turns green and spins in from −180°, count rolls up by one, and a dark pill toast says “Reposted to your followers” for 1.8s. Clicking again says “Repost removed”.
- Click Reply: toast “Replying to @miraokafor”. (In a product this opens the composer.)
- Click Share: a menu rises from the button (fade + 6px lift, 220ms) with Copy link, Bookmark, Send via message. Focus moves to the first item. Arrow Up/Down move, Escape closes and returns focus to Share, click outside closes. Choosing an item closes the menu and shows a matching toast.
- When the digit count of a number changes (999 → 1,000), the counter rebuilds its strips and then rolls.
Structure
stage 1280×800, card centred
┌──────────────── card 598px, radius 18, pad 18/20/8 ────────────────┐
│ (44 av) Mira Okafor [✓18] [ ⋯ 36 ]│
│ @miraokafor · 2h │
│ │
│ text 17/1.48, mention + link + #tags in teal │
│ │
│ ┌──────────── media 16:9, radius 14, 1px line ─────────────┐ │
│ │ SVG transit map, four lines, ten stops, five labels │ │
│ │ [28 · 14 stops · 9 chimes] mono caption, bottom-left │ │
│ └──────────────────────────────────────────────────────────┘ │
│ 9:41 AM · Oct 3, 2026 · 48.2K views mono 12.5 │
│ ───────────────────────────── 1px ──────────────────────────────── │
│ [◯ 214] [⟲ 1,186] [♡ 8,402] [⇪] │
└────────────────────────────────────────────────────────────────────┘
toast: fixed, centred, 28px from bottom
- Card:
articlelabelled by the author name. - Header:
headerwith a decorative avatar (aria-hidden), the name in a div with ansvg role="img" aria-label="Verified account", and a “More options” icon button. - Text: one
p. Mentions, links and hashtags areaelements. - Media:
figureholding thesvg role="img"with a descriptive label, and afigcaption. - Meta:
pwith atime datetime. - Actions:
div role="group" aria-label="Post actions"of four buttons; Share is in a wrapper with itsrole="menu"popover. - Toast:
div role="status" aria-live="polite".
Tokens
:root {
/* surfaces */
--stage: #eef0ec; /* page behind the card */
--card: #fcfdfb; /* card */
--line: #dfe3dc; /* card border, media border, meta rule */
--line-2: #cfd5cc; /* menu border */
/* ink */
--ink: #121614;
--ink-2: #4a524d;
--ink-3: #6b746e; /* handle, idle actions, meta */
/* roles */
--brand: #0b6f6a; /* links, hashtags, verified, reply/share hover, focus */
--brand-soft: rgba(11,111,106,.1);
--like: #d92a5b;
--like-soft: rgba(217,42,91,.1);
--repost: #16834f;
--repost-soft: rgba(22,131,79,.1);
/* type */
--sans: "Hanken Grotesk", system-ui, sans-serif;
--mono: "IBM Plex Mono", ui-monospace, monospace;
/* shape */
--r: 18px; /* card */
--r-media: 14px;
/* motion */
--t-micro: 160ms;
--t-roll: 420ms;
--t-burst: 600ms;
--ease: cubic-bezier(.2,.7,.2,1);
--ease-out: cubic-bezier(.16,1,.3,1);
--ease-pop: cubic-bezier(.34,1.56,.64,1);
}
Card shadow: 0 1px 0 rgba(18,22,20,.04), 0 18px 40px -28px rgba(18,22,20,.35). Spacing runs on 4: 4, 8, 12, 14, 18, 20.
Typography
| Role | Family | Size | Weight | Line-height | Tracking |
|---|---|---|---|---|---|
| Display name | Hanken Grotesk | 15.5px | 700 | 1.2 | 0 |
| Handle · age | Hanken Grotesk | 14px | 400 | 1.5 | 0, --ink-3 |
| Post text | Hanken Grotesk | 17px | 400 | 1.48 | -0.006em |
| Hashtag | Hanken Grotesk | 17px | 600 | 1.48 | teal |
| Action count | Hanken Grotesk | 13px | 500 | 20px | tabular-nums |
| Timestamp line | IBM Plex Mono | 12.5px | 400 | 1.5 | 0.01em, view count 500 --ink |
| Media caption | IBM Plex Mono | 11px | 500 | 1 | 0.04em, light on 72% ink |
| Menu item | Hanken Grotesk | 14px | 500 | 40px row | 0 |
Mono is only for machine facts (time, views, map caption). Do not set the post text in mono.
Motion
| Thing | Trigger | Property | From → to | Duration / easing | Reduced motion |
|---|---|---|---|---|---|
| Action tint | hover | background, colour | transparent → soft tint | 160ms --ease | instant |
| Icon press | :active | transform | 1 → 0.88 | 160ms | instant |
| Heart fill | like on | transform | 0.4 → 1.2 → 1 | 420ms --ease-pop | none |
| Like ring | like on | scale, opacity, border | 0.2/0.9/2px → 1.5/0/0 | 600ms --ease-out | hidden |
| Like particles ×7 | like on | rotate(a) translateY | 0 → −26px, scale 1 → 0.3, fade | 600ms --ease-out | hidden |
| Repost icon | repost on | rotate, scale | −180°/0.7 → 0/1 | 480ms --ease-out | none |
| Digit strip | count change | translateY | −20px × old → −20px × new | 420ms --ease-out | instant |
| Share menu | open | opacity, translateY, scale | 0/6px/0.98 → 1/0/1 | 220ms --ease-out | instant |
| Toast | message | opacity, translateY | 0/16px → 1/0 | 280ms, hides after 1.8s | instant |
| Interchange stop | always | scale | 1 → 1.35 → 1 | 2.4s loop | none |
Particle angles: 0°, 51°, 103°, 154°, 206°, 257°, 309°. Odd particles are amber #f2a33a, even are --like.
States
- Action idle:
--ink-3, no background. - Action hover: action colour, 34px circle tint behind the icon.
- Like pressed: pink-red text and heart fill,
aria-pressed="true". - Repost pressed: green text and icon,
aria-pressed="true". - Share expanded:
aria-expanded="true", menu visible. - Menu item hover/focus: teal soft background and teal text.
- Focus-visible: 2px teal outline, 2px offset, 8px radius, on every button and link.
- Disabled, loading, empty: not used on a single post.
Accessibility
- Each action button carries the full sentence in
aria-label: “Like, 8,402 likes”. Update it whenever the count changes. The rolling digits arearia-hidden, because the strips read as “0123456789” to a screen reader. - Like and Repost are toggles with
aria-pressed. Reply and Share are plain buttons. - Share:
aria-haspopup="menu",aria-expanded,aria-controls. Items arerole="menuitem". Arrow keys cycle, Escape closes and refocuses the trigger. - The verified mark is an
svg role="img"with “Verified account”. The avatar is decorative because the name is right beside it. - The map has a text alternative describing what it shows.
- Toasts go to a polite live region.
- Contrast:
#6b746eon#fcfdfbis 4.7:1. Teal#0b6f6aon the card is 5.9:1. - Hit targets: actions are 40px tall, the more button is 36px; raise it to 40px on touch layouts.
Responsive rules
- ≥1280: card 598px wide, centred.
- 1024 and 768: unchanged; the card is narrower than the viewport.
- <640: the card is
min(598px, 100%)with 16px page padding. At ≤480 the card padding drops to 14/14/6, text to 16px, action padding to 6px, and the meta line to 11.5px. The image stays 16:9. - At 375 nothing overflows horizontally; long links break with
overflow-wrap: anywhere.
Acceptance checklist
Always
- Card shows avatar, name, verified mark, handle and age, text, media, timestamp line, and four actions in that order.
- Links, mentions and hashtags are real anchors coloured with the brand token.
- Each digit of each count rolls independently; separators do not move.
- Like and Repost are
aria-pressedtoggles; theiraria-labelincludes the current count. - Liking fires the ring and seven particles once; unliking fires nothing.
- Share menu opens with focus on the first item, closes on Escape and outside click.
- All actions are at least 40px tall and show a visible focus ring.
- Reduced motion removes the burst, pop, spin and stop pulse; counts change instantly.
- No horizontal scroll at 375px.
This demo
- Author is Mira Okafor, @miraokafor, 2h.
- Starting counts: 214 replies, 1,186 reposts, 8,402 likes, 48.2K views.
- Liking shows 8,403 and the label “Like, 8,403 likes”.
- The map caption reads “28 · 14 stops · 9 chimes”.
- Repost toast reads “Reposted to your followers”.
Implementation notes
Digit strips. Build each digit as a 20px-tall window over a column of ten 20px spans. Only rebuild when the string length changes; otherwise just move the columns, so the transition runs.
function render(el, n) {
const s = n.toLocaleString('en-US');
if (el.dataset.len != s.length) {
el.innerHTML = [...s].map(c => /\d/.test(c)
? '<span class="d"><span class="col">' +
[...'0123456789'].map(x => `<span>${x}</span>`).join('') + '</span></span>'
: `<span>${c}</span>`).join('');
el.dataset.len = s.length;
el.offsetHeight; // commit layout so the first move animates
}
[...s].forEach((c, i) => {
const col = el.children[i].querySelector('.col');
if (col) col.style.transform = `translateY(${-20 * c}px)`;
});
}
.num, .num .d, .num .col span { height: 20px; line-height: 20px; }
.num .d { overflow: hidden; display: inline-block; }
.num .col { display: flex; flex-direction: column; transition: transform 420ms var(--ease-out); }
Burst restart. The burst is a class toggle. Remove the class, force a reflow, add it back, so rapid likes replay it.
burst.classList.remove('go'); burst.offsetWidth; burst.classList.add('go');
.burst b { position:absolute; left:50%; top:50%; width:5px; height:5px; margin:-2.5px; border-radius:50%; opacity:0; }
.burst.go b { animation: fly 600ms var(--ease-out); }
@keyframes fly {
0% { opacity:1; transform: rotate(var(--a)) translateY(0) scale(1); }
100% { opacity:0; transform: rotate(var(--a)) translateY(-26px) scale(.3); }
}
Common mistakes.
- Animating the whole number with a crossfade. The point is that only changed digits move.
- Leaving the digit strips readable by screen readers.
- Using the real network’s blue and bird. Chirrup is teal with a scalloped badge; invent your own.
- Firing the burst on unlike, or on page load.
- Putting the burst inside the icon’s circle with
overflow: hidden; the particles get clipped. - Map labels sitting on top of route lines. Place labels in empty quadrants.
- Using
easeorlinearfor the roll; it needs the expo-out curve to settle.
Rebuild order.
- Stage, card, header with avatar, name, badge, handle.
- Text with anchors.
- Media figure with the SVG map and caption.
- Meta line and rule.
- Action row with counters wired to
render. - Like and repost toggles, burst, toast.
- Share menu with keyboard handling.
- Reduced-motion block and 375px check.
Details
- Palette
- Type
- Hanken Grotesk · IBM Plex Mono
- Motion
- Subtle motion
- Build
- One session
- Tags
On the shelves