Building a game that behaves like a desktop widget
Cozy Coast is an Electron and Phaser game built as a borderless desktop widget first, 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 working at full speed while it was completely obscured. And it had to survive being ignored for six hours without becoming a problem.
That is a desktop widget. A game engine is not really built for it.
Why Electron and not a game framework
Most engines assume they own a window and probably the 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 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.
That shared-types boundary is the part I would keep in any project of this shape. The main process owns the window, the Steam integration and the save file. The renderer owns the game. Every conversation between them goes through one typed contract, so a message that changes shape breaks at compile time instead of arriving as an undefined field somewhere in a fishing loop.
The obscured-window problem
Browsers throttle hidden content aggressively, and they are right to. A background tab has no business running a render loop at sixty frames a second. Chromium will cut timer frequency and stop painting when it decides nobody is looking.
For a widget whose entire selling point is that it keeps going while you ignore it, that default is a bug. A player who buries the window behind their editor for two hours and comes back to two hours of nothing has been quietly robbed.
So the widget keeps fishing at full rate while it sits behind your other windows. Getting there meant separating the two things that throttling conflates: the simulation, which must keep ticking on wall-clock time regardless of paint, and the drawing, which genuinely can stop when nothing is visible. Once those are separate, being hidden is a rendering decision 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 shows you a “while you were away” summary of what happened.
The catch rate tapers the longer you stay away. Somebody who checks in daily earns more than somebody who opens it once a fortnight, and this is a design choice rather than a technical limit. A flat offline rate makes the game a spreadsheet you visit occasionally. A tapering one makes a daily check-in worth something 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 produces Windows and macOS from a single packaging pipeline, into one Steam build carrying a depot per operating system. Store art and banners are generated from the real game rather than drawn by hand.
That is the least glamorous part of the project and probably the highest leverage. Every hour I do not spend on a release checklist is an hour I spend making fish. When one person 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.