Devlog

Notes on building Easter Hop — a browser game made entirely in vanilla HTML5 Canvas.

#4 — Mobile Polish & Global Leaderboard

featuremobilebackend

The local high score was fine for solo play but felt lonely. I added a global top-3 leaderboard backed by Supabase — a Postgres database with a simple REST API. No backend server required; the game posts scores directly from the browser using fetch().

When a score qualifies for the top 3, the game transitions to a name-entry screen. Getting the keyboard to pop up on iOS was the trickiest part: canvas elements can't receive focus, so I added an off-screen <input> element that gets programmatically focused. Android triggers the keyboard automatically on focus; iOS Safari requires the focus call to originate from a touch event, so I hooked it into the touchstart listener.

Also fixed a longstanding visual bug where Easter eggs and clouds appeared to jump up and down. The root cause was computing their vertical position from the current pixel offset, which changed every frame. Switching to a slot-index-based hash — where each cloud or egg derives its position from a stable integer ID — made them scroll smoothly.

#3 — Fireworks, Fences & Lawn Decorations

gameplayvisual

Three visual improvements this sprint. First, the brown wall-style obstacles got replaced with proper white picket fences — posts, horizontal rails, vertical planks, and pointed picket tips that extend into the gap from both sides. The fence body is off-white with a subtle shadow rail and a highlight strip on the leading edge of each post.

Second, Easter eggs now sit on the lawn and scroll past with the ground. They're tiny 8×10 pixel ovals in four color variants (pink, blue, yellow, lavender) with a white horizontal stripe. Combined with the scattered background flowers, the world feels genuinely inhabited.

Third: every 10 fences cleared triggers a small firework burst. 28 particles fan out from the bunny in all directions using Easter egg colors, with a slight upward bias and individual fade-out. It reuses the existing particle pool with no new data structures.

#2 — Easter Hop: The Rebrand

designart

With Easter approaching I decided to transform the game's entire visual identity. The copper robot mole became a cream-white Easter bunny, drawn in the same 17×14 pixel grid. The bunny has pink ear interiors, a rose nose, dark eye pupils, blush cheeks, and shadowed paws — all defined by a colour key lookup table so no image assets are needed.

The underground cyber-cave aesthetic gave way to a spring meadow that transitions to golden summer as your score climbs. Two palette objects (SPRING and SUMMER) define sky, ground, obstacle, and particle colours; every frame lerps between them based on score. At score 30 the transformation is complete — the sky deepens to summer blue, ground turns rich green, and flower petals shift from pink blossoms to sunflower yellow.

Obstacles changed from server racks to wooden garden fences. The background gained scrolling clouds (three overlapping rectangles per cloud, parallax at 0.18× game speed), scattered pixel flowers in a two-pass render (centers first, then petals, to minimise canvas state changes), and a simple sky gradient.

#1 — Building the Core: Molt the Mole

architecturegameplay

Easter Hop started life as "Molt the Mole" — a Flappy Bird-style runner with a copper robot mole navigating server racks in an underground tunnel. The entire game runs in a single HTML file with no dependencies, no build step, and no external assets. Everything — sprite, physics, particles, UI — is rendered on an HTML5 Canvas element using the 2D API.

The game loop uses a fixed-timestep accumulator pattern: wall-clock delta time is accumulated and consumed in 16.67 ms (60 Hz) chunks. This decouples update logic from render rate and prevents the simulation from running at different speeds on different devices.

The player character is a 17×14 pixel sprite defined as an array of character strings, each character mapping to an RGB colour. At render time the sprite is drawn as a grid of filled rectangles scaled by MOLE_SIZE = 3. Canvas save() / restore() handle the rotation and squash-stretch applied on flap. Physics are simple: constant gravity accumulates into a vertical velocity clamped at terminal velocity; a flap applies an upward impulse.

Obstacle gaps shrink and scroll speed increases with score, creating a smooth difficulty ramp without abrupt jumps. A particle pool of 80 pre-allocated objects handles both flap dust and the death burst — avoiding mid-game garbage collection pauses by never allocating new objects during play.