SurveyStream

Documentdocs/og/README.md

SurveyStream — Open Graph card

1200 × 630, dark slate, dual-audience. Self-contained: the three webfonts are embedded as base64, so the file renders identically on any machine with no network and no font installs. That matters — an OG card rendered with a fallback face is a different design.

Files

FileSizeNotes
og-card.html291 KBThe card. Open it and screenshot, or use the commands below.
og-card.png425 KB1200 × 630, exported.
og-card@2x.png1232 KB2400 × 1260, for retina previews.

Exporting

Chrome headless gives a pixel-exact export with no cropping:

CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"

# 1× — 1200 × 630, the canonical OG size
"$CHROME" --headless --disable-gpu --hide-scrollbars \
  --window-size=1200,630 \
  --screenshot=og-card.png \
  "file://$PWD/og-card.html"

# 2× — 2400 × 1260
"$CHROME" --headless --disable-gpu --hide-scrollbars \
  --window-size=1200,630 --force-device-scale-factor=2 \
  --screenshot=og-card@2x.png \
  "file://$PWD/og-card.html"

--hide-scrollbars is not optional: without it Chrome reserves gutter width and the card is cropped a few pixels on the right.

Markup

<meta property="og:image" content="https://surveystream.com/og-card.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:title" content="Turn Real-Time Feedback Into Instant Value">
<meta property="og:description" content="Survey takers cash out in minutes. Research teams get a verified, live data stream they can build on.">
<meta name="twitter:card" content="summary_large_image">

Serve the 1× PNG as og:image. Most platforms re-encode anyway, and the 2× file mainly costs bandwidth. Keep it under 1 MB — several scrapers refuse larger images outright.

Composition notes

  • The scrim is doing the real work. The stream visualisation lives on the right and is masked out of the left third; on top of that a linear-gradient(96deg, …) scrim holds a clean field under the headline. Without it the waves run straight through the type — I built that version first and the headline was unreadable.
  • Tested at feed size. Rendered down to 504 px wide, which is roughly what a timeline shows. The headline, 12,480 and $1,284.50 all still read; the mono footer row is at the edge of legibility, which is why nothing load-bearing lives there.
  • Numerals follow the type system: tabular-nums throughout, and the payout amount carries "tnum" 1, "lnum" 1, "zero" 0 — slashed zero explicitly off, because inside money it reads as a correction mark.
  • Colours use the brand accents (Stream / Signal / Pulse) on the specified #0F172A ground.

Two honest caveats

1. The logo mark is below its own small-size threshold. The lockup renders at 44 px, which puts the mark at roughly 33 px — under the 40 px floor documented in ../logo/interlock/README.md, and far under it once a feed scales the card to half size. It degrades gracefully: the solid base still reads as an S and only the thin accent softens. That is an acceptable trade for a card that is mostly viewed large, but if you would rather be strict, swap the lockup for ../logo/interlock/lockup-horizontal-mono.svg (base only) and tint it Mist.

2. backdrop-filter does not survive server-side OG rendering. The glass panel depends on it. Satori and @vercel/og do not implement backdrop-filter, so generating this card at request time in that stack would render the panel as a flat translucent rectangle — losing the effect but not breaking the layout. Options, in order of preference: ship the exported PNG (what this folder does); or if you need per-page dynamic cards, replace the glass with an explicit gradient fill that approximates the blur.

Tailwind mapping

Written as plain CSS with custom properties so it works with or without a framework. If you port it:

HereTailwind
.ogrelative w-[1200px] h-[630px] overflow-hidden bg-[#0F172A]
.panelw-[356px] rounded-[22px] border border-white/[.16] backdrop-blur-[22px] backdrop-saturate-150
.scrimabsolute inset-0 z-[2] bg-[linear-gradient(96deg,…)]
h1 .litbg-gradient-to-r from-[#5FE3EC] to-[#2FE3A2] bg-clip-text text-transparent

The inset box-shadows on .panel have no clean utility equivalent — keep them as an arbitrary shadow-[…] value or a small component class.