Inspiration
Low tide is a loan. The sea pulls back, hands you a strip of ground that was never yours, and comes to collect on a schedule you can read but not negotiate with. I wanted a survival game where the antagonist is a timetable rather than a monster.
The portrait screen decided the rest. A waterline is a horizontal line across a vertical frame, and depth is literally screen-Y — the phone's shape does work here instead of being tolerated.
What it does
The sea goes out, you climb down and dive for salvage, and it comes back higher than it was. Six tides.
Below the waterline your breath drains. Above it, it refills three times faster. Breath reaches zero and you drown. That single rule is the whole game — the richest salvage sits on the seabed, which is underwater at every tide, so each dive asks the same question with worse numbers: one more piece, or turn back.
Between tides you spend salvage on lungs, swim speed, and reach; whatever you don't spend carries over. The sea rises faster than you improve, so the seabed retreats from you across the run. On the last tide the water floods above the cliff top and there is nowhere left to stand.
Two controls: drag anywhere to swim, one kick button on a cooldown. Salvage collects on contact — there is no pickup button to miss.
How i built it
Three.js and HTML5, prompt-built, with three decisions made on day one rath than retrofitted at the end:
No asset files at all. No images, fonts, or audio. The cliff is generated from layered noise, the water is a custom shader, and every sound is synthe in WebAudio at runtime. This began as a way to eliminate every external-request failure mode at once and ended up defining the whole look.
The build concatenates rather than bundles. Source lives in a dozen num modules so an editor and a test runner can work on them directly; the build strips the module syntax and joins them into one readable inline script. It parses its own output before writing — I shipped a blank page once from a syntax error that every check reported green on.
Balance is tuned by simulation, not by feel. A headless harness imports pure gameplay modules and plays complete six-tide runs — a cautious policy and a greedy one, hundreds of seeds per sweep — reporting win rates, which tide p die on, and how many seconds they spend submerged with nowhere to surface. Every tuning constant in the game was chosen off a table.
Challenges i ran into
The last tide had nowhere to be dangerous. Cautious play won every simulation run, because even on tide six there was dry cliff above the high waterline to stand on and wait it out. The obvious fix — raise the final tide — was pois rise speed is
$$v_{\text{rise}} = \frac{h_{\text{high}} - h_{\text{ebb}}}{T_{\text{surge}} - t_{\text{warn}}} = \frac{20}{6} \approx 3.33\ \text{m/s}$$
against a 4 m/s swim speed, and moving one tide's high mark alone breaks that ratio — the same bug that had made tide one unwinnable earlier on. So I l the water untouched and lowered the cliff instead, sweeping the single constant that caps how high the player can climb.
The packaging nearly shipped a game that could not run. My first archiv
contained an entry literally named vendor\three.js — one filename with a
backslash in it, not a path. Windows' own unzip tolerates that, so everythi
looked perfect locally; a Linux unzip would have produced a junk file at the
archive root, no library, and a black screen. Every check I had written sti
passed.
One mouse pointer cannot hold a drag and press a button. Holding the drag to swim made the kick button unreachable, and releasing it to click ended the exactly when the surge was catching you. The spacebar now feeds the same code path.
Accomplishments that im proud of
The tide-six finale landing where it was aimed: cautious players still surv but on breath rather than on high ground, with roughly four seconds of nowhere left to go against an eight-second lung.
Beyond that — a complete game with 145 tests behind it, no asset files, and finished build that comes to 0.19MB against a 35MB budget, most of which is the rendering library.
What i learned
Verification has to be produced, not asserted. Midway through I recorded th tide-six finale felt tense, and had to retract it the following session: the playtest that "verified" it had never actually reached tide six. Both entri still in the build log. Every claim after that point came with the thing that produced it.
The other lesson is that a prototype's real failure modes cluster at the ed you are not looking at — the archive format, the letterbox coordinate space, the first ten seconds a stranger spends on the screen. The core loop was the ea part.
What's next for Tide
Different stretches of coast with their own tide behaviour: a shallow bay that floods sideways, a trench where one dive is the whole tide. A daily coastli everyone dives on the same day, scored against the same sea. Salvage worth something specific rather than only worth points.
What will not change is the shape — one stat, one currency, one antagonist, the sea coming back higher than it was.
Built With
- claude
- css
- html5
- javascript
- three.js
- web-audio-api
- webgl
Log in or sign up for Devpost to join the conversation.