Quick answer: Water bugs split into two families: physics, where objects sink, float wrong, or jitter on the surface, and performance, where the simulation tanks the frame rate. Both depend on state that changes every frame, the water height at each sample point, the buoyancy forces, the submersion depth, and the cost of the simulation pass. Capture the surface state, the buoyancy data, and the performance numbers when a report fires, and these become reproducible.
Water simulation is one of the most expensive and visually important systems an indie game can attempt, combining a dynamic surface, buoyancy physics for floating objects, and often a fluid solver underneath. When it works it is gorgeous and tactile. When it breaks, players report boats that sink for no reason, objects that float at the wrong height or jitter on the waves, characters that swim through invisible walls, and frame rates that collapse near the shoreline. These bugs straddle physics and performance, and both halves depend on per-frame state that disappears instantly. This post covers the surface, buoyancy, and performance state worth capturing so a sinking-boat report becomes a reproducible case.
Why water bugs span physics and performance
Water simulation is unusual because its bugs fall into two very different buckets that often share symptoms. On the physics side, buoyancy is computed from how much of an object is submerged, which depends on the water height sampled at the object's position, and a wrong height or a bad buoyancy force makes objects sink, pop, or jitter. On the performance side, the simulation pass that generates the surface and any fluid solver can be enormously expensive, and it spikes exactly when the player is near a lot of water, producing frame drops that feel like a different bug entirely.
Both families are hard to reproduce because the state lives for a frame and depends on the player's exact position relative to the water. A boat sinks only at a particular wave phase, or the frame rate tanks only when the camera frames a specific stretch of ocean at a specific detail level. Replaying the moment rarely lands on the same conditions. Capturing the water and performance state at the instant the report fires lets you reconstruct both the wave configuration and the simulation cost, so you can tell a buoyancy bug from a performance one and reproduce whichever it is.
Capturing surface and wave state
The surface is the foundation, so capture its state where the problem occurred. Record the water height and surface normal at the relevant sample points, the wave parameters in effect such as amplitude and wavelength, and the current simulation time that drives the wave phase. A boat that sank often shows a water height sampled below where it should be, perhaps because the sample point fell outside the simulated region or read a stale value. The captured height versus the object position tells you immediately whether the surface itself reported the wrong answer.
Sampling correctness is a frequent culprit, so capture how the height was queried. Record which water body or region the sample came from, whether the query fell back to a default sea level, and the resolution of the simulation grid at that point. Many buoyancy bugs are really sampling bugs: an object straddling two water regions, or sitting at the edge of the simulated grid where the height defaults to zero. Seeing the region and the fallback flag in the capture distinguishes a genuine surface error from an object that simply asked the wrong part of the ocean how high the water was.
Buoyancy and floating object physics
Buoyancy is where floating objects misbehave, so capture the forces directly. For the affected object, record its submersion depth, the buoyancy force applied, the drag and the configured density or mass, and the resulting velocity. A boat that sinks despite looking light usually has a density set too high or a submersion calculation that under-reports how much volume is underwater. Seeing the submersion depth and the buoyancy force side by side reveals whether the physics computed too little lift, which is a tuning or calculation fix rather than a surface one.
Jitter on the surface is its own buoyancy bug, usually a feedback instability. An object bobbing violently is being pushed up by buoyancy and pulled down by gravity in an oscillation the solver never damps, often because the buoyancy force is applied too strongly or without enough drag. Capture the per-frame buoyancy and drag forces and the vertical velocity so the oscillation is visible as alternating signs. That pattern points straight at insufficient damping or too stiff a buoyancy response, which you can tune once you see the forces fighting each other instead of just the visible bobbing.
Performance cost of the simulation
The performance family needs its own capture because frame drops near water are a distinct bug. Record the time the water simulation pass took on both CPU and GPU, the number of simulated grid cells or particles active, the detail level or tessellation in use, and the overall frame time. A report of the game chugging at the coast becomes actionable the moment you see the water pass consuming half the frame, and the active cell count tells you whether the cost came from too much surface being simulated at full detail near the camera.
Level of detail and culling state explain why the cost spikes where it does. Capture the distance-based detail settings, whether off-screen water was being simulated, and how many reflection or refraction passes were active. Many water performance bugs are LOD failures: the simulation runs at full resolution for water the player can barely see, or reflections render the whole scene a second time. Recording the detail level and pass count alongside the timing lets you pinpoint which part of the water budget blew up, turning a vague performance complaint into a specific, fixable cost.
Setting it up with Bugnet
Bugnet's in-game report button can snapshot the water system when a player taps it, capturing both families at once. Alongside the device and platform context, the SDK attaches the surface height and wave parameters at the relevant points, the affected object's submersion and buoyancy forces, and the simulation timing with the active cell count and detail level. Instead of a ticket reading my boat sank or the water is laggy, you receive a record that tells you whether the surface sampled wrong, the buoyancy under-lifted, or the simulation pass blew the frame budget.
Water bugs are tightly tied to hardware and location, so occurrence grouping and filtering matter. A performance collapse on a particular GPU near a particular shoreline generates many reports that are really one issue, and Bugnet's grouped count shows the scope. Custom fields for the water region, the detail level, and the simulation frame cost let you filter the dashboard to, for example, every report where the water pass exceeded a millisecond threshold on a given GPU class, separating the genuine performance regressions from the physics complaints so each goes to the right fix.
Testing water across hardware
Teams that ship convincing water test both families deliberately and across a spread of hardware. For physics, drop objects of varied density into water at different wave phases and confirm they settle without jitter, and test at the edges of water regions where sampling falls back. For performance, profile the simulation pass on your weakest target GPU with the camera framing the most water at full detail, and verify your LOD and culling actually reduce cost with distance. Each maps to a real report you would otherwise field.
After launch, let the captured state route the work. Send the physics reports, with their submersion and force data, to gameplay, and the performance reports, with their timing and cell counts, to rendering, and reproduce each from the recorded state. Group by GPU class and water region to find where the simulation strains, and tune the detail curves or fix the sampling there. Great water is less about the prettiest shader than about a simulation that stays correct and affordable everywhere players go, which you ensure by always capturing both what the water did and what it cost.
Water breaks as physics or as performance. Capture the surface, the buoyancy, and the sim cost and you always know which one you are fixing.