Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

N1k4G/diving-simulator

Open more actions menu

Repository files navigation

Diving Simulator

A 2D HTML5 Canvas diving simulator implementing the Bühlmann ZHL-16C decompression algorithm with multi-gas support, realistic bubble physics, and a technical wrist dive computer-style HUD. Dive any of four authored sites — Shore, Reef, Wreck and Cave — including overhead (wreck/cave) environments with torch, guideline and current mechanics.

Quick Start

Open src/diving-simulator.html in a browser. No build step or server required.

Controls

Diving

Key Action
/ W Inflate BCD (ascend)
/ S Vent BCD (descend)
/ A · / D Fin kick left / right (horizontal swim)
T Toggle torch (cave / wreck)
F Fast-forward at a deco / safety stop (10×)
16 Switch tank (during dive)
I Gas info overlay (Tec / CCR)
H / ? Toggle help overlay
ESC Close overlay
Enter Start dive / Reset

Vertical movement uses asymmetric acceleration: ascent ramps at 2 m/s² and descent at 3.33 m/s², both reaching max velocity in exactly 3 real seconds of sustained keypress. Releasing the key decelerates at 4 m/s². The fin-kick keys (/A and /D) drive horizontal swimming, and currents (when present) push the diver — hold a kick to swim against them.

The fin-kick style depends on the dive mode: recreational dives use a flutter kick (legs alternate up and down); technical and CCR dives use a frog kick (legs sweep symmetrically with a glide pause), the standard kick for trim and silt control.

Dive mode (Rec / Tec / CCR) and dive site (Shore / Reef / Wreck / Cave) are chosen on the gas-setup screen before the dive.

On-screen controls (touch & desktop)

On-screen buttons let you play without a keyboard. The four navigation buttons are laid out as a WASD cross in the bottom-left (ascend on top, descend below it, left/right flanking descend). On touch devices they show arrow glyphs (▲ ◄ ▼ ►); on a non-touch desktop they show W / A / S / D and respond to mouse press-and-hold. Context buttons (Help, Torch, Gas info, Fast-forward, tank switch, and the CCR Bailout / setpoint controls) appear on the right as the dive state requires.

Advanced Gas Setup

Key Action
G Open advanced gas configuration
15 Select tank slot
O / N / E Adjust O₂ / N₂ / He mix
+ / - Add / remove tank
[ Decrease AMV rate (min 8 L/min)
] Increase AMV rate (max 25 L/min)
g / Shift+G Decrease / Increase GF Low (5% steps, range 30–100%)
f / Shift+F Decrease / Increase GF High (5% steps, range 30–100%)

CCR Mode Controls

Key Action
[ / ] Decrease / Increase setpoint (during dive)
B Bailout to open circuit (irreversible)
15 Select diluent preset (in gas setup)
I Gas info overlay (Tec/CCR modes)
ESC Close overlay

Features

Decompression Model

  • Full Bühlmann ZHL-16C with 16 tissue compartments (N₂ + He)
  • Gradient Factors — GF Low / GF High support (default 100/100 = pure Bühlmann). Range 30–100%. Affects ceiling, NDL, and deco schedule via linear interpolation from GF Low → GF High. Displayed on dive computer when not 100/100.
  • Real-time NDL, ceiling, TTS, and GTR calculations
  • Multi-gas support with up to 5 configurable tanks (Nitrox / Trimix)
  • PO₂ monitoring with hypoxia (< 0.16 bar) and hyperoxia warnings
  • Adaptive safety stop — Duration scales with tissue loading: 0 min (<50%), 2 min (50–70%), 3 min (70–85%), 4 min (>85%). "SS PEND" indicator shown at 7–15m. Missing safety stop shows yellow warning on post-dive screen (not a game over).

CCR Mode (Closed Circuit Rebreather)

A full CCR dive mode simulating closed-circuit rebreather operations:

Gas System:

  • O₂ cylinder and diluent cylinder with independent pressure tracking
  • PO₂ control loop: metabolic O₂ consumption with solenoid injection toward setpoint
  • Diluent auto-add on descent to maintain loop volume
  • CO₂ scrubber with countdown timer

Diluent Presets:

Slot Mix Use Case
1 Air (21/79) Shallow recreational
2 EAN32 (32/68) Recreational Nitrox
3 Trimix 21/35 Moderate technical
4 Trimix 18/45 Deep technical
5 Trimix 10/70 Ultra-deep technical

Decompression Integration:

  • Bühlmann deco uses dynamic loop gas fractions: fO₂ = PO₂ / P_ambient
  • GTR reports O₂ cylinder endurance (not diluent)

HUD Elements:

  • Setpoint and actual PO₂ display
  • O₂ bar and diluent bar pressure indicators
  • Scrubber remaining time

Failure Modes:

Failure Trigger Delay
Hypoxia PO₂ < 0.16 bar 30 dive-seconds
Hyperoxia PO₂ > 1.6 bar 30 dive-seconds
CO₂ breakthrough Scrubber depleted 180 dive-seconds

Bailout: Press B to bail out to open circuit. This is irreversible — the diver switches to breathing the diluent gas as an OC supply.

Breathing Cycle & Bubbles

Bubble emission follows a physiological breathing cycle state machine:

Inhale (2s) → Exhale (1.5s) → Pause (0.5s) → repeat
  • Breathing bubbles emit only during the exhale phase, rising from the diver's mouth
  • BCD exhaust bubbles emit during fast ascent (>5 m/min), appearing from the BCD position with smaller radius and faster rise speed

AMV (Actual Minute Volume)

