Parent: #1036. Completes the 36-force catalog.
Add the structure-field hooks, then fieldflow.
Force::field(&self, body, at) -> Option<Vec3> (default None) — the renderable/followable structure field a body radiates. Implement for gravity (radial well), charge (radial monopole), magnetism (dipole). Port dipoleField/monopoleField/bodyGravityField into math/geometry.rs (from natural.ts + geometry.ts).
netField(bodies, forces, x, y) superposition, exposed via env.field_at.
fieldflow (extended.ts §20.3): steer velocity onto the local net field line (speed-preserving, like align) and stream along it (does work); opt-in data-charge-gated follows only charged matter.
Files: engine/types.rs (Force::field, env.field_at), math/geometry.rs, forces/natural.rs + extended.rs, engine/integrator.rs (compute field_at each frame).
Acceptance: matter threads a dipole's loops / streams off a monopole; charge-gated variant leaves neutral matter free; parity count → 36 (COMPLETE); gate green.
Parent: #1036. Completes the 36-force catalog.
Add the structure-field hooks, then
fieldflow.Force::field(&self, body, at) -> Option<Vec3>(default None) — the renderable/followable structure field a body radiates. Implement forgravity(radial well),charge(radial monopole),magnetism(dipole). PortdipoleField/monopoleField/bodyGravityFieldintomath/geometry.rs(from natural.ts + geometry.ts).netField(bodies, forces, x, y)superposition, exposed viaenv.field_at.fieldflow(extended.ts §20.3): steer velocity onto the local net field line (speed-preserving, likealign) and stream along it (does work); opt-indata-charge-gatedfollows only charged matter.Files:
engine/types.rs(Force::field,env.field_at),math/geometry.rs,forces/natural.rs+extended.rs,engine/integrator.rs(computefield_ateach frame).Acceptance: matter threads a dipole's loops / streams off a monopole; charge-gated variant leaves neutral matter free; parity count → 36 (COMPLETE); gate green.