Pre-production

Subsurface

A 2D physics puzzle where you carve pathways through reactive geological layers to guide a volume of viscous fluid down to a collector crystal.

Mockups Every image on this page is an illustration of the intended design, not a screenshot, and the readouts in them are invented values. There is no game build to capture. A working prototype of the simulation does now exist and runs in a browser — how to run it — but it is a bare development harness, not the game these mockups depict.

What it is

A pathfinding puzzle, played by removing earth

You are a subterranean pathfinder. Each level begins with a volume of fluid sealed in a chamber near the surface and a collector crystal buried somewhere below it. Between the two sits a cross-section of ground: watertight clay, loose sand that collapses when you cut into it, and slabs of bedrock you cannot touch.

Your only verb is digging — one finger, one continuous swipe, material removed along the path. There is no undo and no way to put earth back. A channel cut in the wrong place is a permanent feature of the level, which is what makes the digging a decision rather than a chore.

The fluid is the physics

It conserves its volume, pools against watertight layers, and builds pressure in deep vertical columns — which is what drives it hard through narrow gaps at the bottom of a shaft.

The ground reacts

Terrain is not collision data. Sand slumps to its angle of repose and drinks the fluid; fractured rock shatters into chunks that can block the passage you just opened.

You set the pace

The simulation runs in real time, but nothing hurries you. The tension comes from what the fluid is already doing while you decide where to cut next.

In action

Mid-level, partway down

The intended play screen: portrait cross-section, minimal instrument HUD, fluid working its way down a channel that has just broken through the sand band.

DEPTH PRESSURE COLLECTED 38.4 m 2.1 kPa 34% Instrument HUD — depth, pressure, collection Reservoir — a fixed volume, conserved wherever it goes Clay seal — watertight, and the first cut every level asks for Sand band — permeable. Fluid soaks outward and darkens it into wet sand Carved channel — one continuous swipe, not undoable Collector crystal — 85% of the volume has to arrive here
MockupIllustration of the intended play screen. Not a screenshot — the depth, pressure and collection figures are invented, and no build exists that could produce them.

Before / after

What the digging actually changes

The same level, same fluid volume, same layers — shown with and without the player's intervention. Left is the level as it loads. Right is the level after one considered channel, cut down the centre between the bedrock ribs and landing inside the collector trough.

Before — untouched

COLLECTED 0%

FAIL — 0% collected. The clay is watertight, so the payload never leaves the chamber. Nothing about the level resolves itself without a cut.

After — one channel cut

COLLECTED 92%

CLEAR — 92% collected. The remaining 8% is the wet-sand halo: the fluid the permeable band drank on the way down. Cut wider and you lose more of it to the sand; cut off-centre and the cavern floor sends the rest to the drains.

MockupBoth panels are illustrations of intended behaviour drawn from the same cross-section. The percentages are chosen to show the design's intent, not measured from a simulation.

Ground

Four materials, each with two behaviours

Every layer answers two separate questions: what happens when the dig tool passes through it, and what happens when the fluid reaches it. The puzzles come from those answers disagreeing.

Bedrock

Dig
Indestructible. Defines the level boundary and its ribs.
Fluid
Impermeable. Nothing passes, ever.

Clay / silt

Dig
Cuts smoothly and cleanly. The workhorse material.
Fluid
Watertight. Fluid pools against it with a flat surface.

Sand / gravel

Dig
Unstable. Cut into it and the sand above collapses to its angle of repose, reshaping the passage you made.
Fluid
Permeable. Fluid seeps in and turns it to wet sand — darker, heavier, more cohesive — and that volume is off the board.

Fractured rock

Dig
Shatters instead of vanishing, leaving rigid chunks that fall and settle wherever gravity puts them.
Fluid
Chunks plug narrow passages and get shoved around by pressure — usable as a valve, or a problem you made for yourself.

How it is meant to work

A hybrid simulation, not a polygon physics engine

Sand that slumps, fluid that conserves volume, and rock that breaks into rigid bodies do not come from one solver. The specification pairs two.

Cellular grid

The playfield is a dense 2D grid; each cell carries a material type, velocity, mass and wetness. This is the falling-sand approach, and it is what makes thousands of interacting sand, clay and fluid cells affordable.

Rigid bodies on top

A conventional 2D physics engine handles the fractured-rock chunks. The two layers exchange forces: the grid pushes buoyancy and pressure into the bodies, and the bodies mask out grid cells.

Only simulate what moves

The level is split into chunks, and chunks with nothing moving in them sleep. Resting sand and untouched clay cost nothing per frame.

Built to parallelise

