# Magnetic attraction and repulsion in your game (world.magnetism) ## What it is for `world.magnetism` computes forces between gameplay objects: opposite poles attract, equal poles repel, and neutral susceptible metal is pulled toward either pole. It is a simplified gameplay model, not an electromagnetic simulation. The kit only returns forces in newtons. It never moves a body, adds gravity or creates a second physics world: your engine applies each force once per fixed physics step and keeps mass, damping and collisions. ## Turn it on ```text gripforge_gamekit_install { project_id: "gkp_…", id: "world.magnetism" } gripforge_gamekit_configure { project_id: "gkp_…", id: "world.magnetism", config: { "coupling": 100, "maxForce": 1000 } } ``` The kit has no requirement. Its default instance is created from the installed settings; `create(id, config)` adds up to 128 named instances, each a complete magnetic world. ## First example Two bodies are registered with opposite poles, sampled once, and the returned forces are applied by the engine. Nothing moves until the engine applies them; they then approach each other. ```json { "op": "register", "id": "a", "properties": { "polarity": 1 } } { "op": "register", "id": "b", "properties": { "polarity": -1 } } { "op": "sample", "bodies": [ { "id": "a", "position": [-2, 0, 0] }, { "id": "b", "position": [2, 0, 0] } ] } ``` Each command is sent with the service call `request("default", command)`. The sample answers `{ forces: [{ id, force }], pairs }`, sorted by id, with `force` as a vector in newtons. ## Settings and defaults | Setting | Type | Default | Meaning | |---|---|---|---| | `coupling` | number | `100` | Force coefficient, 0 to 1e6. | | `softening` | number | `0.25` | Distance softening in metres, 0.001 to 1e6. | | `maxForce` | number | `1000` | Force budget per pair and per object, in newtons, 0.001 to 1e6. | | `maxBodies` | integer | `128` | Maximum registered objects per instance, 1 to 256. | Settings are fixed once an instance exists. Unknown fields and out-of-range values are rejected without changing state. ## Services, commands and properties Service `world.magnetism`: - `create(id, config)`: a new instance; duplicate ids are rejected. - `request(id, command)`: runs a command. - `remove(id)`: drops an instance and its forces; returns whether it existed. - `ids()`: the instance ids. Commands: `register {id, properties?}`, `set {id, properties}`, `remove {id}`, `clear`, `sample {bodies}`, `status`, `config`, `save`, `load {save}`, `preview {command}`. A `sample` must list every registered object exactly once, including disabled ones; a missing, unknown or duplicate id rejects the whole sample. `preview` evaluates a command on a copy, and previews cannot be nested. | Property | Default | Meaning | |---|---|---| | `polarity` | `0` | `-1` or `1` for a pole, `0` for neutral material. | | `strength` | `1` | Pole strength, 0 to 1e6. | | `susceptibility` | `1` | Response of neutral metal, 0 to 1e6. Use 0 for nonmetal. | | `radius` | `10` | Pole range in metres. | | `enabled` | `true` | When false, the object neither emits nor responds. | | `group` | `1` | Category bitset (non-zero 32-bit). | | `mask` | `4294967295` | Categories it accepts; both bodies must accept each other. | Two neutral bodies do not interact. Beyond the range the force is zero. Each pair is capped at `maxForce`, and the total per object is kept under the same budget while preserving equal and opposite pair forces. ## Events, hooks and modding - world.magnetism.created (event): an instance was created. - world.magnetism.removed (event): an instance was removed. - world.magnetism.changed (event): a decided command ran; carries the instance, the `op` and its result. - world.magnetism.refused (event): a hook cancelled a command; carries the `op`, who refused and why. - `world.magnetism.create` (hook): asked before an instance is created; a mod may change the config or refuse it. - `world.magnetism.request` (hook): asked before a decided command applies; a mod may change the command or cancel it. Reads (`status`, `config`, `save`, `preview`, `load`) and fixed-step commands are not decisions and skip the request hook. A config may name a preset from the presets registry, merged under the config keys. ## Saves `save` returns a document of schema `gripforge.magnetism/1` with the configuration and the properties of every object. `load` is atomic and requires the same configuration. Positions, velocities and masses stay in the engine: restore them together with the magnetic save, then sample again. No cached force is replayed. ## When it does not do what you expect - Nothing moves: the kit returns forces only; apply each vector once as a force before the physics step. - A sample is rejected: it lists a missing, unknown or duplicate object, or one with a non-finite position. - A body is never attracted: its `mask`, `group` or `enabled` excludes it, or two neutral bodies are paired. - A force looks weaker than expected: the per-object budget `maxForce` scaled it down. ## Limits No occlusion, torque, rotation alignment or material detection: your game sets the properties. Forces pass through walls; collisions stay with the engine. Work grows with the square of the object count, bounded by 256 objects. ## Versions Kit 1.1.0 adds the hooks, presets, events and script verbs. 1.0.0 introduced the force model and saves.