Tower Stack Timing Game — Click-to-Drop Block Stacker with Real Overlap Physics
Tower Stack Timing Game · Games · Plain HTML, CSS & JS · Live preview
For supporters
Source Code
Want the source code?
Play the game for free. Become a WebDevPuneet supporter to unlock the complete HTML, CSS and JavaScript source code, the exports (HTML, React, Vue, Angular, Tailwind) and Fork.
Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Tower Stack Timing Game — Real Overlap Math, Not a Scripted Sequence

This is a complete implementation of the classic "stack the moving block" timing game: a block slides back and forth, the player taps to drop it, and it locks into place based on how much it actually overlaps the block beneath it — narrowing the tower with every imperfect placement, exactly like the real mechanic this genre is built on.
Overlap is computed geometrically, not guessed
placeBlock() computes the actual intersecting region between the moving block's current position and the block directly below it: left = Math.max(currentX, prev.x), right = Math.min(currentX + currentWidth, prev.x + prev.width), and overlap = right - left. This is real interval-intersection math — the same logic used to detect whether two 1D ranges overlap and by how much — not a simplified "close enough" heuristic. If overlap comes out at or below a small tolerance (4px, accounting for the player landing an essentially perfect but not pixel-exact hit), the game ends immediately.
Every successful placement narrows what's possible next
The block that gets placed isn't the full-width moving block — it's a new block sized to exactly the overlap region, and currentWidth for the *next* moving block is set to that same shrunken width. This is what creates the genre's core difficulty curve: a series of imperfect-but-passable placements compounds, making each subsequent block progressively harder to land, purely as an emergent consequence of the overlap math rather than a separately scripted difficulty ramp.
Speed scales with height, within a capped range
speed = Math.min(6, 2.2 + stack.length * 0.15) increases the moving block's horizontal speed as the tower gets taller, but caps out at 6 — so the game gets meaningfully harder as a player progresses without becoming literally unplayable at very tall heights, a deliberate balance between "there is a real difficulty curve" and "the game doesn't become impossible."
The camera scroll only activates once it's actually needed
render() checks whether the tower's total pixel height exceeds the visible viewport area, and only applies a translateY "camera scroll" transform once it does — short towers render with no scroll offset at all, and the scroll amount is computed exactly from how far the tower has grown past the visible boundary, so the currently-moving block and the top of the tower remain visible together throughout play, not just for the first several blocks.
Persistent best height, not just a session high score
Same as this library's other playable games, the best height achieved is read from and written to localStorage (towerStackBest), so a player's personal best is meaningful across page reloads rather than resetting every time the page loads.
Step by step
How to Use
- 1Click Start, then click/tap to drop each blockA block slides side to side; each click places it based on real overlap with the block below.
- 2Land the block precisely to avoid narrowing the towerA perfect placement keeps the current width; an imperfect one shrinks the next block to the overlapping region.
- 3Adjust the starting block width and speedChange the START_W constant and the base speed value in startGame() to tune initial difficulty.
- 4Adjust the speed scaling and capChange the multiplier and Math.min ceiling in the speed calculation inside placeBlock() to adjust how quickly and how far the game speeds up.
- 5Adjust the miss toleranceChange the overlap <= 4 threshold in placeBlock() to make near-misses more or less forgiving.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
By computing the real geometric overlap between the moving block's current horizontal position/width and the block directly beneath it in the stack — using interval intersection math (left = max of both left edges, right = min of both right edges, overlap = right minus left), not an approximation or a scripted outcome.
If the computed overlap falls at or below a small tolerance (4px), the game ends immediately — this models the real "you missed almost entirely" failure case in the genre, distinct from a partial but survivable overlap that simply narrows the next block.
Every placement other than a perfect one shrinks the effective width available for the next placement, since the newly placed block is sized to exactly the overlapping region — this creates a naturally compounding difficulty curve purely from the overlap math, without any separate difficulty scripting.
No — the moving block's speed scales up with the current tower height but is explicitly capped at a maximum value (via Math.min), so the game continues to get harder as height increases without eventually becoming impossible to react to.
render() compares the tower's total height in pixels against the visible viewport height, and only once the tower exceeds that does it apply a translateY offset scrolling the tower (and the moving block's position) down by exactly the amount needed to keep the top of the tower in view.
Yes — it's persisted in the browser's localStorage under the key towerStackBest, so a player's best height survives page reloads and future visits, not just the current play session.