Skip to content

About

Block Party - a gentle block puzzle for little hands, built on gamekit

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

22 Commits

Folders and files

Repository files navigation

Block Party 🎉

A block-puzzle game for the whole family. Drag the coloured pieces onto the board and fill a whole row or column to make it sparkle and clear — but the pieces are big and awkward, so mind how you fill the board or you'll run out of room. Modelled on the "Block Puzzle" app, tuned to challenge a capable player (and played by both daughters).

Play it: https://rvenning.github.io/block-party/

Features

  • 🧩 Classic block puzzle: drag pieces onto an 8×8 grid, clear full rows and columns
  • 🧱 A meaty piece mix — pentominoes, long bars and awkward L/T/S shapes — that fills the board fast and makes you plan ahead
  • 🔥 Combo streak: clear a line on consecutive placements and each one is worth more (×1.5, ×2, ×2.5…)
  • 💥 Steeper multi-line bonuses, plus a confetti Super Clear for emptying the whole board
  • 🪙 Coins for every line cleared; ⭐ your best score is remembered
  • 🏁 Runs really end — if a crowded board can't take any of your three pieces, the game's over; the result screen still celebrates the score
  • 👨‍👩‍👧 Pick-a-name family profiles — no passwords; optional 4-digit PIN per profile with an admin override
  • 🦄 Your profile avatar is your player; kid-friendly avatar set
  • 🏆 Shared family leaderboard (best score)
  • 🔊 All sound effects synthesized with WebAudio (no asset downloads)
  • ☁️ Firebase Firestore sync (falls back to localStorage offline)
  • 🎨 Hand-drawn feel: a lit party room with bunting, balloons and confetti on the floor — all of it clipped to outside the board, so nothing ever covers a block
  • 📱 iPad-first: big touch targets, the dragged piece floats above the finger; works with a mouse on desktop
  • 📲 Installable PWA: "Add to Home Screen" button, offline play via service worker

Scoring

  • +1 per cell placed
  • +10 per line cleared, plus a +20 × (lines − 1) bonus for clearing several at once
  • Combo streak: clearing a line on consecutive placements multiplies the clear points (×1, ×1.5, ×2, …); a placement that clears nothing resets it
  • Coins = lines cleared; a full-board Super Clear adds +50
  • Progress { best, coins, lines, games, sver } reconciles across devices by keeping the max of each field within a score season (sver). Bumping the season retires the previous scores everywhere — because the sync merges by max, that's the only way a reset can't be resurrected by an old high score on another device.

Built on gamekit

Profiles, PINs, storage/sync, the sound engine, base UI styles and the PWA kit come from rvenning/gamekit, vendored into lib/. To pull in a newer kit version:

# from the gamekit repo
node tools/sync-to-game.js "D:\OneDrive\Documents\Claude Code\block-party"
# then test, bump the CACHE version in sw.js, and commit

Everything game-specific lives in js/:

File What's in it
js/firebase-config.js the shared project's (public) config
js/pieces.js the seven party colours, every shape, and the weights that set the difficulty
js/game.js the rules: fitting, placing, clearing, scoring. DOM-free, so the tests can run it
js/storage.js progress and the score season
js/audio.js the game's own jingles on gamekit's synth
js/art.js the party room and what a block looks like
js/render.js layout, input, the frame loop, the feedback
js/main.js profiles, screens, the results sheet, the wiring

game.js never touches the page. It pushes presentation events onto a queue (place, clear, super, stuck) and render.js drains them and makes the noise — which is what lets the whole engine be replayed in Node with no browser.

Tests

npm test      # node --test

tests/golden.txt is five complete runs — 340 placements — captured from the original single-file version before any of this was refactored. tests/engine.test.js replays them through a seeded dealer and a deterministic bot and asserts every placement, score, line count, coin and combo streak comes out identical, plus the piece registry, the scoring rules and the end-of-run condition.

If those tests fail, the game changed. Find the change and take it back out; don't re-bake the golden file unless a rule was deliberately altered.

The look

Block Party is one question asked over and over: will this piece fit there, and which of my three should I spend? Everything in js/art.js exists to make that easier to answer, and nothing in it is allowed to make it harder.

That gives the art one hard constraint. The engine can fill all 64 cells and all three tray slots, so the occlusion budget over the board and the tray is zero — no decoration may ever sit in front of a block. It isn't enforced by being careful: every layer that draws in front (bunting, the vignette, the glitter, the balloons, the party lights) goes through Art.clipOutsidePlay, which is an even-odd clip of the whole canvas minus the board minus the tray.

The rest of it:

  • The room is baked. The empty grid, the table, the tray shelf and the litter on the floor never change, so they are painted once into an offscreen canvas and blitted — one drawImage instead of 64 rounded rects and a hundred scraps of confetti every frame. Rebuilt only on resize.
  • The landing preview is not a translucent block. At 45% opacity on a busy board it was being read as a block that was already there. It's an outlined socket with a coloured glow now — a promise, not a thing.
  • A piece that can't go where you're holding it says so before you let go. It loses its colour and sits in a red glow. This was the game's central question and it had no feedback at all: the only "no" was a beep after the drop failed.
  • A refused piece flies home instead of vanishing, which read as the game eating it.
  • A dead tray piece loses its colour and goes still. Dimming alone wasn't enough — a faded orange still reads as orange next to a bright one.
  • Everything that moves multiplies by Art.motion, so prefers-reduced-motion is one number set to zero (plus the usual blanket CSS query).

PWA files

  • manifest.json — app identity: name, icons, standalone display, theme colours
  • sw.js — service worker; precaches the app shell (including lib/, js/ and css/), then network-first with cache fallback. Bump CACHE whenever a shell file changes, or devices keep serving the copy they already have
  • icons/ — 192/512 PNG app icons plus a maskable variant, generated by tools/make-icons.js (no image tools needed — pure Node)

Local development

No build step — plain HTML/JS. Serve the folder with any static server:

npx http-server . -p 8098 -c-1   # http://localhost:8098

Regenerate the icons after changing the art:

node tools/make-icons.js

Deploys are just pushes to main (GitHub Pages).

Canvas note: the <canvas> needs an explicit CSS size (#cv { width:100%; height:100% }). A canvas is a replaced element, so position:absolute; inset:0 alone won't stretch it — without a CSS size it renders at its attribute size (W × devicePixelRatio), which is 2–3× too large on retina screens. This is invisible on a desktop preview but overflows on any iPhone/iPad.

Storage

Progress lives in localStorage (keys bp_*) and mirrors to Cloud Firestore (collection blockparty, same Firebase project as WordVoyage and Chicken Cross). The Firebase API key in js/firebase-config.js is public by design — it only identifies the project; access is limited by Firestore security rules, and the key is referrer-restricted to the game's domains and locked to the Firestore API.

About

Block Party - a gentle block puzzle for little hands, built on gamekit

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages