igneum/site/og/preview.html
igneum-labs a4c5b6c1e8 site: share cards and metas from one source (site/og), rendered on a build box
Every served page now carries its og: and twitter: block from site/og/pages.mjs through site/build.mjs (injected between
share markers on the hand-written pages, through meta() on the generated ones); nothing is pasted per page. New cards under
site/og/: eighteen 1200 x 630 PNGs at about 100 KB and a 1200 x 1200 square each (the second og:image for the readers
that crop square), rendered from site/og/card.html by site/og/render.mjs on build box 2 with its Playwright, never on the
Mac. The old og.png family stays on disk for cached links; nothing points at it. Titles under 60, descriptions under 110,
checked by the build. One command refreshes every card: node site/og/render.mjs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 14:51:03 +00:00

80 lines
6.3 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Igneum share preview sheet</title>
<!-- The reader mocks (the link-preview lane, 8 October 2026): how one route's card and metas read in WhatsApp (the large
preview and the small square thumbnail), iMessage, X (summary_large_image) and Slack. Not a served page: site/og/render.mjs
opens it with ?card=&title=&desc=&path= and screenshots each block. The frames approximate each app's chrome at phone
width; they exist to catch a crop or a truncation before a link is sent, not to copy any app. -->
<style>
@font-face{font-family:'Plex Sans';font-weight:400;src:url(../fonts/plex-sans-400.woff2) format('woff2')}
@font-face{font-family:'Plex Sans';font-weight:600;src:url(../fonts/plex-sans-600.woff2) format('woff2')}
body{margin:0;background:#1b1b1f;color:#eee;font:14px/1.4 -apple-system,'Plex Sans',Arial,sans-serif;padding:24px}
#sheet{display:grid;grid-template-columns:repeat(2,1fr);gap:28px;max-width:1130px}
.frame{background:#0e0e10;border:1px solid #2a2a30;border-radius:14px;padding:16px}
.frame h2{margin:0 0 12px;font:600 12px/1 'Plex Sans',sans-serif;letter-spacing:.14em;text-transform:uppercase;color:#9a9a9e}
.meta{margin-top:10px;font:12px/1.5 ui-monospace,monospace;color:#9a9a9e;word-break:break-all}
/* WhatsApp: a 320 px bubble; the large preview shows the whole 1200 x 630 at bubble width; the small one crops a square thumb */
.wa{width:320px;background:#005c4b;border-radius:12px;padding:6px;color:#e9edef;font-family:-apple-system,'Plex Sans',Arial,sans-serif}
.wa .prev{background:#025144;border-radius:8px;overflow:hidden}
.wa .prev img{display:block;width:100%;height:auto}
.wa .txt{padding:8px 10px}
.wa .t{font-weight:600;font-size:14px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.wa .d{font-size:13px;color:#cfd6d4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-top:2px}
.wa .h{font-size:12px;color:#9fb3ae;margin-top:3px}
.wa .link{padding:6px 10px 4px;font-size:14px;color:#53bdeb;word-break:break-all}
.wa.small .prev{display:flex}
.wa.small .thumb{width:92px;height:92px;flex:none;background-size:cover;background-position:center}
.wa.small .txt{min-width:0}
/* iMessage: a 290 px rich link, image on top, title and host under */
.im{width:290px;border-radius:18px;overflow:hidden;background:#2c2c2e;color:#fff;font-family:-apple-system,'Plex Sans',Arial,sans-serif}
.im img{display:block;width:100%;height:auto}
.im .txt{padding:9px 12px 10px}
.im .t{font-weight:600;font-size:14px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.im .h{font-size:12px;color:#98989d;margin-top:2px}
/* X: summary_large_image, a 500 px card with the title over the image's foot */
.x{width:500px;border-radius:16px;overflow:hidden;border:1px solid #2f3336;position:relative;background:#000}
.x img{display:block;width:100%;height:auto}
.x .cap{position:absolute;left:12px;bottom:12px;background:rgba(0,0,0,.77);color:#fff;font-size:13px;padding:2px 6px;border-radius:4px;max-width:92%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.x .h{font-size:13px;color:#71767b;margin-top:6px}
/* Slack: an unfurl with the ember bar, title, text and the image under */
.sl{width:520px;border-left:4px solid #F2541B;padding:6px 12px;background:#1a1d21;color:#d1d2d3;font-family:'Plex Sans',Arial,sans-serif}
.sl .s{font-weight:600;color:#fff;font-size:15px}
.sl .t{font-weight:600;color:#1d9bd1;font-size:15px;margin-top:2px}
.sl .d{font-size:15px;margin-top:2px}
.sl img{display:block;width:360px;height:auto;margin-top:8px;border-radius:8px}
</style>
</head>
<body>
<div id="sheet">
<div class="frame" id="wa-large"><h2>WhatsApp, large preview</h2>
<div class="wa"><div class="prev"><img id="wa-img" alt=""><div class="txt"><div class="t" id="wa-t"></div><div class="d" id="wa-d"></div><div class="h" id="wa-h"></div></div></div><div class="link" id="wa-link"></div></div>
<div class="meta">og:image 1200 x 630, the whole card at bubble width</div></div>
<div class="frame" id="wa-small"><h2>WhatsApp, square thumbnail</h2>
<div class="wa small"><div class="prev"><div class="thumb" id="was-thumb"></div><div class="txt"><div class="t" id="was-t"></div><div class="d" id="was-d"></div><div class="h" id="was-h"></div></div></div><div class="link" id="was-link"></div></div>
<div class="meta">the centre square crop of the wide card (the small-thumbnail mode); the square variant is the second og:image</div></div>
<div class="frame" id="imessage"><h2>iMessage</h2>
<div class="im"><img id="im-img" alt=""><div class="txt"><div class="t" id="im-t"></div><div class="h" id="im-h"></div></div></div>
<div class="meta">og:image and og:title</div></div>
<div class="frame" id="x"><h2>X, summary_large_image</h2>
<div class="x"><img id="x-img" alt=""><div class="cap" id="x-t"></div></div><div class="x h" id="x-h" style="border:0;background:none;border-radius:0"></div>
<div class="meta">twitter:card, twitter:title, twitter:image</div></div>
<div class="frame" id="slack" style="grid-column:1 / span 2"><h2>Slack unfurl</h2>
<div class="sl"><div class="s">Igneum</div><div class="t" id="sl-t"></div><div class="d" id="sl-d"></div><img id="sl-img" alt=""></div>
<div class="meta" id="sl-meta"></div></div>
</div>
<script type="module">
const q = new URLSearchParams(location.search);
const card = q.get('card') || 'home', title = q.get('title') || 'Igneum', desc = q.get('desc') || '', path = q.get('path') || '/';
const img = `./${card}.png`, url = 'igneum.network' + (path === '/' ? '' : path);
for (const id of ['wa-img', 'im-img', 'x-img', 'sl-img']) document.getElementById(id).src = img;
document.getElementById('was-thumb').style.backgroundImage = `url(${img})`;
for (const id of ['wa-t', 'was-t', 'im-t', 'x-t', 'sl-t']) document.getElementById(id).textContent = title;
for (const id of ['wa-d', 'was-d', 'sl-d']) document.getElementById(id).textContent = desc;
for (const id of ['wa-h', 'was-h', 'im-h', 'x-h']) document.getElementById(id).textContent = 'igneum.network';
for (const id of ['wa-link', 'was-link']) document.getElementById(id).textContent = 'https://' + url;
document.getElementById('sl-meta').textContent = `og:title ${title.length} chars, og:description ${desc.length} chars`;
</script>
</body>
</html>