Building a game that behaves like a desktop widget, choom
Cozy Coast is an Electron and Phaser game built as a borderless desktop widget first, choom, which changes the window model, the render budget and the packaging pipeline.
Cozy Coast is a fishing game, and the least interesting thing about building it was the fishing. The hard requirement was the window.
It had to be a small borderless panel in the corner of your screen. It had to go in front of your other windows or behind them, on request. It had to keep running at full tilt while it was completely buried. And it had to survive being ignored for six hours without turning into a problem.
That is a desktop widget. A game engine is not built for it, choom.
Why Electron and not a game framework
Most engines assume they own a window and probably the whole screen. Their window handling is built for fullscreen, borderless-fullscreen and a resizable game window, in that order of care. Everything I needed sits outside that list: no window chrome, always-on-top toggling, click-through behaviour, and a footprint measured in a corner of a monitor rather than a resolution.
Electron already solves those, because a decade of desktop apps have needed them. So the shell is Electron, Phaser draws the coast inside it, and TypeScript runs across the main process, the renderer, and the message types shared between them. Clean loadout, no bloat.
That shared-types boundary is the part I would keep in any build of this shape. The main process owns the window, the Steam integration and the save file. The renderer owns the game. Every word between them runs through one typed contract, so a message that changes shape flatlines at compile time instead of showing up as an undefined field somewhere deep in a fishing loop.
The buried-window problem
Browsers throttle hidden content hard, and they are right to. A background tab has no business running a render loop at sixty frames a second. Chromium cuts timer frequency and stops painting the moment it decides nobody is looking.
For a widget whose whole pitch is that it keeps going while you ignore it, that default is a bug. An angler who buries the window behind their editor for two hours and comes back to two hours of nothing has been quietly rolled.
So the widget keeps fishing at full rate while it sits behind your other windows. Getting there meant splitting the two things throttling smashes together: the simulation, which has to keep ticking on wall-clock time no matter what gets painted, and the drawing, which genuinely can stop when nothing is visible. Once those are split, being buried is a rendering call instead of a gameplay one.
Offline progress, and the taper
Closing the game is the extreme case of the same problem. Cozy Coast catches up on launch and hands you a “while you were away” rundown of what went down.
The catch rate tapers the longer you stay gone. A choom who checks in daily earns more than one who cracks it open once a fortnight, and that is a design call rather than a technical limit. A flat offline rate turns the game into a spreadsheet you visit sometimes. A tapering one makes a daily check-in worth eddies without ever punishing you for missing a day, because there are no timers to beat and no way to fall behind.
One pipeline, two platforms
The build spits out Windows and macOS from a single packaging pipeline, into one Steam build carrying a depot per operating system. Store art and banners get generated from the real game rather than drawn by hand.
That is the least nova part of the build and probably the highest leverage. Every hour I do not burn on a release checklist is an hour I spend making fish. When one choom is doing all of it, the pipeline is not overhead. It is the thing that decides how much game gets made.
It runs on Windows and macOS, and the coast is at cozycoast.website. Come see it.