Grid updates are dispatched to worker threads or compute shaders, with an ECS keeping particle data separate from the systems that act on it — the shape that keeps this viable on a phone.

Levels are authored as PNGs, with hex values mapping to starting cell states — #FF0000 clay, #00FF00 sand, #0000FF fluid spawner, #FFFFFF collector — so a level is data a designer can paint rather than code. Full specification →

Getting started

How to use this, per environment

What you can do with Subsurface today depends entirely on where you're trying to do it, and the differences are worth stating plainly.

Read the specification

Available

The design document is the project's source of truth: mechanics, material behaviours, simulation architecture, level format and progression. Nothing to install — read it rendered on GitHub, or open docs/design-spec.md in a checkout.

Run this website locally

Available
# clone and open — no build step, no dependencies
git clone https://github.com/CoderCoop/SubSurface.git
cd SubSurface

open docs/index.html        # macOS
xdg-open docs/index.html    # Linux
start docs\index.html       # Windows

Why this one differs: the site is plain HTML and CSS with no generator, no bundler and no network calls, so a browser can open it straight off the filesystem. You would only need a local server (python3 -m http.server -d docs) if the site later starts using ES modules or fetching level data — both of which browsers block on file:// origins under CORS, even though the files sit right there.

Play the early build

Available

Nothing to install — open it in a browser. It is a progressive web app, so on a phone you can add it to your home screen from the browser menu and it will run full-screen and offline afterwards.

Why this one differs: it is the only entry here that needs no checkout, because the game ships as part of this site rather than alongside it. Everything it needs, including the physics engine, is served as static files from docs/play/ — there is no server, no API and no network call once the page has loaded, which is exactly why it can be cached and played with no connection.

Work on the simulation

Available
# fetches the physics engine (Box2D, via planck)
npm install

# the game, straight off the filesystem
open docs/play/index.html   # or xdg-open / start

# and the tests (Node 18+)
npm test

Drag to dig. Clay cuts clean and holds fluid. Sand collapses into whatever you cut and drinks what runs through it, giving it back only under pressure. Fractured rock shatters into loose chunks that can wedge in the passage you just opened. Get 85% of the payload into the crystal.

Why this one differs: the page itself needs no install — the physics engine is committed alongside the game, so it opens straight off the filesystem like everything else here. npm install is for the test suite, which resolves the same engine from node_modules rather than the vendored copy. A test fails if those two ever drift apart. There is still no bundler anywhere: planck ships a plain UMD file that works under both a script tag and require.

Install it on a phone

Available

Open the game on your phone and add it to your home screen — "Add to Home Screen" in Safari's share menu, "Install app" in Chrome's menu. It then launches full-screen with no browser chrome and runs with no connection.

Why this one differs: there is still no App Store or Play Store listing, and no TestFlight or internal-testing track — this page will not link to one until a build exists. What changed is that it no longer needs to. A progressive web app installs from the browser, so the mobile packaging, review queues and signing certificates the spec's native target implies are simply not on the path any more. The remaining gap is the game itself — one level, raw grid, no art, no audio, no haptics — rather than the delivery.

Status

What exists, and what doesn't

Area State Notes
Design specification Written Mechanics, materials, architecture, level format, progression.
Project website Written This page. Illustrated with mockups until a build exists.
Cellular grid (fluid, sand, clay) Proof of concept Working, in docs/play/ — fluid flow and pressure, sand at its angle of repose, absorption and pressure release, digging, and the collector. Runs in a browser; covered by 32 tests, including the conservation invariant after every step.
Rigid-body layer (fractured rock) Proof of concept Box2D (via planck) drives the chunks; the interaction layer is ours. Fluid exerts buoyancy and drag on the bodies, and the bodies mask out grid cells so every cellular rule treats a chunk as solid without knowing rigid bodies exist.
PNG level loader Not started Hex-to-material mapping described in the spec.
Audio & haptics Not started ASMR-leaning digging and flow; pressure rumble, fracture taps.
Volume conservation vs. absorption Decided Wet sand holds fluid rather than destroying it, and gives it back when enough pressure builds against the band. So volume is strictly conserved — released = in play + collected + drained + held — and a saturated band is a delay and a reservoir rather than a leak. Only the collector and the drains take fluid off the board, and both are counted.
Engine for the shipping build Open Deliberately undecided. The proof of concept answered the questions it was built to answer; whether the game ships on it or is ported to a game engine is a separate call. Either way Subsurface stays open, which narrows the field.
Level format Interim Levels are currently bands expressed in code. The PNG loader below replaces that with the same data painted as pixels.