A game whose whole mechanic is other people is spread by one person pasting the address to another.
Pasted into a chat today, drift shows nothing: <link rel="icon" href="data:,"> is an empty image, and
the document carries a <title> and a description and no card at all.
Done looks like
[ ] An icon that is really an icon: one small SVG under static/, linked by content through
asset(), and an apple-touch-icon sized so a phone home screen gets something. The empty
data:, is gone.
[ ] Open Graph and Twitter card tags in the head — title, description, a card image, the canonical
URL built from publicOrigin and never from a header a client sent — so a pasted link previews as
the sea rather than as a bare domain.
[ ] The card image is generated by the app rather than drawn by hand: an SVG (or a small PNG route)
that shows the arena and the one rule, served with a long cache and a version in its address.
It never contains a player's name, so it cannot leak who was playing.
[ ] robots.txt: the page is crawlable, and the routes that are not pages are not — the crawler
must never take a seat (#11 makes joining a socket event for exactly this reason, and this is the
other half of it).
[ ] The head stays small: every tag added is in the first paint, nothing blocks rendering, and the
budget in #21 still passes with room to spare.
[ ] A test asserts the canonical URL and the card tags are built from publicOrigin, and that a
Host or X-Forwarded-Host header from a client cannot change them.
Filessrc/page.ts, src/routes.ts, static/ (new icon, new card), src/server.test.ts.
Risks The canonical URL is the security-shaped part: built from a request header it becomes a way
to make the app advertise somebody else's address, which is why publicOrigin is the only source and
a test says so. The card image is easy to over-build — one static SVG that says what drift is beats a
live render of a round nobody is in.
Waits on #7, which owns src/page.ts and the head until it lands. Fits Quill's brief.
A game whose whole mechanic is other people is spread by one person pasting the address to another. Pasted into a chat today, drift shows nothing:
<link rel="icon" href="data:,">is an empty image, and the document carries a<title>and a description and no card at all.Done looks like
static/, linked by content throughasset(), and anapple-touch-iconsized so a phone home screen gets something. The emptydata:,is gone.URL built from
publicOriginand never from a header a client sent — so a pasted link previews as the sea rather than as a bare domain.that shows the arena and the one rule, served with a long cache and a version in its address. It never contains a player's name, so it cannot leak who was playing.
robots.txt: the page is crawlable, and the routes that are not pages are not — the crawlermust never take a seat (#11 makes joining a socket event for exactly this reason, and this is the other half of it).
budget in #21 still passes with room to spare.
publicOrigin, and that aHostorX-Forwarded-Hostheader from a client cannot change them.Files
src/page.ts,src/routes.ts,static/(new icon, new card),src/server.test.ts.Risks The canonical URL is the security-shaped part: built from a request header it becomes a way to make the app advertise somebody else's address, which is why
publicOriginis the only source and a test says so. The card image is easy to over-build — one static SVG that says what drift is beats a live render of a round nobody is in.Waits on #7, which owns
src/page.tsand the head until it lands. Fits Quill's brief.