{Shelf Pop–Triple Match} Project Report
1. The Concept
Shelf Pop! is a portrait, mobile-first cozy sorting game. The player runs a tiny juice shop: drinks sit in wooden cubbies, and the job is to tidy the shelves before the timer hits zero.
The loop is simple to show and hard to rush:
- Drag a bottle from one shelf to another.
- Put three of the same drink on one shelf to POP them.
- Clear the board to win stars and coins.
There is no holding tray. Every move is a shelf-to-shelf choice, so the puzzle is spatial, not a dump-and-sort. Similar colors are kept in families so the board stays readable. Boosters (Hint, Shuffle, Undo) help beginners without removing the timer pressure that experts play against.
The shop is the reward layer, not the core. Coins buy decorations for the storefront. Language is English and Khmer. The feel is peach, mint, wood, and 3D buttons — a mini-market, not a dark arcade.
Unique hook: triple-match on the shelf itself, with a different shelf shape and wood skin every level.
2. The Stack
No engine, no bundler, no backend.
- HTML5:
index.html— home, game, shop, shared modal - CSS3:
style.css— mobile-first layout, shelf skins, 3D buttons, overlays - Vanilla JavaScript:
script.js— levels, drag, matching, save, audio - localStorage: coins, stars, level, language, sound, tutorial flag, shop items
- Web Audio API: SFX plus a looping synthesized song (no mp3 files)
- Google Fonts: Nunito
- Raster UI: WebP icons (language, pause, hint, shuffle, undo, back, star)
- Persistence key:
shelfPopSave
Play it by opening index.html on a phone or in a desktop browser. Portrait is the target. The game is a PWA-ready web shell (apple-mobile-web-app tags, safe-area padding).
3. The 1 Day Sprint (+ polish pass)
Morning (Hours 1–3):
Locked the core loop first. Built the shelf board, CSS drink sprites, and pointer drag (item leaves the cubby immediately, ghost follows the finger). Drop rules: empty slot appends, full shelf can swap, otherwise snap back. Match-3 POP on one shelf, combo popup, timer HUD, Hint / Shuffle / Undo. Incremental DOM updates on drop so the board does not rebuild every move. fitBox scales drinks to cubby size, not item count.
Afternoon (Hours 4–6):
Wrapped a real product around the loop. Home screen (peach–mint gradient, PLAY / SHOP), shop with buyable decor, win modal, pause (retry + home, tap outside to resume — no RESUME button). English / Khmer copy. localStorage for progress. Coin economy and star tracking. Power-row layout fought CSS order (later unscoped rules kept winning); the fix was to put .game-screen .power-row at the end of the stylesheet.
The Finish Line (Hour 7-8):
Shipped a playable 20-level path. Each level has its own type count, packing style, wood skin, corner shape, and cubby layout (I, H, diamond, stairs, zigzag, 3×3). Home stars cap at 60. After level 20, NEXT goes home. Mobile fit pass: HUD, compact power buttons, drinks flex-centered in cubbies. Visibility-change pauses the run without fighting an already-open modal.
Polish (Aug 10):
New-user intro on level 1 (drag, match three, boosters) with icon diagrams and a hand; timer stays frozen until LET’S POP. Sound toggle plus pickup / drop / pop / win / lose SFX. Language and sound folded into one globe icon with a two-option menu. Pause and Time’s Up restyled to cream cards, gold badges, and 3D pills; CONTINUE removed from Time’s Up. Looping cozy song on Web Audio, ducked during pause and end screens.
4. The Roadblocks
- CSS cascade: power-button size and gap kept reverting because later global
.power-rowrules overrode media queries. Lesson: one source of truth at the bottom ofstyle.css. - Drag vs. layout: full
renderBoard()on every drop felt sluggish and broke pointer identity. Incremental DOM (splice,layoutBox, swap in place) was required. - Scale bugs: fitting drinks by item count made full shelves look tiny. Fit from cubby width/height only.
- Tutorial flag existed (
tutorialDone) but did nothing until the intro overlay was wired; retry of level 1 must not replay it. - No audio files: SFX and music had to be synthesized so the game still works offline.
- i18n leftover: Time’s Up showed the raw key
adBodyuntil the lose copy was fixed. - Icon mix-up: two home icons (language + sound) needed to become one control without losing either option.
- Scope creep on pause/win: RESUME, always-on combo bar, and ResizeObserver were tried and then removed to keep the board stable.
5. Key Takeaways
- Ship the verb first (drag → pop), then screens, then juice (sound, intro, shop).
- On a single CSS file, order is architecture. Unscoped utilities will silently crush component rules.
- Mobile puzzles live or die on pointer feel. Ghost drag, swap, and snap-back have to be decided before art polish.
- Constraints make the hook: no tray forces real shelf planning; families keep colors honest; 20 distinct layouts keep “level 12” from looking like “level 2.”
- A first-run intro with icons beats a wall of text, especially with mixed Khmer / English players.
- Mute is part of audio. If you add a song, duck it on pause and honor ON / OFF.
My final thought:
Shelf Pop! is a small web game with a clear promise: tidy the shelf, pop the triple, beat the clock. The stack stayed boring on purpose so the feel could stay sharp. The work that mattered was not more systems — it was making one drag, one pop, and one cream pause card feel like a real phone game.