1
0
This repository has been archived on 2026-08-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tera/scripts/brand-assets/og.html
T
karti df9641cddd The share cards are photographs of the building that exists
Both cards re-rendered off the current engine, and the office card's own
copy fixed at its source: `og.html` said "one floor plan" while the
artwork behind it showed two storeys held apart around a commons. The meta
description in `vite.config.ts` and the words baked into the picture are
two different strings and only one of them had been corrected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 04:37:45 -07:00

219 lines
7.8 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Tera / Spaces — share cards</title>
<!--
One template, two doors, for the same reason the app is one bundle behind
two names: `?card=tera` and `?card=office` differ in four strings and one
background, and two files would drift the moment somebody adjusted the
scrim on one of them.
No webfonts. The card is rasterised by a headless browser on a box that may
or may not have network at the time, and a card whose type silently falls
back to Times is worse than one that never used a webfont — so this uses
the same system stack the app itself uses (`ui-monospace` throughout, with
Georgia for the headline, which is the face `index.html`'s own no-JS
fallback already sets).
1200x630 is the size every unfurler crops toward: Twitter/X's
`summary_large_image`, Open Graph's own recommendation, Slack, Discord,
iMessage, LinkedIn. Nothing important goes within 48px of an edge, because
several of them shave a few pixels and one of them rounds the corners.
-->
<style>
html, body { margin: 0; padding: 0; background: #06080b; }
.card {
position: relative;
width: 1200px;
height: 630px;
overflow: hidden;
box-sizing: border-box;
background: #06080b;
color: rgba(255, 255, 255, 0.92);
font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
/* The art is the product, shot from the running app — see `capture.mjs`.
`cover` plus a per-card origin, because the two shots want cropping
toward different halves of themselves. */
.art {
position: absolute;
inset: 0;
background-repeat: no-repeat;
background-size: cover;
}
/*
Two scrims, not one, and they do different jobs.
The horizontal one buys contrast for the type: the left 58% goes to
near-solid so a white headline sits on a known background rather than on
whatever pixel the render happened to put there — which is the failure
that makes screenshot-backed cards unreadable at timeline size. The
vertical one is a vignette that keeps the top and bottom edges from
competing with the corner text, and it is much weaker, because the whole
point is that you can still see the place.
*/
.scrim {
position: absolute;
inset: 0;
background:
linear-gradient(90deg, rgba(6, 8, 11, 0.97) 0%, rgba(6, 8, 11, 0.9) 38%,
rgba(6, 8, 11, 0.45) 62%, rgba(6, 8, 11, 0.12) 100%),
linear-gradient(180deg, rgba(6, 8, 11, 0.45) 0%, rgba(6, 8, 11, 0) 30%,
rgba(6, 8, 11, 0) 68%, rgba(6, 8, 11, 0.6) 100%);
}
/* The app's own hairline grid, at the app's own opacity. It is the one
piece of furniture both this and the lumbridgecorp.com card share, so
the two read as a family without being the same layout. */
.grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
background-size: 48px 48px;
}
.body {
position: absolute;
inset: 0;
padding: 64px 72px;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
}
.eyebrow {
display: flex;
align-items: center;
gap: 12px;
font-size: 17px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: #f2b134;
margin: 0 0 28px;
}
/* The same coin the lumbridgecorp.com card leads with. */
.coin {
width: 15px;
height: 15px;
border-radius: 50%;
background: radial-gradient(circle at 34% 30%, #ffe8ac, #f2b134 48%, #d9932b 100%);
box-shadow: 0 0 16px rgba(242, 177, 52, 0.45);
}
h1 {
font-family: Georgia, "Times New Roman", serif;
font-weight: 400;
font-size: 68px;
line-height: 1.04;
letter-spacing: -0.022em;
margin: 0 0 26px;
max-width: 15ch;
color: #f4f6f9;
}
.sub {
font-size: 21px;
line-height: 1.5;
letter-spacing: 0.005em;
color: rgba(255, 255, 255, 0.62);
margin: 0;
max-width: 30ch;
}
/* Bottom left, on the baseline the padding already establishes. The host
is the one string on the card that is not a claim about anything. */
.host {
position: absolute;
left: 72px;
bottom: 56px;
font-size: 18px;
letter-spacing: 0.14em;
color: rgba(255, 255, 255, 0.5);
margin: 0;
}
.host b { color: #ffd68a; font-weight: 400; }
.licence {
position: absolute;
right: 72px;
bottom: 56px;
font-size: 15px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.34);
margin: 0;
}
</style>
</head>
<body>
<div class="card">
<div class="art" id="art"></div>
<div class="scrim"></div>
<div class="grid"></div>
<div class="body">
<p class="eyebrow"><span class="coin"></span><span id="eyebrow"></span></p>
<h1 id="headline"></h1>
<p class="sub" id="sub"></p>
</div>
<p class="host">lumbridgecorp.com<b id="host"></b></p>
<p class="licence">Apache-2.0</p>
</div>
<script>
/*
Every string here is the project's own.
The headline for each door is the sentence `README.md` already uses to
say what that half is, and the sub-lines describe only what the code
actually does — a sun and moon computed locally, an office that renders
with no server at all, a licence that is in the repo root. A share card
is the most-read sentence a project has and the least reviewed, which is
exactly why it should not be the one place new claims get invented.
*/
const CARDS = {
tera: {
eyebrow: "Lumbridge Simulate",
headline: "Cities from above.",
// The last sentence is CONTRACT.md §0's acceptance test, in the words
// `main.ts` already uses for it.
sub: "A real sun and moon over a board you can fly around, and an office you can step into. Clone it and it works.",
host: "tera.",
art: "art-tera.png",
// Low, so the far edge of the board — where the terrain stops and the
// sky begins in a hard diagonal — stays out of frame. A card with the
// seam in it reads as a rendering fault rather than as a map.
position: "56% 88%",
},
office: {
eyebrow: "Lumbridge Spaces",
headline: "An office you can walk around.",
sub: "Two buildings, real hours, the lights on at night — rendered from a data file anybody can copy.",
host: "office.",
art: "art-office.png",
position: "62% 46%",
},
};
const which = new URLSearchParams(location.search).get("card") ?? "tera";
const card = CARDS[which] ?? CARDS.tera;
document.getElementById("eyebrow").textContent = card.eyebrow;
document.getElementById("headline").textContent = card.headline;
document.getElementById("sub").textContent = card.sub;
document.getElementById("host").textContent = "";
document.querySelector(".host").innerHTML =
'<b>' + card.host + '</b>lumbridgecorp.com';
const art = document.getElementById("art");
art.style.backgroundImage = 'url("' + card.art + '")';
art.style.backgroundPosition = card.position;
document.title = which;
</script>
</body>
</html>