The games section launched with two tiny games. Neither took long to build, and that was the point. Some notes from the process.
Scope is the whole game
A snake game has maybe five rules: move, eat, grow, speed up, die. That's a weekend project with room left over for polish — and polish is what makes a tiny game feel finished rather than abandoned. Score persistence, a pause state, swipe controls on touch screens: each is an hour, and together they're the difference between a demo and a game.
Canvas, but let CSS pick the colors
The snake board is a <canvas>, but it reads its palette from the same CSS
variables the rest of the site uses:
function readToken(name: string, fallback: string) {
return getComputedStyle(document.documentElement)
.getPropertyValue(name)
.trim() || fallback;
}
ctx.fillStyle = readToken("--ember", "#f54e00");Toggle dark mode and the game re-inks itself on the next frame. One design system, everywhere — including inside the games.
Keep React out of the game loop
React re-renders are for UI, not for a 10-tick-per-second game loop. The snake's state lives in refs; React only hears about it when the score changes or the game ends:
const snake = useRef<Point[]>([]);
const dir = useRef<Point>({ x: 1, y: 0 });
// ...the interval mutates refs and repaints the canvas directlyFinish and ship
The least glamorous lesson: a small finished game beats a big unfinished one every time. Ship the snake. The bigger ideas can wait their turn on the coming-soon card.