Coldwater
A short first-person diving game where light is the only resource and the surface is the only safe place.
RepositoryColdwater is an invented placeholder project — no real game, studio, or release sits behind it. It stands in for a small first-person game written up as engineering: one mechanic, a handful of systems holding it up, and the parts that turned out to be harder than they looked.
The clip above is a silent screen capture of a dive in progress. There is no speech and no meaningful audio in it, which is why it carries no caption track — a clip with either would have to ship one.
One resource, and it is not oxygen
Every diving game has an air gauge. Coldwater has one too, and it is deliberately boring: it drains at a fixed rate, it is visible at all times, and it never surprises anyone. The resource the game is actually about is light.
A diver carries a lamp with a fixed battery and three brightness settings. Brightness is a straight trade: the widest setting shows the room but drains the battery in about four minutes of held-down use, and the narrowest shows a corridor of maybe six metres and lasts most of a dive. Because the world is otherwise unlit below the thermocline, spending light is spending information — and the player has to decide how much of the room they need to see before committing to a route.
That single trade produced most of the moment-to-moment tension without any scripting. A player who lights everything up early is navigating the last third of the dive by memory.
Fog that lies on purpose
Physically correct underwater attenuation looked wrong. Real water eats red first and turns everything a flat blue-green, and at the depths this game runs at, a correct model made the whole screen an even wash — no depth cues, no sense of a room ending. Distance stopped being readable.
What shipped is a two-term fog: a physically-shaped exponential term for the overall wash, plus a much steeper near-field term that only affects the first eight metres. The second term has no basis in optics. It exists so the edge of the lamp cone has a visible boundary, which is what lets a player judge how far away a wall is.
Saving a dive
Dives are five to twelve minutes and a player can quit mid-dive, so the save format has to capture a running simulation rather than a checkpoint. The first version wrote the whole world state to IndexedDB on a timer, which was fine until the world got large enough that the write blocked a frame.
The version that shipped saves a seed plus an input log. The world is generated deterministically from the seed, and replaying the input log reconstructs the exact state at any point. Restoring a dive means running the simulation forward at maximum speed until it catches up, which takes under 200ms for a full twelve-minute dive.
The catch is that determinism becomes a hard requirement rather than a nice
property. One Math.random() call in a particle effect broke restore for a
week before anyone traced it, because the symptom — a diver ending up
slightly out of position — looked like a physics bug.
What would change next time
The lamp settings should have been two, not three. Playtesting notes are full of people cycling past the middle setting without ever choosing it deliberately, and the middle option mostly exists because three felt like the right number of options rather than because it answered a question the player was asking.