Merge nucleic/eager-feather-seal-fsqu into main

Mirrored from corpo 80a719b.
This commit is contained in:
2026-08-12 02:31:02 -07:00
parent 7e72470e1e
commit f5ab9dcd48
5 changed files with 377 additions and 3 deletions
+249
View File
@@ -0,0 +1,249 @@
<!doctype html>
<!--
Source for website/public/og.png (1200x630).
Render with: npm run og (website/)
This card is a portrait of the page it links to, so every value here is lifted
from src/pages/index.astro rather than invented: the --paper ground, the two
diagonal green ambient washes, the grain that keeps them from banding, Archivo
for the statement, JetBrains Mono for the footer, and the 100deg
#cdead9 -> #2f8f5c signature on "runs." Change the site's palette or hero and
this file has to follow, or the card goes stale again.
Legibility rule (enforced by render-og.mjs): a social card is shown as small as
~320px wide (27% scale), so nothing here is smaller than 30px, no line reaches
the 72px padding, and there are no hairlines — a 1px rule scales to a quarter
of a pixel and simply disappears.
-->
<html lang="en">
<head>
<meta charset="UTF-8" />
<style>
@font-face {
font-family: 'Archivo';
src: url('../public/fonts/archivo.woff2') format('woff2');
font-style: normal;
font-weight: 100 900;
font-stretch: 62% 125%;
font-display: block;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('../public/fonts/jetbrains-mono.woff2') format('woff2');
font-style: normal;
font-weight: 400 700;
font-display: block;
}
:root {
--ink: #eef3ee;
--secondary: #aebdae;
--muted: #93a494;
--sage: #c6d8c6;
--paper: #0a100c;
}
* {
box-sizing: border-box;
margin: 0;
}
body {
width: 1200px;
height: 630px;
overflow: hidden;
background-color: var(--paper);
color: var(--secondary);
font-family: 'Archivo', sans-serif;
-webkit-font-smoothing: antialiased;
}
.card {
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 1200px;
height: 630px;
padding: 60px 72px 62px;
isolation: isolate;
}
/* The site's ambient field, held still. Two oversized diagonal bands of green
light crossing at different angles — deliberately not a radial glow: the
circular-blob version of this background was rejected on the site itself. */
.ambient {
position: absolute;
inset: 0;
z-index: -1;
overflow: hidden;
}
.ambient span {
position: absolute;
top: -60%;
left: -60%;
width: 220%;
height: 220%;
}
.ambient .haze {
background: linear-gradient(
106deg,
transparent 31%,
rgb(63 174 116 / 6%) 45%,
rgb(96 186 137 / 2.5%) 53%,
transparent 63%
);
transform: translate3d(-9%, 3%, 0);
}
.ambient .drift {
background: linear-gradient(
-24deg,
transparent 20%,
rgb(120 196 152 / 3%) 43%,
rgb(63 174 116 / 4.5%) 59%,
transparent 79%
);
transform: translate3d(7%, -5%, 0);
}
/* The site's third ambient layer, its feTurbulence grain, is deliberately NOT
reproduced here, and this is the one place the card departs from the page.
The grain is on the site to keep these low-alpha washes from banding, and on
the site it earns that. In a still it does not: scanning background rows of
both renders, the grainless card's gradients are already dithered by the
compositor (longest run of one green value: 1-7px over 420px, i.e. no bands
to break). Measured against the grained render it moves no channel by more
than 5/255 (mean 1.5) — and it costs 364KB, because per-pixel noise is
precisely what PNG cannot compress. An invisible layer is not worth doubling
a file every feed in the world re-fetches. Re-measure before restoring it. */
/* Settles the field back to --paper before it reaches the card's edge, so the
crop reads as an edge rather than as a wash that got cut off. */
.ambient .edge {
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: none;
background: linear-gradient(
to bottom,
var(--paper) 0,
rgb(10 16 12 / 0%) 14%,
rgb(10 16 12 / 0%) 72%,
rgb(10 16 12 / 55%) 90%,
var(--paper) 100%
);
}
/* The masthead lockup, at the site's own proportions: the mark is 2.94x the
brand-name font size and the gap is 0.83em of it. */
.lockup {
display: flex;
align-items: center;
gap: 27px;
}
.lockup img {
display: block;
width: 94px;
height: auto;
flex-shrink: 0;
}
.lockup .brand-name {
color: var(--ink);
font-size: 32px;
font-weight: 600;
letter-spacing: -0.02em;
line-height: 1.05;
}
/* margin-left is the site's optical inset: the R carries a left side bearing,
so the box has to hang 0.078em outside the padding for the printed edge of
the headline to land on it. */
.statement {
margin-left: -0.078em;
font-size: 132px;
font-weight: 600;
letter-spacing: -0.03em;
line-height: 0.98;
color: var(--ink);
}
.statement .line {
display: block;
}
/* Line two is locked to line one in em, exactly as on the site, so the
composition holds at whatever size the headline ends up. */
.statement .line-runs {
margin-left: 2.2em;
}
.statement .that {
color: var(--secondary);
}
.statement .runs {
color: transparent;
background: linear-gradient(100deg, #cdead9 8%, #2f8f5c 82%);
background-clip: text;
-webkit-background-clip: text;
}
.rule {
position: absolute;
left: 72px;
bottom: 132px;
width: 132px;
height: 4px;
border-radius: 2px;
background-image: linear-gradient(100deg, #cdead9, #2f8f5c);
}
.foot {
display: flex;
align-items: baseline;
justify-content: space-between;
font-family: 'JetBrains Mono', monospace;
font-size: 30px;
line-height: 1;
letter-spacing: -0.01em;
color: var(--muted);
}
.foot .site {
color: var(--secondary);
}
</style>
</head>
<body>
<div class="card">
<div class="ambient" aria-hidden="true">
<span class="haze"></span>
<span class="drift"></span>
<span class="edge"></span>
</div>
<div class="lockup">
<img src="../public/blakeslee-icon.svg" alt="" />
<span class="brand-name">Blakeslee<br />Research</span>
</div>
<h1 class="statement">
<span class="line line-research">Research</span>
<span class="line line-runs"><span class="that">that</span> <span class="runs">runs.</span></span>
</h1>
<div class="rule"></div>
<div class="foot">
<p class="site">blakeslee.xyz</p>
</div>
</div>
</body>
</html>
+114
View File
@@ -0,0 +1,114 @@
// Renders website/scripts/og.html to website/public/og.png at 1200x630.
//
// CHROME_PATH=/path/to/chrome npm run og
//
// Uses puppeteer-core, the driver this package already carries for
// profile:runtime, so the card needs no browser dependency of its own.
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
import puppeteer from 'puppeteer-core';
const chromePath = process.env.CHROME_PATH;
if (!chromePath) {
throw new Error('Set CHROME_PATH to a Chromium/Chrome executable.');
}
const here = dirname(fileURLToPath(import.meta.url));
const source = resolve(here, 'og.html');
const target = resolve(here, '../public/og.png');
const browser = await puppeteer.launch({
executablePath: chromePath,
headless: true,
// Same pair profile:runtime uses, and for the same reason: the container and CI
// images this gets run in are root with a small /dev/shm.
args: ['--no-sandbox', '--disable-dev-shm-usage'],
});
const page = await browser.newPage();
await page.setViewport({ width: 1200, height: 630, deviceScaleFactor: 1 });
await page.goto(`file://${source}`, { waitUntil: 'networkidle0' });
// The fonts and the mark are the whole card; screenshotting before they arrive
// silently produces a fallback-font PNG that still looks plausible.
await page.evaluate(async () => {
await document.fonts.ready;
await Promise.all([...document.images].map((image) => (image.complete ? null : image.decode())));
});
// Guard the legibility contract. Feeds render this card as small as 320px wide — a
// 27% scale — so crowded, clipped, or re-wrapped type is worth failing over.
const problems = await page.evaluate(() => {
const pad = 72;
const width = 1200;
const height = 630;
// The statement hangs its box outside the padding by a deliberate optical inset,
// so the R's printed edge — not its box — lands on the padding. That slack is a
// CONSTANT on purpose: reading it back off the element under test would let any
// margin-left, however wrong, widen the very bound meant to catch it.
const opticalSlack = 12;
const found = [];
const label = (element) => element.className || element.tagName;
for (const element of document.querySelectorAll('.card p, .card h1, .card .brand-name')) {
const size = parseFloat(getComputedStyle(element).fontSize);
if (size < 30) found.push(`${label(element)} is ${size}px (< 30px)`);
}
const statement = document.querySelector('.statement');
const range = document.createRange();
for (const element of document.querySelectorAll('.statement .line, .foot p, .brand-name')) {
const leftBound = pad - (statement.contains(element) ? opticalSlack : 0);
range.selectNodeContents(element);
// One rect per inline box, not per line — "that" and "runs." are two boxes on
// one line, and a <br> contributes an empty one. Distinct tops is the line count.
const rects = [...range.getClientRects()].filter((rect) => rect.width > 0 && rect.height > 0);
const lines = new Set(rects.map((rect) => Math.round(rect.top))).size;
// Oversized type does not run past the padding — it wraps, quietly turning a
// two-line headline into three and pushing the composition out of the frame.
// One source line must stay one rendered line.
const expectedLines = element.classList.contains('brand-name') ? 2 : 1;
if (lines !== expectedLines) {
found.push(`${label(element)} renders ${lines} lines, expected ${expectedLines}`);
}
for (const rect of rects) {
if (rect.left < leftBound - 1 || rect.right > width - pad + 1) {
found.push(
`${label(element)} spans ${Math.round(rect.left)}-${Math.round(rect.right)}px ` +
`(bounds ${leftBound}-${width - pad})`,
);
}
}
}
// Nothing may run off the bottom: the card clips, so an overflowing block is
// invisible here and obvious in a feed.
for (const element of document.querySelectorAll('.lockup, .statement, .foot, .rule')) {
const rect = element.getBoundingClientRect();
if (rect.top < -1 || rect.bottom > height + 1) {
found.push(
`${label(element)} runs ${Math.round(rect.top)}-${Math.round(rect.bottom)}px vertically ` +
`(card is 0-${height})`,
);
}
}
return found;
});
if (problems.length) {
await browser.close();
console.error('og.png legibility check failed:\n ' + problems.join('\n '));
process.exit(1);
}
await page.screenshot({ path: target });
await browser.close();
console.log(`wrote ${target}`);