The drawing is right — three wakes braiding into one lane, two motes riding it, the bloom leaving through the gate on the rim: the whole rule as geometry, with no player's name in it. What is wrong is the frame and the weight. The arena square sits in the middle with roughly a third of the width dark on each side, and chat clients do not show a 1200×630 card at 1200×630: they crop it toward a square or scale it to about 360 px. Cropped square a reader loses the rim and the gate — the part that says where the bloom is going — and at 360 px wide the gate is a line one pixel thick. Until #CANVAS lands this is the only picture of the game anyone sees.
Done looks like
[ ] The card reads at the two sizes it is actually seen at: a square centre crop and a 360 px-wide scale both still show the braided lane, the bloom, and the gate it is going through. The pull shows both, downscaled, rather than asserting it.
[ ] The bytes come down to a stated ceiling held by a test — 60 KB at 1200×630 is a suggestion — and it is reached by drawing and encoding, not by shrinking the picture. The star field and the per-pixel noise are what a deflate stream cannot compress; the pull says what actually made the difference.
[ ] The touch icon gets the same pass: 20 KB for a 180×180 square that a phone shows at the size of a fingernail, drawn from the same painter, legible at that size.
[ ] src/png.ts keeps its shape — adaptive filters, one IDAT, node:zlib and nothing else. If the encoder gains an option (a palette, fewer bits per channel) it is an option this app uses, with a test in src/png.test.ts, not the beginning of a general PNG library. No image dependency.
[ ] Nothing the card promises changes: still 1200×630 and 180×180, still no player's name and no text the OG tags do not already carry, still addressed by the hash of its own bytes and cached a year at a versioned address — the existing tests in src/server.test.ts stay green without being edited.
Risks A byte ceiling is a leash on a hand-drawn picture: if the card is genuinely better at 90 KB, move the ceiling in the pull and say why, rather than making the sea flat to hit a number. The noise and the stars are what make it look like water — thin them, do not delete them.
Fits Quill's brief (the eye and the words a link carries); the encoder half is Vesper's if png.ts has to change.
Fetched from production on
main, not read from the source:The drawing is right — three wakes braiding into one lane, two motes riding it, the bloom leaving through the gate on the rim: the whole rule as geometry, with no player's name in it. What is wrong is the frame and the weight. The arena square sits in the middle with roughly a third of the width dark on each side, and chat clients do not show a 1200×630 card at 1200×630: they crop it toward a square or scale it to about 360 px. Cropped square a reader loses the rim and the gate — the part that says where the bloom is going — and at 360 px wide the gate is a line one pixel thick. Until #CANVAS lands this is the only picture of the game anyone sees.
Done looks like
src/png.tskeeps its shape — adaptive filters, one IDAT,node:zliband nothing else. If the encoder gains an option (a palette, fewer bits per channel) it is an option this app uses, with a test insrc/png.test.ts, not the beginning of a general PNG library. No image dependency.src/server.test.tsstay green without being edited.Files
src/card.ts,src/png.ts,src/png.test.ts,src/server.test.ts.Risks A byte ceiling is a leash on a hand-drawn picture: if the card is genuinely better at 90 KB, move the ceiling in the pull and say why, rather than making the sea flat to hit a number. The noise and the stars are what make it look like water — thin them, do not delete them.
Fits Quill's brief (the eye and the words a link carries); the encoder half is Vesper's if
png.tshas to change.