# df_geom
The geometry bench the deep-water animals are built from.
The engine ships eight primitives — cube, sphere, cylinder, cone, torus,
capsule, plane, octahedron — and none of them is an eel. So every body in
`fauna/lower` is **lofted**: a profile of rings is swept along an axis or along
a path, welded into a closed surface, given area-weighted smooth normals, and
uploaded once with `renderer.mesh.create` as a runtime GPU mesh that every
sighting of that species reuses.
## Builders
| Call | Makes |
|---|---|
| `Geom.lathe(rows, radial, opts)` | a profile revolved around +Y — bells, mantles, jaws, beads. Rows are `{ y, r }` or `{ y, rx, rz }`. |
| `Geom.blade(spine, thickness, radial)` | a flattened lathe — fins, webs, ear-flaps, ctene plates. Spine rows are `{ y, w }`. |
| `Geom.tube(stations, radial, opts)` | a profile swept along a 3D path with a parallel-transported frame — eels, arms, tentacles, the elbow of a bigfin squid. Stations are `{ x, y, z, r }`. |
| `Geom.chain(parent, prefix, n, len, r0, r1, material, radial, meshKey)` | a run of **parented** links along −X. A few degrees per link compounds into a smooth curve, which is how a body undulates without a skeleton. |
| `Geom.profile(y0, y1, steps, f)` / `Geom.spindle(len, r, steps, bias)` | row sugar. |
`opts` on `lathe` takes `capTop` / `capBottom`; on `tube` it takes `close`,
`closeStart` and `closeEnd` — a head that opens into a mouth leaves its front
end open and puts the gape geometry inside it.
## Meshes and parts
`Geom.handle(key, fn)` memoises by key: the builder only runs on a miss, so a
comb jelly's eighty ciliary plates upload one mesh and then only spawn
transforms. `Geom.part(parent, name, key, fn, material, opts)` spawns one piece
of an animal — an entity carrying that memoised mesh and a material.
`Geom.forgetAll()` drops both caches so a geometry edit is picked up on the
next build; it leaves the GPU meshes alone, because a sighting may still be
drawing one.
## The rig index
A species' `animate(root, t, ctx)` is handed nothing but the root, so
`Geom.rig(root)` walks the hierarchy ONCE per sighting and returns a
`name -> entity` map, cached by root id and swept when the table grows.
Reach for `P.sd_esca` rather than iterating children every frame.
## Conventions in this slice
- Fish are built **head toward +X**, dorsal +Y, flanks ±Z. The camera is a
side-on station, so the flank is what the player reads.
- Jellies, octopuses and squid are built **mouth or mantle UP**, along +Y.
- A `blade` points along +Y with its width in X; `localEulerAngles = {0,0,90}`
lays it back along −X, `{±90,0,0}` swings it out along ±Z.
Consumed by every `df_sp_*` module in `fauna/lower`. Slice owner: fauna-lower.