A mining-themed risk/reward browser game. Place tetromino-shaped pieces on an 8x8 grid to mine blocks, collect rune loot, avoid hidden bombs, and descend deeper for bigger payouts — or cash out before you bust.
Built with React + Vite. No backend, no frameworks beyond React.
npm install
npx vite dev # dev server
npx vite build # production buildYou start each run by inserting a $1.00 ante. An entry toll of $0.50 is deducted immediately, leaving you at $0.50. Your goal: grow your balance by mining blocks, then cash out in profit — or hit the 10x jackpot cap ($10.00).
If your balance hits $0.00, you bust and lose everything.
- Place a piece on the grid to mine blocks beneath it
- Collect rune loot revealed under broken blocks — this grows your balance
- Avoid bombs hidden under blocks — detonating one costs you balance
- When your swings run out (or the layer is cleared), choose to descend deeper or cash out
- Descending costs a toll and opens a new layer with harder blocks, more bombs, but richer loot
- Repeat until you cash out, bust, or hit the jackpot
The board is an 8x8 grid of stone blocks. Each block has hit points (HP) that increase with depth. Your pick starts at level 1, dealing 1 damage per swing. Blocks on layer 1 have 1 HP; by layer 4 they have 2 HP, and so on (HP = ceil(layer / 2)).
Every block sits on top of a hidden tile from the floor's layout. Tiles determine what you find when you break a block:
- Rune tiles (R1, R2, R3, Q, K) — the main economy. Each tier pays a base value multiplied by the rune's modifier and the floor's rune multiplier
- Gear tiles — power-ups: shield charges, extra swings, skip charges, sweep charges
- Bomb tiles — penalties that cost you balance
- Empty tiles — nothing
You can't see what's under a block until you mine it.
Each layer gives you 8 swings (base). You place one piece per swing. Pieces come in three types:
- Tetrominoes (~82% chance) — standard 4-cell shapes (I, O, T, S, Z, L, J)
- Pentominoes (~15% chance) — larger 5-cell shapes (18 varieties)
- Dynamite (~3% chance) — special: destroys a 3x3 area centered on the clicked cell
Pieces arrive in random rotations. A queue of 5 upcoming pieces is visible on the right sidebar.
- The piece must be fully within the 8x8 grid — no cells can hang off the edge
- The piece must overlap at least one intact block on the current layer — you can't swing into purely empty space
- Cells that land on already-empty spaces pass through and deal damage to the block at that position on the next layer below (future damage)
Dynamite is special: it destroys everything in a 3x3 area regardless of HP, and it defuses bombs safely instead of detonating them. Rune tiles destroyed by dynamite are lost (their value is not collected), but gear tiles survive.
Clicking the piece preview in the orbit ring (or pressing Q) discards the current piece and draws the next one. This costs a swing and cannot be used on your last swing.
Bombs are hidden under blocks, indistinguishable from normal tiles until mined. Layer 1 has 0 bombs. The count ramps up: 1, 2, 3, 5, 6, 7, then caps at 8 bombs from layer 8 onward.
The first bomb you detonate in a run costs 0.25x your ante ($0.25). Each subsequent detonation doubles the penalty:
| Bombs Hit | Penalty |
|---|---|
| 1st | $0.25 |
| 2nd | $0.50 |
| 3rd | $1.00 |
| 4th | $2.00 |
| 5th | $4.00 |
This escalation persists across layers — it never resets. Bombs become extremely dangerous in the mid-game.
When a bomb detonates, it explodes in a 3x3 area around itself. If another bomb is caught in the blast radius, it chain-detonates too, with each bomb in the chain applying its own penalty. Chain explosions destroy blocks (losing their rune value) but spare gear tiles.
Each layer starts with a free bomb sweep — row-by-row mine counts shown on the left margin of the grid. Each number tells you how many hidden bombs are in that row. Additional sweep charges can be found as gear loot.
When adjacency numbers and revealed information make it logically certain that a block contains a bomb, the game auto-flags it with a marker. (This system is currently disabled in the codebase but the engine supports it.)
Shield charges are found as gear loot under blocks. When activated (click the shield button below the grid), your next swing is protected — if you hit a bomb, the shield absorbs the penalty. The shield is consumed after one swing whether or not a bomb was hit.
Shield loot scales with depth: layer 1 has 0 shields, ramping to a cap of 4 shields per layer from layer 9 onward.
Above the grid sits the slot machine — five columns representing the five rune tiers (S1, S2, S3, Q, K). Each column is assigned a random rune from your deck for this layer. When you mine a block and reveal a rune tile, you earn that slot's base value multiplied by the rune's modifier and the floor's multiplier.
| Slot | Color | Base Value | Rarity |
|---|---|---|---|
| S1 | Blue | $0.01 | Common |
| S2 | Green | $0.05 | Uncommon |
| S3 | Amber | $0.10 | Mid |
| Q | Rose | $0.20 | Rare |
| K | Purple | $0.40 | Legendary |
Each layer has a rune multiplier that starts at 1.0x on layer 1 and increases by 0.2x per layer (1.0x, 1.2x, 1.4x, ...). This multiplies all rune payouts on that floor.
When you reveal 3 or more adjacent runes of the same slot type (orthogonally connected), you trigger a combo. Combo thresholds are at 3, 5, 7, and 9 connected tiles. Each combo:
- Awards a cash bonus based on the combo count and slot value
- Grants +1 bonus swing
- Triggers the rune's special effect (varies by rune — bonus cash, extra swings, multiplier boost, sweep charge, etc.)
Connected rune groups are highlighted on the grid with colored borders matching their slot.
Your deck contains the first 10 runes from the rune pool. Each layer, 3 runes are randomly assigned to the S1/S2/S3 slots (from your deck), while Q and K always use special fixed runes (Gem and Relic).
When your swings run out or the layer is fully cleared, all remaining rune loot on the board is collected in a sweep animation, then you're given a choice:
- Descend — pay a toll to go one layer deeper
- Cash out — end the run and take your balance (minus a 2% exit fee)
Toll costs follow a Fibonacci progression: cheap early, exponentially more expensive later. The formula is ante * 0.08 * fibonacci(layer + 1). Early layers cost pennies; deep layers can cost several dollars.
When you descend, any blocks you didn't mine become bedrock — permanent obstacles that persist for the rest of the run. This means leaving too many blocks unmined gradually shrinks your playable area. If fewer than 4 cells remain playable, the game forces a cash-out.
When your piece overlaps empty cells (already-mined areas), the pick damage passes through to the block at that position on the next layer. This means strategic mining on upper layers can pre-break blocks below, giving you a head start on future layers. Pre-broken blocks on a new layer reveal their loot immediately (and their value is collected on layer init).
The drill-down display shows the HP of the first unbroken block below each empty cell, with a depth indicator (+1, +2, etc.) and a visual darkening to convey depth.
Your balance divided by the ante gives your multiplier. The journey bar at the top shows your progress from 0x (bust) to 10x (jackpot). Key thresholds at 1x, 2x, 3x, 5x, and 7x are marked.
You can spend balance to upgrade your pick, increasing damage per swing. Upgrade costs scale linearly: level 1→2 costs $1.00, 2→3 costs $2.00, etc. Higher pick levels let you break multi-HP blocks in a single swing and push more passthrough damage to lower layers.
If your balance reaches 10x your ante ($10.00), you hit the jackpot — the game ends with a special celebration and full payout (no exit fee).
If your balance drops to $0.00 (from bomb penalties or tolls), you bust and lose everything.
| Input | Action |
|---|---|
| Click | Place piece at cursor position |
| Hover | Preview piece placement (ghost overlay) |
| Q | Skip/discard current piece (costs 1 swing) |
| R | Rotate piece (disabled by default; enable in Settings) |
| W | Use sweep charge |
| 9 | Auto-mine: finds optimal placement and executes (tap to preview, tap again to confirm; hold to repeat) |
On mobile/touch devices, placement uses tap-to-confirm: first tap shows the ghost preview, second tap on the same position executes the swing.
When a block is mined, the cell shows up to four pieces of information:
- Center — the rune or gear sprite found underneath
- HP (if applicable) — remaining hit points when viewing through to blocks below
- +D (top-right) — depth delta when viewing a block on a lower layer through an empty cell
- ADJ (bottom-right) — count of adjacent bombs (shown for empty cells neighboring revealed bombs)
- CRT scanline/vignette/flicker overlay for retro aesthetic
- Procedural crack overlays on damaged blocks (SVG generated per cell)
- Canvas particle system for block debris on destruction
- Layer color palettes cycle through 10 earth tones (Rust, Ochre, Olive, Moss, Slate, Steel, Dusk, Mauve, Ash, Bone)
- Rune sprites are dye-tinted to match their slot color
- Full procedural sound synthesis via Web Audio API — no audio files
- Header — game title, How Do help toggle, SFX toggle, debug tools, settings
- Journey bar — visual progress from bust to jackpot with multiplier markers
- Left sidebar — depth gauge, pick/tool widget, pet supervisor, bomb counter with damage display, layer minimaps
- Center — slot machine, 8x8 grid, shield button
- Right sidebar — piece queue (5 upcoming), piece type odds, current piece orbit with swing dots
Accessible via the SETTINGS button in the header. Includes toggles for:
- Show Depth Delta, Adjacency numbers, HP numbers
- Dye Runes to slot color
- Allow piece rotation
- Bomb symbol style
- Layer dim rate, UI scale
- All economy values (cap multiplier, exit fee, toll base, bomb penalty, etc.)
- Gameplay values (dynamite chance, pentomino chance, swings per layer)
- Animation timing
src/
App.jsx — Root, renders QuarryApp
quarry/
QuarryApp.jsx — Main game component (all state + UI)
quarry.css — All Quarry styling
game/
types.js — Config, constants, pieces, economy formulas
engine.js — Game state mutations (createGame, executeSwing, etc.)
sound.js — Procedural audio synthesis
cracks.js — SVG crack overlays
debris.js — Canvas particle system
sprites.js — Sprite rendering utilities
void.js — Background void canvas effect
components/
QuarryGrid.jsx — Grid rendering + ghost preview
QuarryCell.jsx — Individual cell rendering
PiecePreview.jsx — Piece shape preview
LayerMinimaps.jsx — Future layer damage previews
CatMascot.jsx — Pet supervisor mascot
SlotMachine.jsx — Rune slot machine display
QuarryTitle.jsx — Animated title screen
experiments/ — Algorithm tuning page