Onceworlds
Engine · Water

Water, swimming and floating

Water and lava, swimming, floating on the waves, and water that hurts.

Don't make water out of a blue plane. The API reference ("Water3D and Buoyancy") has every field.

The default path: one Water3D

import { Transform } from '@onceworlds/engine';
import { Water3D } from '@onceworlds/engine/modules';

world.spawn([Transform({ position: [0, 0, 0] }), Water3D.preset('lake', { size: [80, 80] })]);

The surface is the entity's height and spreads size (x, z) around it. It moves with waves, shows the sky, gets clear and soft at the shore and foams where it meets things, by itself. In a scene it is a node of kind Water3D.

Preset For
ocean Big swell, deep blue, whitecaps: islands, boats, pirates. waves 0.7 m.
lake Calm, green-blue, small ripples: most levels. The defaults.
pool Clear turquoise, almost still: pools, fountains, a bathhouse.
lava Glowing, crusted, slow: a floor that hurts. Nobody swims in it (swim: false).
toxic Bright green sludge: swamps, labs, sewers.

Change it with fields (waves, waveLength, shallow, deep, clarity, foam, glow...) rather than drawing your own. A scene file keeps values: a node that names a preset and leaves its values out gets a lake, and the loader prints the line to write.

Swimming

A character with Character3D swims in any Water3D once more than its swimDepth (0.9 m) is under: jump swims up, drop or crouch dives, and at the surface it stays afloat until it jumps out. Nothing to add.

Things that float

Give a dynamic body Buoyancy and it floats on whatever water is under it, riding and tipping with the waves:

import { Body3D, Buoyancy, Collider3D, Mesh, Material } from '@onceworlds/engine/modules';

world.spawn([
  Transform({ position: [0, 1, 0] }),
  Body3D.dynamic({ mass: 60 }),
  Collider3D.box({ size: [3, 0.4, 2] }),
  Buoyancy(),                                   // float 1: half under, like wood
  ...Mesh.box([3, 0.4, 2], Material.standard('#8a5a32')),
]);

float is how it sits: 2 rides high (a beach ball), 1 half under, 0.5 just under, less sinks slowly (a stone: 0.2). drag is how much the water slows it. The mass doesn't matter: the push is relative to its own weight. Needs Physics3D.

Hurting in lava, and other rules

waterAt(world, x, z) is the water at a point: { surface, bottom, density, swim, entity }, the same waves the player sees.

import { defineSystem } from '@onceworlds/engine';
import { waterAt } from '@onceworlds/engine/modules';

const Burn = defineSystem({                     // Health is the game's own component
  name: 'burn',
  stage: 'fixed',
  query: [Health, Transform],
  run({ query, world, time }) {
    query.each((_e, health, tr) => {
      const lava = waterAt(world, tr.position.x, tr.position.z);
      if (lava && !lava.swim && tr.position.y < lava.surface) health.hp -= 40 * time.dt;
    });
  },
});

Islands and coasts

Terrain3D.preset('island') falls below 0 at its edges: put Water3D.preset('ocean') at height 0 over it and the shallows, beaches and deep water colour come by themselves (see terrain.md).

Limits