About

An early prototype of Wavebreakers in motion: ocean swell, wakes as player-generated geometry, dynamic lighting and weather, and a stylised realism aesthetic.

Wavebreakers is a multiplayer arcade jetski racer I’m building in Godot. My core focus is the ocean fluid mechanics: wakes are real, player-generated geometry, and tides and swell act as dynamic track features the player can ride. The design hinges on core mechanics executed deeply rather than a breadth of features: make the water feel dynamic and alive, build a cohesive, inviting visual identity, and the rest of the game will follow.

Currently I’m still in the early prototyping phase, figuring out how to simulate the ocean, how to make it fun, and how to make it look good.

Implemented so far are:

  • A deterministic sum of Gerstner wave components for the base ocean surface, with a separate deterministic channel for player-generated wakes.
  • Dynamic lighting with hand-tuned LUTs and post-processing for each, with a mechanism to transition smoothly between them.
  • Dynamic volumetric clouds, again supporting smooth transitions between different weather states.
  • Shaders for water, foam, caustics, and spray, with a physically based rendering (PBR) approach to simulate authentic light scattering and water reflections and refractions.

Stylistically, the visual direction forgoes realism in favour of stylised realism. This not only makes it easier for me, a non-artist, to implement; it also allows the ocean to be more readable and expressive.

It gives me creative latitude to push visual style with exaggeration, ignoring true realism, while still being grounded in physical simulation. In my world the water is always clear, the waves are beautiful, and the lighting is always dramatic.

I initially intended for this to be cel-shaded, but the resulting look was too flat and cartoonish, and the opaque water just didn’t work. I realised what I wanted was sort of a Pixar version of reality.

I’m pairing simplified asset textures and geometry with highly saturated colour palettes and relying on lighting and shader effects to make it interesting. Clear turquoise water over white sand during the day, deep purples and oranges at sunset, dripping with effects like caustics, sea spray, bloom, glare, and sub-surface scattering for backlit crests.

Crucially, every property that impacts handling remains physically simulated - the visuals live on the GPU but are scoped to ensure they do not affect gameplay. Skilled play demands reading the ocean: launching off swell crests for trick boosts, riding wave fronts for extra speed, aligning landings to maintain velocity, and drafting in a rival’s wake to slingshot past.

The constraint that shapes everything

One rule governs the entire architecture: gameplay water is CPU based, deterministic, and never reads from the GPU or relies on previous state*. The sea surface is a pure function of position and synchronised game time, calculated via a sum of Gerstner wave components, so that every client in an online race evaluates an identical base surface for a given game tick.

The vehicle physics loop is structured as a pure (state, input, tick) function, allowing all client prediction, reconciliation replay, ghost playback, and AI bots to use a single code path.

Because the game is modest in scale, the majority of the performance budget is allocated to the ocean simulation, lighting, and weather. The CPU remains the source of truth. Everything is split into either simulation and presentation, with presentation reading from simulation. This one-directional causality and deterministic nature is what allows the ocean simulation to be highly ambitious, while remaining viable for low-latency online multiplayer.

What this blog documents

This devblog tracks the technical systems and overall development progress. Posts will deep dive into architecture decisions, hidden complexities, optimisation, and roadblocks I hit along the way. Where possible, breakdowns will be grounded directly in actual game code.

Workflow & Tooling

This project and devblog are the work of a solo software developer.

I’m using modern development tools, including AI (Claude and Gemini are my current choices). These help me accelerate code prototyping, scaffold boilerplate, and refine text structure — my experiences with AI-assisted development will likely form their own posts in time, as there are tremendous efficiency improvements to be had, especially for rapid prototyping, but also some unique challenges.

I own every architectural decision and stylistic choice, and write the copy for this blog. I’m leaning heavily on AI for developing the interactive demos and scaffolding.

Subscribe by RSS.