Gravity zones
Usage guide of world.gravity_zones: small planets, oriented fields and zero-G volumes; the zones config, priority and blending, the sample and step services, attaching Rapier bodies, the request hook, events and engines.
Local gravity in your world (world.gravity_zones) #
Small planets, fields with a fixed direction and zero-gravity rooms, with deterministic priorities. Readable offline: gripforge docs world-gravity-zones, or the MCP tool gripforge_docs (topic world-gravity-zones).
What it is for #
The kit answers one question: what is the gravity at this point? A zone is a sphere or an oriented box with a mode (radial toward a centre, directional along a world-space vector, or zero). The kit returns the acceleration, the local "up", and the winning zone. It can also advance a body (velocity and rotation) and, on the Rapier physics port, keep attached dynamic bodies under the local gravity and aligned to the local up. It never moves a collider: the engine keeps collisions and character control. The same Rust core is shipped as a C library (libgfgravity) and WebAssembly for engines that call sample and step themselves.
Turn it on #
{ "id": "world.gravity_zones",
"config": { "defaultGravity": [0, 0, 0],
"zones": [{ "id": "planet", "mode": "radial", "center": [0, 0, 0], "radius": 30, "strength": 8 }] } }
First example #
<!-- test: kits/game_engine/host/tests/world_gravity_zones.rs::service_and_save_restore_share_the_library_model --> With the zone above, a point 10 m over the centre falls toward it, a zero-G room can be added at run time, and a save and reload bring it back.
{ "op": "call", "service": "world.gravity_zones", "method": "sample", "args": [[0, 10, 0]] }
{ "op": "call", "service": "world.gravity_zones", "method": "setZone",
"args": [{ "id": "room", "mode": "zero", "center": [0, 10, 0], "radius": 3, "priority": 5 }] }
The first answer has gravity equal to [0, -8, 0]; after setZone, sample at the same point answers zeroG true and the zone room. After removeZone, the zone is planet again.
Settings and defaults #
| Setting | Type | Default | Meaning |
|---|---|---|---|
defaultGravity | vector, m/s² | [0, -9.81, 0] | acceleration outside every zone; use [0, 0, 0] for space |
zones | list, at most 256 | [] | the gravity fields |
A zone:
| Key | Default | Meaning |
|---|---|---|
id | required | unique name (1 to 128 characters); a duplicate is refused |
mode | required | radial, directional or zero |
center | required | [x, y, z] in metres |
shape | sphere | sphere or box |
radius | 10 | sphere radius, metres |
halfExtents | required for a box | positive half sizes, metres |
rotation | identity | box orientation as a quaternion [x, y, z, w]; it does not rotate a directional gravity |
direction | required for directional | non-zero world-space vector, normalised by the kit |
strength | 9.81 | acceleration in m/s²; a radial field is constant, not inverse-square |
priority | 0 | higher wins; on a tie the greater id (UTF-8 order) wins, whatever the insertion order |
blendDistance | 0 | width in metres of the inner edge that blends over lower-priority fields; 0 is a hard edge |
enabled | true | a disabled zone is ignored |
An invalid config is reported by the project validation and, at start, logged as an error; the kit then falls back to zero gravity.
Services, events, hooks #
world.gravity_zones(service):sample(position)answersgravity,up(a zero vector in zero-G),zone(an id or null) andzeroG.step(body)answers the velocity and rotation afterdt. The body holdsposition,velocity, optionalrotation(quaternion) andalignRate;dtmust be within 0 to 1 second andalignRatewithin 0 to 10000 radians per second.config()is a snapshot;configure(config)replaces the fields atomically.configure({ preset: "<id>", ... })takes the config of a document ofworld_gravity_zones_presetsand applies your own keys over it.setZone(zone)inserts or replaces a zone;removeZone(id)answers whether it existed.attach(entity, options)anddetach(entity): Rapier physics only, on an existing dynamic body.options.nativeGravity(default[0, -9.81, 0]) is the gravity the engine already applies, which the kit compensates;options.alignRate(default 6) is how fast the body turns its up toward the local up, in radians per second.
gravity.changed(event): an attached body changed its winning zone. Payload:entity,from,to(zone ids or null for the default field),gravity,up.world.gravity_zones.changed(event): a decided method succeeded. Payload:op,result.world.gravity_zones.refused(event): a hook cancelled a decided method. Payload:op,by,reason.world.gravity_zones.request(hook): asked before each decided method (setZone,removeZone,configure,attach,detach) with{ op, args }. A tap may changeargsor cancel; the call then answers{ ok: false, cancelled: true, by, reason }.world_gravity_zones_attached(condition): true when the entity is attached.world_gravity_zones_request(verb): runs a decided method from a script, withopandargs.
{ "world_gravity_zones_attached": "player" }
Modding #
A mod can change both settings, add documents to world_gravity_zones_presets (named gravity fields) and tap the request hook.
Saves #
The save keeps the zones and the attached bodies with their last winning zone.
Engines #
The rules are the same Rust core everywhere. In the Rust kit host, attach works on the Rapier port only. Other engines call sample and step through libgfgravity and disable their own body gravity before applying the result; they keep their collisions. There is no presenter.
When it does not do what you expect #
attachfails with "requires the Rapier physics port": the engine uses another physics; callsampleandstepyourself.attachfails with "requires an existing dynamic rigid body": the entity has no body yet.- A config is refused: a duplicate zone id, more than 256 zones, a zero
direction, a missinghalfExtentsfor a box, or an unknown key. - Two zones overlap and the wrong one wins: raise the
priorityof the one you want, or add ablendDistance. - A body falls twice as hard: set
nativeGravityinattachto what the engine applies.
Limits #
Constant-strength fields, no orbital (inverse-square) gravity. No collision and no locomotion: the engine owns them.
Versions #
Kit 1.1.0 (service contract 1.1.0). The request hook, presets and script verbs since 1.1.0; the Rust core, C library and WebAssembly wrapper since 1.0.0.