A first-person sailing game: a 9 m bermuda sloop, rolling seas and procedurally generated islands. Built with Bevy 0.20.
cargo runThe first build compiles Bevy with optimisations and takes a while; later builds are quick.
.cargo/config.toml makes the x86_64-pc-windows-gnu target link with Rust's
bundled LLD. That toolchain also needs a working dlltool; the one it ships
cannot run on its own, so use LLVM's:
rustup component add llvm-toolsthen copy llvm-ar.exe to llvm-dlltool.exe in the toolchain's
lib/rustlib/x86_64-pc-windows-gnu/bin directory and point rustc at it from
~/.cargo/config.toml:
[target.x86_64-pc-windows-gnu]
rustflags = ["-C", "dlltool=<path to>/llvm-dlltool.exe"]None of this applies to the MSVC toolchain.
powershell -ExecutionPolicy Bypass -File tools\package.ps1
makes a release build and puts cartographer.exe, the assets folder and
a short README.txt in dist\Cartographer, zipped as
dist\Cartographer.zip (about 38 MB). Whoever gets it unzips it and runs
the executable; it needs 64-bit Windows and nothing installed. The first
release build takes a quarter of an hour.
The assets go as they stand, so what has been placed and where the player starts go with them. A release build opens no console window, and its symbols are stripped. It is not signed: Windows will warn about it the first time it is run.
| Input | Action |
|---|---|
| Left click / Esc | Capture / release the mouse |
| Mouse | Look |
| W A S D | Walk, swim (swimming follows where you look) |
| Space | Jump, swim upwards, let go of the ladder |
| Left Shift | Hurry |
| Q / E | Turn the control under the crosshair |
| F12 | Debug mode: fly, and tune the islands and the water |
Look at a control from within arm's reach and hold Q or E. Once you have hold of it you can look away, to watch the sails or where you are going, and it goes on turning until you let the keys go:
- Helm (wheel at the aft end of the cockpit): Q steers to port, E to starboard. The wheel stays where you leave it; the red spoke is upright when the rudder is centred.
- Mainsheet winch (aft end of the cabin top): E trims the mainsail in, Q eases it out.
- Jib sheet winches (on the cockpit coamings, either side): E trims the jib, Q eases it.
- Main halyard (port side of the cabin top, nearer the middle): E hoists the mainsail, Q lowers it into the boom. Part way is a reef.
- Jib furling line (port side of the cabin top, outboard): E lets the jib out, Q rolls it up on its stay.
- Anchor windlass (foredeck): Q lets the anchor go, E weighs it. It holds in under 40 m of water, so only near islands.
Every ship has a line coiled on a cleat each side at the bow and the stern; the dinghy has a painter at her stem and a line at her transom.
- Taking a line: look at the coil and left click. The line is in your hand and pays out behind you as you go. A tool in your hand is put away.
- Making it fast: look at a cleat or a bollard ashore, one of the cleats on a dock, the ring beside the quay steps, or the ring on top of a mooring buoy, and left click.
- Casting off: left click where the line is made fast, and it is in your hand again. Left click its own cleat aboard to coil it down.
- Easing and taking in: look at the line's cleat aboard and hold Q to ease it or E to take it in. You can take in only so hard: she comes in as fast as she will, and not against a strong wind.
- A line is 30 m. Carried further than that from its cleat it goes back to its coil, and so it does if you choose a tool with it in hand.
- With a bow line and a stern line she lies alongside. By one line she swings to it.
- Ropes lie on the ground and float on the sea, and go through everything else. The lines go with the ship: they are not saved.
A bigger sister of the sloop, spawned from the debug menu's Ship tab. On deck she is worked exactly as the sloop is; she is a little faster and steadier. She has a cabin:
- Going below: walk forward from the wheel, up on to the bridge deck and down the two steps of the companionway in the middle of the cabin's after end. Come back up the same way.
- Below: the saloon, with a settee each side and a table on the mast; a galley to port and a chart table to starboard at the foot of the steps; and through the door forward, a berth in the bows. You can see out of the windows. None of it does anything yet.
- You cannot jump below decks, and from the cockpit the cabin top is reached by way of the side decks.
A 13.4 m catamaran drawn after the HH44, spawned from the debug menu's Ship tab: two slim hulls 7.15 m over all, a deckhouse with glass all round it on the bridge deck between them, a hard top with solar panels over the cockpit, and a tall mast with a square-headed mainsail.
- There is a helm on each quarter, on the side deck, and either wheel steers her. You are put at the starboard one. Every line comes aft to the helms: the winches beside the starboard wheel are the mainsheet and a jib sheet, and beside the port wheel the other jib sheet, the main halyard and the jib's furling line. The anchor windlass is on the foredeck.
- From either helm it is a step down into the cockpit, and from there through the door into the saloon, which has a galley, a settee with a table, and a chart desk. None of it does anything yet. You cannot jump under the roof.
- Forward there are nets between the hulls to walk on, as far as the beam the forestay comes down to. Each hull ends aft in two steps down to a platform by the water, with a ladder to climb out of the sea by.
- She sails nearly flat and is fast: about 10 knots on a beam reach in a breeze the sloop makes 6 in, and 15 as it freshens.
- She does not point as high as the sloop, and is slower through a tack. Keep her speed up going into one.
- With too much sail up in a gale she can be capsized, and will not come back up. Despawn her and spawn another.
A small open rowing boat, spawned from the debug menu's Ship tab in place of the sloop. You sit in it, so your eyes are lower than on the sloop.
- Oars (in front of you from the stern thwart): look at them and hold E to row ahead or Q to back water. While you row, A and D ease the oar on that side, which turns her that way. Flat out she makes about 3 knots.
- Getting aboard: from the water, swim up to the stern and press W to climb in over the transom. In the shallows you can step in over the side.
- She has no sails, anchor or sailing panel, and the wind and the waves push her about far more than they do the sloop.
Hold Tab to open the tool wheel in the middle of the screen. Move the mouse to pick a sector and let Tab go to take up what is in it. Letting go without picking one, or on an empty sector, puts away whatever you hold.
- Spyglass (top sector): it comes to hand low on the right. Hold the right mouse button to raise it and look through it; Q and E draw it in and out, from 2 to 10 times. The view turns more slowly the more it is magnified, and Q and E do not work the ship's controls while it is at your eye.
- Flare gun (right sector): a left click fires a red flare the way you are looking. Fired well up it climbs to about 125 m, burns for 9 seconds and lights the ground under it at night. It goes out if it comes down in the sea. The next one takes 2.5 seconds to load, and they do not run out.
- Compass (bottom sector): its card keeps its N to the north, and the
black line on the far side of its case is the way you are facing, so the
letter under the line is your heading. Hold the right mouse button to
bring it up under the crosshair. The bearing is also written out above
the hint, as three figures and a point:
054 NE. The card takes a moment to settle after a quick turn. North is true north.
The last sector is empty for now.
You can only leave the deck by jumping over the side. To get back aboard, swim to the ladder on the transom and hold W. Anchor before you go ashore, or the boat will not be where you left it.
The panel in the bottom-right corner is shown while you are aboard or within 10 m of the boat. It shows how the sails are set and the ship's instruments:
- The dial is the boat seen from above, bow up, on a compass card that turns with the ship: the mark under the pointer at the top is your heading.
- Both sails are drawn at their real angles. A sail drawn in red is luffing.
- The blue arrow is the true wind, the yellow arrow the apparent wind, and the red wedge the no-go zone you cannot sail into.
- Each sail has a bar that fills as its sheet is hauled in, and a verdict such as "Trimmed", "Over-trimmed", "Stalled - ease" or "Luffing - sheet in". The bar is as long as there is sail set: it shortens as the mainsail is lowered or the jib rolled up.
The vane at the masthead also points into the apparent wind.
- The boat cannot sail closer than about 40 degrees to the true wind. Pointed too high, the sails luff (they shake and turn red on the dial) and the boat stops.
- Sails work best when eased until they are just short of luffing: sheeted hard in when close-hauled, well out when running downwind.
- Over-sheeting stalls the sails and makes the boat heel instead of drive.
- The mainsail pushes the bow towards the wind and the jib pushes it away, so the boat steers itself to some extent according to how the two are trimmed.
- The keel draws 1.5 m. Run it into the shallows and the boat goes aground.
- In a strong wind, set less sail: the boat heels less and is easier to steer. Under the mainsail alone she will not bear away from a standstill with the wind forward of the beam, so keep some jib.
- To stop, turn into the wind. Letting both sheets right out slows the boat but does not stop it unless the wind is forward of the beam.
| File | Contents |
|---|---|
src/ocean.rs, assets/shaders/ocean.wesl, assets/shaders/waves.wesl |
Wave field (CPU and GPU copies that must match), ocean and sky materials |
assets/shaders/submerged.wesl |
The sea over a point of the ground, for its wet sand and the foam at the water's edge. What is under the sea is faded into it by the surface, in ocean.wesl |
src/terrain.rs, assets/shaders/terrain_detail.wesl |
Island placement, heightmaps and meshes, streaming, ground queries, fine ground detail |
src/rocks.rs |
Generated rock shapes and where an island's rocks go |
src/trees.rs |
Generated tree shapes and where an island's trees go |
assets/shaders/rock.wesl, assets/shaders/boulder.wesl |
The pattern rock is shaded with, shared by cliffs and scattered rocks |
src/island_gpu.rs, assets/shaders/island_height.wgsl |
The compute shader that defines island shapes, and the code that runs it and reads the heights back |
src/ship/ |
The kinds of ship: a Hull for each (hulls.rs) with its dimensions and what can be walked on, their rigs (Rig) and controls; loading and animating the model, wind, buoyancy, grounding |
src/ship/finish.rs, assets/shaders/finish.wesl |
The finish of a ship's wire and chrome |
tools/build_sloop.py |
Blender script that builds the sloop: writes art/sloop.blend and assets/models/sloop.glb |
src/sailing.rs |
Sail, keel and rudder forces, and the Design of each boat that sails |
src/rowing.rs |
The dinghy: oars, drag and how she turns |
tools/build_dinghy.py |
Blender script that builds the dinghy: writes art/dinghy.blend and assets/models/dinghy.glb |
tools/build_catamaran.py |
Blender script that builds the catamaran: writes art/catamaran.blend and assets/models/catamaran.glb |
tools/boatyard.py |
What the model scripts build with: the shared materials and the mesh builder |
src/placed/, assets/placed.ron |
Assets placed in the world by hand: the kinds there are, the dock, quays and breakwater built to a length, carrying a new one on the cursor, what is solid about them, their lamps and buttons, and the data file |
tools/build_lighthouse.py |
Blender script that builds the lighthouse: writes art/lighthouse.blend and assets/models/lighthouse.glb |
tools/build_lamppost.py |
Blender script that builds the lamppost: writes art/lamppost.blend and assets/models/lamppost.glb |
src/selector.rs |
Pressing the button of a ship selector: taking the ship away and bringing the next kind |
tools/build_harbour.py |
Blender script that builds what of the harbour has a model: the bollard, the cleat, the two harbour lights and the hut, each to art/<name>.blend and assets/models/<name>.glb |
tools/build_shore.py |
Blender script that builds what stands ashore: the flagpole, the signpost, the cairn, the campfire, the bench, the crate, the barrel and the lobster pot, each to art/<name>.blend and assets/models/<name>.glb |
tools/build_mooring_buoy.py |
Blender script that builds the mooring buoy: writes art/mooring_buoy.blend and assets/models/mooring_buoy.glb |
tools/build_navigation_buoy.py |
Blender script that builds the navigation buoys, red and green, and their chain: writes art/navigation_buoy.blend, assets/models/navigation_buoy.glb and the same with _green |
tools/build_ship_selector.py |
Blender script that builds the ship selector: writes art/ship_selector.blend and assets/models/ship_selector.glb |
tools/package.ps1 |
Builds the game for sending to someone: a release build and the assets, zipped in dist |
src/sails.rs, assets/shaders/sail.wesl, assets/shaders/rope.wesl |
The sails as cloth and how they furl, telltales, and the sheets, halyards and furling line as rope |
src/sky.rs, assets/shaders/sky.wesl, assets/shaders/sky_common.wesl |
The calendar, and the sun, moon, stars and light it gives |
src/weather.rs, assets/shaders/rain.wesl |
The pressure map and the weather read off it; rain |
src/clouds.rs |
The block of noise the clouds are cut from |
src/sky_config.rs, assets/sky.ron |
The sky's parameters: the clouds and the weather |
src/player.rs, assets/spawn.ron |
First-person controller and control interaction, and where the player starts |
src/tools.rs, assets/shaders/tool_wheel.wesl, assets/shaders/spyglass.wesl |
The tool wheel and the spyglass |
src/mooring.rs |
Mooring lines: taking them in hand, making them fast, easing and taking in, and the ropes as they are drawn |
src/flare.rs |
The flare gun, and the flares it fires |
src/compass.rs |
The compass |
src/crosshair.rs |
Who a key or a click is for: the turns the controls, lines, buttons and tools take, and the prompt the HUD shows |
src/hud.rs |
The date, the crosshair and prompts |
src/trim.rs, assets/shaders/trim_dial.wesl |
Sail and wind status panel |
src/island_config.rs, assets/islands.ron |
Island types: the data file and the code that loads, validates and saves it |
src/data.rs |
Where the data files are, and the reading, falling back and saving they all share |
src/maths.rs |
Sums more than one part of the game does: smoothstep, a hash, a noise |
src/water_config.rs, assets/water.ron |
The sea's parameters: waves, clarity and colour |
src/debug_menu.rs |
F12 debug mode: free flight, the island, water and sky editors, and the Ship and Assets tabs |
src/dev.rs |
Scripted input and screenshots for testing without a keyboard (see its header) |
- Ocean and sky shading after afl_ext's Very fast procedural ocean (MIT).
- Island erosion uses Rune Skovbo Johansen's
erosion filter through the
bevy_erosion_filtercrate (MPL-2.0).
The sloop is generated by tools/build_sloop.py. To change it, edit the script
and run it in Blender (Scripting tab, or blender --python tools/build_sloop.py);
it rebuilds the scene, saves art/sloop.blend and re-exports the .glb. Hand
edits to the .blend are overwritten by the next run.
The same script builds the 36 footer, which is the sloop scaled up with a
hollow hull and a cabin: blender --background --python tools/build_sloop.py -- sloop36 writes art/sloop36.blend and assets/models/sloop36.glb. What
can be walked on below is the below module of src/ship/hulls.rs, which mirrors
the script. The dinghy has a script of its own, tools/build_dinghy.py, and so has
the catamaran, tools/build_catamaran.py, which builds all of her but the
parts the game moves; those it has the script for the sloop make, to her
measurements. What can be walked on aboard her is the cat module of
src/ship/, and her mast, sails and the leads of her lines are CAT_RIG
there.
The game does not collide against the mesh. The deck outline, deck heights and
control positions are constants in src/ship/ that the script mirrors, so
keep the two in step. The parts the game moves (BoomPivot, Mainsail,
JibPivot, Jib, Wheel (or WheelPort and WheelStbd), the winches, Windlass, WindVane) are found by
node name.
Islands are defined in assets/islands.ron: a list of types, each with a
name, a weight (how common it is), a radius range and a full set of shape
parameters. Every island in the world is one of these types, and the first
type is always the home island. The file is read when the game starts, so
editing it needs no rebuild, and its header comments describe each field.
To add a type, copy one of the entries, rename it and change its values. Any parameter you leave out takes the built-in default.
The shape itself is computed by assets/shaders/island_height.wgsl; the data
file only supplies its inputs.
The sea is defined in assets/water.ron: how its waves are generated (scale,
height, speed, choppiness), what keeps it from looking the same everywhere
(bent crests, groups of bigger waves, a long swell that runs with the wind
and smooth patches that lie along it in light airs), how
clear the water is, its colour, and what
happens near a shore (calmer swell, rollers and foam) and round the boat
(foam at the hull, bow waves and a wake astern), and how the foam itself
looks and how readily wave crests break into whitecaps in a wind. The file
is read when the game starts, and its header comments describe each value.
The boat and the swimmer float on the same waves that are drawn, so changing
the waves changes how the boat rides.
A day lasts an hour of play. A month is ten days, in which the moon goes from new to full and back, and a year is four months: spring, summer, autumn and winter. The game starts at 08:00 on the first of spring, and the date and time are shown in the top-left corner.
The noon sun stands overhead at midsummer and 30 degrees to the south at midwinter. By night the moon lights the sea as far as its phase allows.
R hurries a passage along: the boat, the sea, the weather and the calendar
all run five times as fast until R is pressed again, and the top-left corner
shows x5 meanwhile. You walk, steer and work the winches at your usual
speed, so the boat answers the helm five times as quickly as you turn it.
With the debug menu open, [ and ] step the time back and on by an hour,
or by a day with Shift held.
Highs and lows of pressure drift over the sea and bring the weather with them: more cloud as the pressure falls, then rain and poor visibility, and a wind that blows round each low and strengthens where the pressure changes quickly. A spell of bad weather usually takes ten to twenty minutes to pass.
The barometer under the date in the top-left corner is the forecast: a falling glass means cloud and wind are on the way. You can also see weather coming, as thicker cloud towards the quarter it lies in.
The clouds have depth: flat bases, rounded tops, and light and shade from
the sun or the moon. How they are shaped and lit, and how the weather
behaves (its speed, the size of its systems, how fair it is on the whole and
how much wind it raises), is defined in assets/sky.ron, whose header
comments describe each value.
F12 opens a panel for editing the game's data files and lets you fly. F12 again closes it and leaves you where you flew to, on your own feet: on the ground, in the sea, or aboard if you were over the ship's deck.
-
Tabs:
Islandsedits the island types,Wateredits the sea andSkyedits the clouds and the weather.Shipedits no file.Assetsedits what has been placed in the world by hand. -
Ship:
Despawn the shiptakes the ship out of the world, with everything aboard; if you were aboard you are left in the sea.Spawnputs a new one in about 16 m ahead of the camera, lying square to the wind, if the water there is deep enough. There is one ship at a time: the sloop, the 36 ft sloop, the catamaran or the dinghy. -
Where you start: also on the Ship tab.
Spawn heremakes the game start with you where you are now, facing the way you are facing, in place of at the helm;Spawn at the helmputs that back. Both writeassets/spawn.ronat once. The ship starts where she always does. -
Assets: the list at the top is everything placed; the mouse wheel scrolls it.
- Adding one: under
New instance(click the heading to shut or open it) pick a kind: the wooden dock, the dock section, the lamppost, the lighthouse, the ship selector, the red buoy or the green buoy, the mooring buoy, the pieces of a harbour, or what stands ashore (all listed below). It is carried on the cursor, 12 m off or just short of whatever the cursor is on if that is nearer: the ground, the sea, a ship, a rock, a tree or another placed asset. A left click away from the panel sets it down and selects it. A right click gives up. Holding the right button still looks around. - Changing one: click it in the list. Its three axes are drawn on it
in the world, and the rows below move it east, up and south, turn it
in yaw, pitch and roll, and scale it. A dock, a dock section, a quay,
the quay steps and a breakwater also have a
Length, in metres: they are built in the game to whatever length they are set to, and the far end moves while the end at the origin stays put. A position and a length have no ends to slide between: drag the bar and it moves 2 cm for each pixel, or use - and + for 10 cm.Remove ittakes it out of the world. - Nothing is kept until Save, which writes
assets/placed.ron. - The dock is 14 m long when set down, and can be made anything from 3 m to 200 m. It is solid. You can walk on it, step onto it from ground within 0.6 m of its deck, and climb the ladder at its outer end out of the water: swim up to it facing the dock and hold W. A ship is stopped by it and slides along it. You cannot swim under it.
- The dock section is the dock without its ladder, for a dock that turns
a corner: a longer straight one is one dock with a longer
Length. Nothing snaps into place. - The lamppost lights itself at dusk and goes out at dawn. It lights what
stands near it, without shadows; the sea does not take its light. Its
post is solid. Set on a dock it is carried a little above the deck:
bring it down with
Up (y), to 1.1 on a dock that is at 0. - The lighthouse stands on a slab 2 m deep whose sides are steps, with
its door towards you as you place it. It is set down with the floor of
the tower where the cursor is on the ground; on a slope, raise or sink
it with
Up (y)until the high side of the ground meets the top of the slab, and walk up the steps on the low side. Inside, a spiral stair of 80 steps goes up to the lantern, where a door leads out onto the gallery. After dark its beam goes round once in 3 seconds. - The ship selector is a pedestal with a button. Out of debug mode, walk
up to it, put the crosshair on the button and press E: the ship is
taken away and the next kind comes, in the order sloop, 36 ft sloop,
catamaran, dinghy. She comes out beyond the pedestal from where you
stood to place it, the way the arrow on its plate points, lying with
her bow to your right and her sails stowed. Her near side is 3 m from
the button, or as much further out as it takes to find water to float
her clear of the dock, up to 40 m more. Put it on the outer end of a
dock: off a beach the bigger ships come a long way out. Like the
lamppost it wants bringing down onto a dock's deck with
Up (y). - The mooring buoy is a round float with a ring on top to make a line fast to, and 20 m of chain under it. It rides the sea as the navigation buoys do, and does not move from where it is put.
- A navigation buoy, red or green, is a float with a cage and a lantern on it,
and 50 m of chain hanging straight down under it. It rides the sea:
wherever it is put it is kept at the surface, going up and down with
the waves and rocking to them, so
Up (y)does nothing to it. After dark its light flashes its own colour, 0.6 seconds in every 4. A ship is stopped by the float. The chain is not laid on the bottom: in shallower water it goes on down through it. - The harbour is made of pieces:
- The stone quay is 8 m long when set down, 4 m wide, with its top
level with a dock's deck. Like a dock it runs out from its origin,
and is stretched with
Length, from 1 m. - The quay steps are a quay with steps down its right-hand side, near its origin, to a landing just under the water, to come ashore by. Stretched, from 5.5 m, the wall past the landing grows.
- The breakwater is 10 m of a mound of rock when set down, flat on top, and can be climbed out of the water up its sides. It stretches from 2 m.
- The bollard and the cleat stand on a quay or a dock: bring them down
onto it with
Up (y). - The harbour light, red or green, is a white tower 4.3 m high whose light is steady from dusk to dawn.
- The harbour hut is a wooden hut 4 m by 5 m on a stone footing that goes a metre down, for ground that is not level. Its doorway is on the side you place it from. A lamp hangs inside.
- The stone quay is 8 m long when set down, 4 m wide, with its top
level with a dock's deck. Like a dock it runs out from its origin,
and is stretched with
- Ashore:
- The flagpole is 8 m high. Its flag flies the way the wind is blowing, and is drawn in to the pole in light airs.
- The campfire burns from dusk to dawn, and flickers.
- The signpost, the cairn, the bench, the crate, the barrel and the lobster pot are there to be put about. Each is solid.
- A new kind is a model and an entry in
KINDSinsrc/placed/kinds.rs, with the boxes, ladders, round walls, stairs and floors that make it solid and the lamps and beacons it has, if any. One built to a length is built insrc/placed/built.rsinstead of having a model.
- Adding one: under
-
Holding the weather: on the Sky tab, set
Hold weatherto 1 andHeld pressureto anything from -1 (storm) to 1 (settled) to look at one kind of weather. This is not saved. -
Flying: W A S D along where you look, Space up, Left Ctrl down, Left Shift for speed. The mouse is free for the panel; hold the right button to look around.
-
Island type: the
<and>buttons choose which type the sliders edit. -
Sliders: drag a bar, or use the - and + buttons either side for single steps. Loaded islands rebuild a moment after a change, nearest first.
-
Save writes the open tab's values back to its file (
assets/islands.ron,assets/water.ron,assets/sky.ronorassets/placed.ron). Reload rereads that file, discarding unsaved edits.
Why the game is built the way it is, one decision per document, is recorded in
docs/.