< BACK TO OVERWORLD

BUILD GUIDE · EXPERIMENT 07

How OVERWORLD was built.

ONE SESSION · THREE PASSES · A PLAYABLE GAME · NO IMAGE FILES

PIXEL CANVASDAY / NIGHTCODE-DRAWN MASCOTPLAYABLE DEMO

THE IDEA

OVERWORLD is a fictional two-person pixel game studio. The brief was simple and demanding: the site itself should feel like one of their games. That meant a living world, a mascot with a face, and a demo you can actually play. Every pixel on the page is generated at runtime. There is not a single image file in the project.

CRISP PIXELS, THE EASY WAY

The whole aesthetic rides on one trick: set a canvas to a tiny internal resolution and let CSS blow it up with nearest-neighbor scaling.

canvas { image-rendering: pixelated; }
// hero buffer is only 256 px wide internally
heroCanvas.width = 256;
heroCanvas.height = Math.round(256 * cssHeight / cssWidth);

Drawing a 1x1 fillRect becomes a chunky ~6px block on screen, perfectly square, no blur. The game cabinet runs at 180x210, the catalogue previews at 112x80. Small numbers, big personality.

ONE MASCOT, DRAWN IN CODE

Meep, the pink creature, is not a sprite sheet. It is a function. The body is an ellipse test on the pixel grid, with a shadow band on the lower third and a highlight patch top-left; eyes, cheeks, a leaf sprout, and feet are stamped by coordinate. The same drawMeep() renders the 16px logo, the three studio avatars, the two idlers in the hero, and the player in the game. Change one line and every Meep on the page updates.

A WORLD THAT TURNS

The hero is a layered scene: a sky gradient, twinkling stars, a sun that cross-fades into a cratered moon, drifting clouds, three parallax hill layers built from sine waves, trees, floating coins, and the mascots. A single dayFactor from 1 to 0 lerps every colour between day and night. Tap the sky or hit the toggle and the factor eases across, dragging the whole palette (and the page chrome) with it.

THE BUG THE SCREENSHOTS CAUGHT

My colour helper returned an rgb(...) string, and the sky gradient nested it: mix(mix(a,b,ty), mix(c,d,ty), f). The outer mix then tried to parse "rgb(23,16,70)" as hex, produced NaN, and the canvas silently kept its previous fill. The sun, hills, and clouds drew fine on top, so at a glance it looked plausible, but the day sky was rendering near-black. Pass 1 screenshots made it obvious. The fix was one line: teach the hex parser to also accept rgb() strings so the mix could safely nest.

A DEMO YOU CAN ACTUALLY PLAY

Coin Dash is a real 60fps mini game with a proper state machine (ready → play → over), keyboard, pointer drag, and touch controls, a spawn director that speeds up with your score, coin chains for double points, three lives, and a best-score memory. It shares the same pixel renderer and mascot as the rest of the site, and its background respects the day-night toggle too.

DETAILS THAT EARN THE RETRO LABEL


Live site: buloy.space/x/overworld · All experiments: buloy.space/x