What the game is and how it is put together, as built so far. The README covers how to run, export and test it; this is the design. Last updated 2026-10-05.
A low-poly trick racer about one sockeye salmon’s life. You swim a course, jump, spin and flip for points in time with a drum & bass soundtrack, and the courses add up to the salmon life cycle: the long swim home from the ocean to spawn, then the next generation’s run back down to the sea.
Reference for the life cycle: https://www.nps.gov/olym/learn/nature/the-salmon-life-cycle.htm
A run is the whole life cycle, so every stage on it is swum twice.
Reaching the ocean ends the run. Best scores are kept per stage and per direction.
Title → NEW RUN → globe on the Big Blue → START → intro → stage → results → globe (pick the way on) → travel line → next stage → … → spawning ground → spawning scene → the same stages in reverse → the Big Blue → outro → the run’s summary page.
Two routes, North America and Japan. They share the first three steps and part at step 4. Each has a fish farm as a short, easy early ending and a home lake at the end of the full run.
The stages are joined up into one run of water. A run is not a string of separate screens: the salmon never leaves the water between one stage and the next.
Track.RUN_OUT, 520 m), at its ease, while the results
are read over the picture. CONTINUE lets the globe down from above the screen (just the
globe, with nothing round it), which draws the way to the next stage, with the ways not
taken greyed out and dashed (shut ones marked LOCKED), while that stage is made out of
sight (World.make_next). When the globe has got there the salmon is on the new stage
(World.take_next): the old one is gone, the sky, the haze and the light turn to the new
one’s over a moment, the globe goes back up, and the stage is under way at once, with no
countdown. (main._coast, _travel_on, _arrive.) The way back down is joined up the
same way; the cutscenes between the way up and the way down, and at the end, are as they
were. PRACTICE and the tester’s stage picker still go straight to a stage.Track._plan_fork). Something lies along the course there and divides it into as
many ways as there are: the left-hand one is the default, the others the advanced. At sea,
where there is room, it is a cruise ship as big as a real one (some 320 m by 48 m); in a
river, an island; a stage with three ways on has two of them. A boom of red buoys runs
from the right-hand edge of the water to the first bow and shuts every way but the
left-hand one, with a sign over each saying what the goal is, for as long as the goal is
not met; it opens the moment it is, and shuts again if a goal is lost (few wipeouts). The
side the salmon passes the bow on is the way it goes."submerged" in levels.gd): six
layers deep, nothing on its surface, no coming up and no jumping, until a current near
its end climbs back to the surface and throws the salmon out, ahead of its own fork."divider" and
"fork_at" in levels.gd): sea stacks in the Deadliest Catch and at the end of the trench, a
gravel bar on the Rocky Coast, an iceberg in Aurora, a pier in the harbours and the
fish ladder, a reef in the Reefside (two of them: three ways), an island in the
Bubbling Brook, a logjam in the Withering Waters. Only the Big Blue has the cruise ship.
Once the way is chosen the rest of the stage is swum as usual.Not done yet: the next stage is made in one go (about a third of a second on a desktop, longer on a phone: a hitch while the globe is coming down).
Each stage names the stages it leads to. The first is the default way on. The others are advanced ways, opened by meeting that stage’s goal; otherwise they are shown locked.
| Step | Stage | Where | Leads to (default first) | Goal to open the rest |
|---|---|---|---|---|
| 1 | Big Blue | mid Pacific | Deadliest Catch, Abyss | collect 12 rings |
| 2 | Deadliest Catch | Gulf of Alaska | Rocky Coast, Harbor | 5 tricks on the beat |
| 2 | Abyss | Mariana Trench | Reefside, Aurora | 5 tricks on the beat |
| 3 | Rocky Coast | off British Columbia | The Fish Ladder, Withering Waters | no more than 2 wipeouts |
| 3 | Harbor | Puget Sound | The Fish Farm, The Fish Ladder | score 60K |
| 3 | Reefside | off Okinawa | Neon Harbor, Bubbling Brook, Withering Waters | collect 14 rings |
| 3 | Aurora | Bering Strait | Bubbling Brook, Neon Harbor | collect 12 rings |
| 4 | Bubbling Brook | inland of Seattle | Emerald Plunge, Riptide Rapids | score 70K |
| 4 | Withering Waters | near Bend, Oregon | Riptide Rapids, Alpine Lake | collect 12 rings |
| 4 | The Fish Ladder | Seattle | Riptide Rapids, Alpine Lake | 6 tricks on the beat |
| 4 | The Fish Farm | north Puget Sound | early ending | |
| 4 | Neon Harbor (Japan) | Tokyo Bay | The Hatchery, Bamboo Baitway | score 60K |
| 5 | Emerald Plunge | Mount Rainier | Alpine Lake | |
| 5 | Riptide Rapids | Mount Rainier | Alpine Lake | |
| 5 | Bamboo Baitway (Japan) | Hokkaido | Ancestral Waters | |
| 5 | The Hatchery (Japan) | north Honshu | early ending | |
| 6 | Alpine Lake | Mount Rainier | ending | |
| 6 | Ancestral Waters (Japan) | Hokkaido | ending |
Notes:
ui/beat_fish.gd); the timing grades in a speech bubble beside the salmon (fx/speech.gd).horizon_drop in psx.gdshader,
Track.mat_far), and pines have needles drawn on them (needles, Track.mat_pine).sea_visitors.gd), and now and then a golden
trout: touch it and it joins the pack for the rest of the run (School.join).Track.BEAR_SIZE).fx/spawning.gd,
filmed by the camera’s STAGE mode): the nest dug, the eggs laid and fertilised and covered,
the hatching, and the young setting off; then the way down begins.World._turn_water). A stage joined on has a front to it (a wall
under its banks and bed: Track._build_front)."canyon").sea_visitors.gd).world/crosser.gd, the "boats" kind): run into one at the
surface and it is a wipeout; go round, or dive under.Track.DRAFT), two propellers and
rudders at the stern."sunk": the same walls
26 m further down), and it is left under the water, by a choice of ocean currents: one
for each way on, side by side; the one ridden is the way taken ("divider": "currents").heave in fish.gdshader), and tuna
chase the salmon: up from behind and then round it. Every fish is in the field guide.Track.CURRENT_KINDS): winding; a ramp under the water
(short, up to the surface and off the end into the air); a loop (round like a corkscrew);
a huge one; and a long low straight one. There are many more of them, and a swipe to
either side darts out of one (up or down leaves it too).Props.half_ring), with its name over the top. After a fork the next stage is joined on
turned a little towards the side taken.hide_from), and the
next stage is joined on to the side that was taken (fork_centre), turned a little that
way. So a fork is at the end of its stage (fork_at is no longer used).Salmon.launch).levels.gd: "weather", "stars", "aurora", "clouds"): it rains
on the Rocky Coast (fx/weather.gd), which roughens the water and leaves ringlets on it
(rain in the water shader); Emerald Plunge and Aurora are at night, under
stars and an aurora (the sky shader). Clouds of krill drift near the surface of the sea.fork_at, 0.6 without it) a short divider parts the water, and where it ends the
right-hand way turns off to the right on a course of its own: a second stretch of the
same stage (Track._build_branch, a Track that is a child of the stage until taken),
with its own obstacles and its own finish, which leads to the advanced stage. Keep left
and the main way goes on to the default one. Passing the end of the divider on the right
puts the salmon on the branch (World.take_branch). There is no bank between the two
where they part (open_side). The Big Blue (the ship and the abyss) and the Ocean
Trench (a choice of currents) keep their own kinds of fork."no_surface"): only the dark.sea_visitors.gd).A stage is a course about 2.4 to 3.4 km long (roughly 55 to 95 seconds): open water 70 to
140 m wide at sea, a river 16 to 21 m wide inland, a lake or harbour 22 to 28 m. It is
generated from one entry in scripts/world/levels.gd. An entry sets the course (length,
width, slope, how much it bends, what it is made of, how often waterfalls come), the scenery
(bank shape and colours, a table of dressing rules), and the sky, fog, light and water.
What a course is made of
| Piece | What it does |
|---|---|
| Ramps | Kick you into the air. Rings mark the arc. |
| Rails | Bamboo, logs or pipes to grind along; land on one or swim onto its end. |
| Rocks | Rapids full of rocks (ice, coral heads, containers). Clip one swimming and you are bumped; hit one in the air and you wipe out. |
| Rings | Trails to collect: points and boost. |
| Predators | Bears in rivers strike on every other beat: jump them or steer wide. Sharks at sea keep no beat: each swims to and fro across your way, one at the surface and one under it, and touching it at its own depth is a wipeout, so go round, over or under. |
| Waterfalls | Going up: a wall 2.6 to 4 m high to leap, or be washed back 40 m. Going down: a drop of 9 to 20 m to launch off. |
| Currents, boost rings, sea nettles | Under the sea stages only: see “The layers under the water”. |
There is a gate over the finish and none at the start.
The stages at a glance
The sea is wide and the rivers are narrow: the sea stages are 70 to 140 m of open water (the Rocky Coast and the Reefside with land along one side only), and the rivers after them are 16 to 21 m between their banks.
| Stage | Look | Water | Predator | Notable |
|---|---|---|---|---|
| Big Blue | broad daylight, deep blue water, buoys, ships far off | flat, open | shark (rare) | the gentle start: 140 m of open water, long empty stretches, no rock fields, no bottom in sight, no ramps; six layers to dive |
| Deadliest Catch | cold open water off Alaska, the sea floor in sight, the fishing fleet about | flat | shark | 90 m wide; strings of crab-pot floats (dive under them); two layers to dive |
| Abyss | near-black water, glowing jellyfish, seamounts | flat, open, 110 m wide, six layers deep and swum all under the water | none | the abyss: come into down a giant current from the Big Blue, left by a current back to the surface; currents, boost rings and sea nettles |
| Rocky Coast | the coast of Oregon under a grey sky: 70 m of sea with a rocky shore along the left only (dark sand, black rock, sea stacks, drift logs, spruce on the bluffs) and open water on the right | barely climbs | shark | |
| Harbor | quays, cranes, sodium light | barely climbs | shark | |
| Reefside | pink dawn over clear water, 70 m wide, a beach along one side only, dense coral | flat, open | shark | |
| Aurora | pack ice and icebergs under an aurora, 100 m wide | flat, open | shark | |
| Bubbling Brook | farmland, barns, windmills; very winding | gentle climb | none | harvest gold in autumn, green in spring |
| Withering Waters | red-rock canyon, cacti, mesas | climbs | none | a few waterfalls; blooms in spring |
| The Fish Ladder | concrete channel through forest | climbs | none | a waterfall every 170 m |
| The Fish Farm | net pens on a grey lake | flat, open | none | short; feed barrels are the only obstacles |
| Neon Harbor | Harbor under pink city light | barely climbs | shark | |
| Emerald Plunge | temperate rainforest: big conifers, ferns, mist | climbs | bear | the training course borrows its look |
| Riptide Rapids | granite gorge; gold larches in autumn, snow in spring | steepest | bear | most waterfalls and rocks |
| Bamboo Baitway | Japanese mountain stream: bamboo, torii, lanterns | climbs | bear | red maples in autumn, cherry blossom in spring |
| The Hatchery | The Fish Farm with bamboo ashore | flat, open | none | |
| Alpine Lake | wide calm lake ringed by peaks | flat, open | none | ramps, rails and rings only |
| Ancestral Waters | Alpine Lake with maples and torii | flat, open | none |
Seasons are part of each entry: the base settings are autumn (the way up), and a spring
block replaces whatever changes on the way down.
A pack of six salmon swims every course right round you, matching your life stage: each
steers as a flock does (boids: keep clear of your neighbours, swim the way they swim, make for the middle of them) and follows you besides; they leap when you leap and
dive when you dive, and each leaves a small V of foam behind it and a little splash where it leaves the water and lands. In the flow (from x2, fully at x3) the pack draws in close and falls
in step: as high out of the water as you are, and turning every spin, flip and corkscrew you
turn (School.in_step). Other salmon swim further off about their own business, and
there are more of them the higher the stage’s score (3 at the start, up to 16 by 120,000).
All of them avoid rocks, ride ramps and leap falls. They are company only.
On the salt water there is more: swarms of sardines under the surface, each a ball
turning on itself; a wall of sardines that gathers at the edge of the course as you near it,
in place of a line of buoys (edge_swarm.gd); and a chance on every stage of a leatherback
turtle, a humpback whale off to one side (it rolls up to breathe and now and then throws
itself out of the water) and Pacific bluefin tuna that come by from behind
(sea_visitors.gd). Which of those a stage has is rolled when it is begun; more of each
turn up as the score climbs, and a kind the stage did not have turns up anyway once the
score is high enough. They are scenery: nothing touches them.
Touch (and mouse, which counts as a finger)
| Gesture | On the water | In the air |
|---|---|---|
| Drag | a stick under the thumb: drag to one side of where your finger came down and the salmon steers that way, harder the further you drag, for as long as you hold it there (until it meets the bank). Where on the screen you touch makes no difference | |
| Swipe up | full jump (also hops off a rail); dived, comes back up to the surface | backflip |
| Swipe down | dive one layer deeper | frontflip |
| Hard flick left / right | dash 3 m that way, turning a corkscrew as it goes (it takes a fast, flat flick well past the reach of the stick, so that turning does not set it off) | spin with a corkscrew |
| Swipe left / right / down / diagonal | one full 360 that way: spin, frontflip, or both | |
| Wiggle back and forth | boost | |
| Circles | boost | corkscrew, the way the finger goes round |
Touch has no grabs yet.
Keyboard / gamepad keep the fuller set: steer, swim harder or brake, hold-and-release jump (charge), boost, corkscrew, four grabs. See the README for the bindings.
The salmon swims on the surface or dived under it. Swiping down goes down a layer; swiping up comes up one (and from the surface, jumps). Once under, it can also be swum up and down freely, to anywhere between the layers and back to the surface: up and down on the keys or the stick, or a slow drag up or down with the finger held (a quick stroke is still a swipe). Steering and speed are the same at every depth. A river has one layer under the surface (1.7 m down). The Big Blue has six and the Abyss three, 3.6 m apart; the Deadliest Catch has two, 2.6 m apart.
What is under the sea stages with layers (Big Blue, Deadliest Catch, Abyss) is laid out
on its own along a trail of its own, whatever is on the surface above it
(deep in levels.gd):
current_bubbles.gd) are swept along inside it. It is under the water like
everything else there (so the surface tints it from above), and the murk does not hide it.fx/speech.gd)
and then (the jump itself is one; on keys and pads, so is the start of each held spin). A
trick is worth the grade of its swipes taken together, not when it lands. The grades: MISS,
SLOPPY, O.K. (x1.1), ALRIGHT (x1.15), NICE (x1.25), GOOD (x1.35), GREAT (x1.5), EXCELLENT
(x1.75) and PERFECT! (x2). The windows are shares of the gap between beats, so they keep
pace with the tune: at 174 BPM, PERFECT! is within about 25 ms and NICE within about 110.
The callouts run from a dim blue-purple up through blue and green to gold for EXCELLENT,
and PERFECT! is polished platinum with a gleam running across it. NICE or better counts
as “on the beat” for the goals that ask for it.water_lines) and drifts of flat, ragged white foam with clear water between
them (water_whitecaps, more on the open sea). Under that:
its colour runs from shallow to deep with how much water is really
under each pixel, a rim of foam forms wherever something breaks the surface (banks, rocks,
ramps, the fish), and patches of foam drift with the current. Every stage can set any of
its controls (water_* in levels.gd: foam amount, depth range, rim width and so on).textures/foam_noise.png, made by
scripts/tools/bake_foam.gd; any picture that wraps can be set in its place on
materials/water.tres). The noise in the water shader takes its random numbers from whole
numbers, not the usual fract(sin()), which the desktop renderer gets wrong at the corners
of each square (every square then shows as a block).swell says how rough its water is (higher and longer
waves on the open sea than on a river); water_swell_height, water_swell_length and
water_swell_speed shape it. The light falls on the slope worked out at every pixel, so
the surface is smooth however coarse the mesh. Foam can ride the crests
(water_crest_amount), and the water is paler looked down into than looked across
(water_view_clear). Track.swell_y() works out the same waves, and the salmon, the
other salmon, the wake and the splashes ride them. Nothing flashes on the beat: the water
and the light are steady.floor) instead of a river bed:
in sight in the Deadliest Catch and the Reefside, and not drawn at all under the Big Blue.
From underneath, the surface is a bright ceiling that hides the sky.meander in levels.gd).Six tunes, one per step of the map, synthesized in code and baked to audio files. Stages on the same step share a tune.
| Step | Tune | BPM |
|---|---|---|
| 1 | Abyssal | 150 |
| 2 | Reef Break | 160 |
| 3 | River Mouth | 166 |
| 4 | Upriver | 174 |
| 5 | White Water | 186 |
| 6 | Homecoming | 178 |
The beat clock follows whichever tune is playing, so the countdown, on-beat landings, predators and the pulsing scenery all keep time with it. The music is muffled briefly on a wipeout and during long air.
The only map the run has. It is a full-screen scene: the Earth (NASA’s Blue Marble picture, drawn in big pixels) in space, with an atmosphere, a cloud layer above the ground and three hurricanes. It turns to face the stage in hand and never zooms.
conceptArt/ui/levelSelect.png.glint_pixels, which makes
the light come off the water in squares of that many pixels); and the wake (how long, how
wide, a wiggle, gaps, froth down the middle, a second pair of arms).
What is set is the stage’s own preset, used on that stage and no other. SAVE, BACK and
the stage arrows write every stage’s preset into materials/water_presets.cfg, which goes
out with the game (web build included); RESET clears this stage’s; COPY and PASTE carry
one stage’s to another. So the water of a stage is, in order: materials/water.tres, then
the stage’s water_... keys in levels.gd, then its preset.
With a mouse and keys the view can be turned (drag), moved in and out (wheel, or Q and E)
and moved over the water (W A S D), down to under the surface looking up; R puts it back.
H hides the panel, F chooses whether the camera stands over one stretch of water or goes
with the salmon (STILL / FOLLOW), and [ and ] change stage.1990s educational software and science books: Libre Baskerville for headings, Jost for
everything else, navy plates with a cream rule, cream paper buttons that turn gold in hand,
and a few primary colours. The title is set like a book cover. Wording is terse and uses
the life-cycle terms. All of it is defined in scripts/ui/ui_kit.gd.
Godot 4, almost entirely generated at startup: meshes, courses and scenery are procedural, and the music and sound effects are synthesized offline by scripts in the project.
| Area | File |
|---|---|
| Game flow, menus, globe screen, results | scripts/main.gd |
| Stages and how they connect | scripts/world/levels.gd |
| Course generation from a stage | scripts/world/track.gd |
| Procedural meshes | scripts/world/props.gd |
| The salmon: movement, tricks, hazards, autopilot | scripts/player/salmon.gd |
| The other salmon, and shoals of small fish | scripts/world/school.gd, scripts/world/shoals.gd |
| Predators | scripts/world/bear.gd |
| Camera | scripts/world/chase_camera.gd |
| Splash and wake | scripts/fx/splash.gd, scripts/fx/wake.gd (the wake is drawn in shaders/water.gdshader) |
| Water, underwater view, currents | shaders/water.gdshader, shaders/post.gdshader, shaders/current.gdshader |
| The water every stage starts from, and a scene for setting it up in the editor | materials/water.tres, scenes/water_scene.tscn (scripts/tools/water_scene.gd) |
| Scoring and timing grades | scripts/game/score.gd |
| Water lab, field guide | scripts/ui/water_lab.gd, scripts/ui/model_viewer.gd |
| Touch gestures | scripts/ui/touch_controls.gd, scripts/autoload/game_input.gd |
| Globe | scripts/ui/globe.gd, shaders/globe.gdshader |
| Music and the beat clock | scripts/autoload/music.gd, scripts/audio/ |
| Saves and settings | scripts/autoload/save.gd |
Movement is simulated in “track space” (distance along the river, offset across it, height), which keeps it robust on a twisting course. An autopilot plays the game for the title screen and for the automated smoke test.
Things that are true of the build today and likely to matter for the next round of work.
main
rebuilds the public site, and GitHub fails builds that come too close together.The next round is level details, game feel and animation. Starting points: