4 min read

Generating a press kit from the running game

Twelve social cards built from HTML and CSS templates, filled with real screenshots captured from the running game, and rebuilt with one command instead of a design tool.

The Cozy Coast press kit is twelve images. Six Instagram stories at 1080 by 1920, six LinkedIn cards at 1200 by 627, covering the Early Access launch and the multiplayer hub release.

No design tool was opened to make any of them. They are HTML and CSS, rendered by a small Python script, and the screenshots inside them are captures of the game actually running.

Three commands

npm run press:capture                          # real screenshots from the running game
.venv/bin/python scripts/press-assets.py       # cut them into build/presskit/assets/
.venv/bin/python build/presskit/render.py      # every card, launch kit and hub kit

The first one launches the game and captures it. That distinction matters more than it sounds. The other anglers visible in the hub cards are genuine remote avatars reacting to real session events, so the party list, the name plates, the emote pops and the join notice are all live UI rather than mock-ups.

A press kit built from mock-ups is a promise. A press kit built from captures is a screenshot. If the UI shifts and the cards stop matching the game, I find out when I regenerate, not when a player does.

Why HTML and CSS beat a design file

Every template lives in build/presskit/templates/ and shares one stylesheet, kit.css, which mirrors the site design system. That gets me four things a binary design file does not.

I can diff it. A change to a card shows up in a pull request as changed lines, not as a file that is simply different now.

I can restyle everything at once. When the site palette changed, the press kit changed with it, because the cards were already reading from the same tokens rather than from colours somebody had eyedroppered a year earlier.

I can open one in a browser and tweak it live, then rerun the render. The authoring loop is the one I already use every day.

And there is no seat, no licence, and no file that only opens on one machine.

The sizes are the whole job

Most of the actual work in a press kit is not visual. It is fitting text inside the region a platform will not cover or crop.

Instagram stories are 1080 by 1920, and the platform draws its own furniture over the top and bottom of that. The profile row sits over the top. The reply bar sits over the bottom. So every word in the story cards sits inside the safe area, which means the stories carry their own text and can be posted with no caption at all. Add a link sticker to the store page and they are done.

LinkedIn cards are 1200 by 627, which is the 1.91 to 1 landscape slot the feed crops to. Hand it anything else and the feed decides what to trim, usually the part with the title on it.

Encoding those constraints in CSS means they hold. A card cannot accidentally drift into the reply bar between releases, because the layout is a rule rather than a judgement somebody made once with a ruler.

Steam patch notes are a different animal

Steam’s news editor takes BBCode, so the hub release announcement lives as steam-patchnotes-hub.bbcode.txt and gets pasted in.

Its image tags point at copies served from the marketing site rather than at uploads, because the news editor does not reliably give you an upload. So the press images are copied into the site’s public folder and deployed, where they resolve at a stable URL:

cp build/presskit/out/{li,ig}-*.png docs/website/public/press/

Those files are deliberately unlinked. Nothing on the site navigates to them. They exist to resolve, which is a slightly odd category of asset and worth writing down somewhere so future me does not delete them as orphans.

The part that is still manual

The tally numbers on the stat cards are baked in as text. There are 160,966 fish and 50,418 seagulls sitting in a template as literal characters, and if the tally has moved they have to be refreshed from https://cozycoast.website/api/global before a rerun.

I could fetch them at render time. I have not, and I am not sure I should. A press card is a claim about a moment, and a card that quietly restyles itself with new numbers every time the script runs is harder to reason about than one where updating the figures is a decision I made. The note in the README is doing the job for now.

That is the honest state of it: a pipeline that is fully automatic where automation is obviously right, and deliberately manual at the one point where a number becomes a public claim.

The game those cards are advertising is at cozycoast.website, on Steam for Windows and macOS.

Let's connect.

Always happy to talk shop, compare notes, or just say hi. Email or LinkedIn is the fastest way to reach me.

Get in touch