BUILD GUIDE · EXPERIMENT 07
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.
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.
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.
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.
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.
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.
6px 6px 0) and press-down button states, no soft blur anywhere.prefers-reduced-motion the world renders one static frame; the game still plays because that motion is something you chose.IntersectionObserver, and DPR work is avoided entirely by staying low-res.Live site: buloy.space/x/overworld · All experiments: buloy.space/x