Gas consumption is driven by a configurable AMV rate (default 15 L/min, range 8–25). AMV directly affects:

  • Gas consumption: consumption = AMV × ambient_pressure
  • GTR (Gas Time Remaining): recalculated each frame using current AMV

Adjust AMV with [ and ] in the advanced gas setup screen. Higher AMV simulates heavier breathing (e.g., exertion, stress); lower AMV simulates relaxed, efficient breathing.

Dive Computer Display

The HUD is styled after a modern technical wrist dive computer:

  • Titanium-gray bezel with inner shadow
  • 6 horizontal data zones with alternating dark backgrounds
  • Depth as the dominant centered element (42px)
  • Ascent rate bar indicator (6px, color-coded)
  • 3-column data grid: MAX / AVG / ASC rate + AMV / GTR / TTS
  • Red-tinted zone background when decompression obligation exists
  • Compact 9px labels for minimal visual clutter

Physics

  • Time acceleration: 3× (1 real second = 3 dive seconds)
  • Max ascent rate: 18 m/min
  • Max descent rate: 30 m/min
  • Barotrauma threshold: 18 m/min sustained for 10 dive-seconds
  • Maximum depth: 300 m
  • Hypoxia threshold: PO₂ < 0.16 bar for 10+ dive-seconds → game over

Dive Sites

Four authored sites, each playable with any dive mode, selected on the gas-setup screen:

Site Character Max depth Overhead?
Shore Gentle sandy slope from a beach entry, seagrass, boulders, a small sunken boat + anchor landmark ~32 m No
Reef Flat-topped seamount (mesa) with coral gardens, gorgonians, sponges and fish; steep flanks to the abyss open No
Wreck ZENOBIA-inspired Ro-Ro ferry on its side: multi-deck hull with cars/lorries, cargo, engine room; three marked penetration points (bow / hatch / stern); a large bower anchor lies on the seabed off the bow ~68 m Yes
Cave Cenote: a brown-limestone entrance that forks into a shallow upper tunnel and a deep lower tunnel descending to a ~100 m grey-rock cathedral, rejoining before the surface shaft ~106 m Yes

Overhead environments (wreck & cave) add confined-space mechanics:

  • Limited line-of-sight — the wreck hides everything outside a bubble around the diver behind its solid steel hull; the cave is near-black without a torch.
  • Torch (T) — lights a cone in the cave and widens the visibility bubble in the wreck.
  • Guideline — a breadcrumb line is laid automatically while overhead, marking the way back to open water.
  • Bad-air pockets — unbreathable gas traps (e.g. the cave's upper tunnel) where you cannot surface.
  • Overhead game-over notice — dying in an overhead environment shows a safety callout about the dangers of wreck/cave diving (training, continuous guideline, rule of thirds).

Environment

  • Boat / buoy / pond surface markers per site; warm cenote sky and jungle rim above the cave
  • Currents — many dives feature a horizontal current that pushes the diver; counter it with A/D fin kicks
  • Site-aware marine life (reef fish, turtles, rays, sharks; no sharks at shore/cave)
  • Depth-graded water and rock: warm shallows cooling to dark grey/black with depth

Testing

Open src/diving-simulator-tests.html in a browser to run the automated test suite. Tests cover decompression math, gas consumption, PO₂ calculations, breathing cycle, AMV bounds, and gameAPI integration.

The same suite runs headless under Playwright via npm test (it loads the test harness and asserts window.testResults).

Development & CI

The game is plain HTML/CSS/JS with no build step. Install dev tooling with npm install, then:

Command What it does
npm run lint ESLint over src/*.js (a husky pre-commit hook also lints staged files with --max-warnings=0)
npm test Runs the in-browser test suite headless via Playwright
npm run screenshots Captures review screenshots (phone + desktop, setup + in-dive) to screenshots/ via scripts/screenshots.mjs

CI pipelines (GitHub Actions):

  • .github/workflows/pr.yml — runs on every pull request to main: lint → tests → review screenshots (uploaded as artifacts). It does not deploy.
  • .github/workflows/deploy.yml — runs on push to main (i.e. after a PR is merged): lint → tests, then deploys to Cloudflare Pages.

So a PR is fully checked (and produces screenshots for review) before merge, and deployment only happens once the change lands on main.

gameAPI

The simulator exposes window.gameAPI for programmatic access and testing:

// Read-only
gameAPI.depth           // current depth (m)
gameAPI.maxDepth        // max depth reached
gameAPI.diveTime        // elapsed dive time (dive-seconds)
gameAPI.ascentRate      // current ascent rate (m/min)
gameAPI.breathPhase     // 'inhale' | 'exhale' | 'pause'
gameAPI.breathTimer     // time remaining in current breath phase
gameAPI.hypoxiaTime     // accumulated hypoxia exposure (dive-seconds)
gameAPI.safetyStopNeeded     // whether a safety stop is required
gameAPI.safetyStopRemaining  // seconds remaining on safety stop
gameAPI.safetyStopInitialized // whether stop duration has been locked
gameAPI.safetyStopComplete   // whether safety stop was completed

// Read-write
gameAPI.amvRate         // AMV rate (clamped 8–25 L/min)
gameAPI.gfLow           // GF Low (clamped 30–100%)
gameAPI.gfHigh          // GF High (clamped 30–100%)
gameAPI.gameState       // 'title' | 'surface' | 'diving' | 'gameover'
gameAPI.activeTank      // active tank index

// Functions
gameAPI.calculateSafetyStopDuration()  // returns adaptive stop duration in seconds

About

A 2D HTML5 Canvas diving simulator with the Buhlmann ZHL-16C decompression algorithm, multi-gas, CCR mode, and a technical wrist dive computer-style HUD.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Used by

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.