Whack-a-mole, swamp edition. Mosquitoes spawn from the reeds and drift in lazy loops — click to swat. Don't hit the dragonflies; they eat mosquitoes for you (a swatted dragonfly costs you score and combo). The swamp narrates as you go. Reach 30 and the swamp sleeps.
A tension-release minigame. Drop it on a 500 error page ("something is buzzing where it shouldn't"), or as a between-section breather in a long page. The narrative messages make it more than a stress ball: every swat is part of a small story about the swamp finally getting some quiet.
Arena, HUD, swatter that follows the cursor, narrative + sleep overlay.
<div class="arena" id="arena" data-quota="30" data-spawn-ms="900"> <div class="hud">...score / combo...</div> <div class="swatter" id="swatter">...svg...</div> <div class="narr" id="narr"></div> <div class="sleep" id="sleep">...endgame...</div> </div>
Each bug picks an edge spawn, a target heading, and a wobble (sine modulation perpendicular to its heading). Dragonflies fly straighter and faster. Both have a generous click-radius so the swatter feels accurate without being trivial.
// spawn one bug function spawnBug(kind){ const rect = arena.getBoundingClientRect(); const side = Math.floor(Math.random() * 4); let x, y, vx, vy; if (side === 0) { x = 0; y = Math.random() * rect.height; vx = .5+Math.random(); vy = (Math.random()-.5); } if (side === 1) { x = rect.width; y = Math.random() * rect.height; vx = -.5-Math.random(); vy = (Math.random()-.5); } if (side === 2) { x = Math.random()*rect.width; y = 0; vx = (Math.random()-.5); vy = .5+Math.random(); } if (side === 3) { x = Math.random()*rect.width; y = rect.height; vx = (Math.random()-.5); vy = -.5-Math.random(); } const speed = kind === 'df' ? 1.4 : 0.9; return { kind, x, y, vx: vx*speed, vy: vy*speed, t: Math.random()*9, alive: true }; } // every frame: wobble + drift bug.vx += Math.cos(bug.t) * (bug.kind === 'df' ? .03 : .06); bug.vy += Math.sin(bug.t * 1.3) * (bug.kind === 'df' ? .03 : .06); bug.x += bug.vx; bug.y += bug.vy; bug.t += 0.05;
The swamp speaks at score milestones. Replace these with your own copy.
const NARRATIVE = { 3: 'the air is thinning', 8: 'the bog notices', 14: 'the reeds are grateful', 21: 'the herons can hear themselves think', 30: 'the swamp sleeps' }; const SCOLD = { 1: 'a dragonfly! she was helping.', 3: 'the dragonflies are not the enemy.', 5: 'the swamp is shaking its head.' };
| Where | Default | Effect |
|---|---|---|
HTML data-quota | 30 | Score needed to trigger the "swamp sleeps" endgame. |
HTML data-spawn-ms | 900 | Average ms between spawns. Lower = swarm mode. |
JS DF_RATE | 0.18 | Probability each spawn is a dragonfly (so don't go too high). |
JS CATCH_R | 26 px | Click radius. Higher = more forgiving swat. |