# Skate 3 physics engine for Zero
`skate_physics` integrates a reconstructed Skate 3 physics engine into Zero. Use this package for Skate 3-style skateboard and rider physics, or use its custom rigid-body solver components independently. It exposes a reconstructed Skate 3-derived Rust solver through editable entities, components and assets: physical bodies, collision volumes, joints, constraints, motors, forces and simulation state. It is a reusable simulation system, not just a skateboarding controller or a park scene.
## Why use it?
Build and tune connected physical assemblies without first writing the integration between a custom solver and Zero. Inspect velocities and forces, change mass and inertia, configure joint limits, and drive mechanisms with spring/damper or hard motors. Motors apply impulses through the solver rather than teleporting bodies. The general body/joint/drive layer does not require a rider or animation clips.
The package connects physics authoring, fixed-step simulation and entity presentation. Use it to experiment with constrained bodies, motor-driven mechanisms and vehicle assemblies; the skateboard and rider are included applications of the system, not its definition.
## What it provides
- `World`: authority-gated fixed-step simulation and publication of solved entity state.
- `Body` and `CollisionVolume`: editable mass, inertia, forces, velocities, primitive/compound collision geometry and bounded static-mesh collision.
- `Joint` and `Drive`: body references, local frames, linear/angular limits and independently configurable motors.
- `API`: in-engine authoring helpers and an explicit-state solver interface.
- Input and actuator components for device-driven or scripted physical assemblies.
- An integrated skateboard/rider system with control maps, rig mapping, visual bindings and animation-slot overrides.
- Example scenes, a modular park, an authored skateboard, and the `GettingStarted` guide.
## Where to start
Read **GettingStarted** for the distinction between the general physics components and the specialized rider integration. The low-level **Demo** workbench illustrates bodies, joints and a vehicle assembly. **SampleScenes** exposes rider, vehicle-only, self-propelled, scripted-control and physics-tuning examples. The world's default **RiderFidelity** scene demonstrates the coupled rider/board system with Zero's avatar and the authored park.
## Integration boundaries
Static mesh collision has documented size limits; see `Body`. The specialized native rider/board integration requires a fixed body layout; that restriction is distinct from authoring assemblies with the general body/joint/drive API.
The rider demo retains converted reference animations for testing, replaceable through normal Zero assets and animation bindings. These are not required by the general motor component. The default showcase uses the authored skateboard and Zero avatar; unused reference character and board models are excluded from publication. See the component documentation for supported shapes, units and solver-specific conventions.
Original two-second balance motion authored for OriginalRiderRig; contains no retail animation samples.
Geometry design derives from the project-owned skate.rider module, asset 2901eef4-ce5a-47a5-9788-96b39a9c135d. No retail mesh or animation bank is used.
# BoneBody
Map a named bone on skin to an explicit physics body. Enable physicsPose on the
skin's AnimationSource. weight blends from animation to the simulated pose;
offset is in metres in the body's local frame, with a quaternion rotation offset.
Mappings are normal synchronized entities and replicas read the replicated body.
One active mapping per bone. This path currently requires uniform positive scale
on the skin and bone ancestry; unsupported scale is reported, not silently repaired.
# World.component
Authority-gated fixed-step driver; reads and publishes ordinary Zero entities.
Bodies, joints and drives sort by their editable `solverOrder`, then entity ID.
Existing default-zero orders retain the prior behavior. Presets can preserve
native registration order across clones instead of depending on generated IDs.
## Fixed-step publication
`maxSubsteps` (1..16, default8) bounds fixed steps per publication. Entered NativeGround `body_commands` updates can batch because each step derives fresh native observations from the preceding state. Entry, exit, observe and externally supplied Ground observations stay single-step. Animation/other external targets are sampled before the request and held through its batch; choose1 when a caller requires new external targets each step.
New live body command values apply to the next request and do not invalidate already solved motion. Changes to body state, geometry, configuration, topology or authority still reject stale work. `receivedSeconds`/`simulatedSeconds` reset with restoreState; `droppedSeconds` and `rejectedResults` remain cumulative. `lastStepCount` names the last publication's step count. `onStep` fires once per publication, and readContacts returns the final substep's contacts.
Original project mannequin converted to a normal skinned Zero mesh with vertex colors and fifteen weighted parts.
Geometry design derives from the project-owned skate.rider module, asset 2901eef4-ce5a-47a5-9788-96b39a9c135d. No retail mesh or animation bank is used.
Original fifteen-bone calibration rider rig; editable parent hierarchy and bind transforms.
Geometry design derives from the project-owned skate.rider module, asset 2901eef4-ce5a-47a5-9788-96b39a9c135d. No retail mesh or animation bank is used.
# ContactPair
Set the physics World's `contactSelection` to `authored` to use its enabled
ContactPair entities as the complete ordered list of collision candidates.
Each pair holds normal Zero references to bodyA, bodyB and world. solverOrder
sets order; entity ID breaks ties. Reversed pairs are distinct and may both be
present, as in the native character solver. Identical directed duplicates and
self-pairs are rejected. An empty authored list generates no contacts.
Collision enabled flags, static/static suppression and collisionGroup still
apply. This selects candidates only; native geometry and material handling
determine the actual contacts. Default automatic selection remains unchanged.
# TerrainQuery
An editable terrain query batch using the reconstructed engine's original
triangle traversal, manifold correction and contact-retention path.
Assign World and a static mesh Body as surface. Set memberGroup and give moving
Body components that terrainGroup value. Group zero on a Body is unassigned.
Multiple queries may address different surfaces, but duplicate body/surface
pairs are rejected. Queries run in solverOrder, then entity-ID order; members
retain Body.solverOrder. Ordinary pair traversal skips pairs covered by a query.
Padding, separation distance, edge-normal threshold, convexity tolerance and
retention settings are explicit Inspector fields. They do not move bodies or
replace physics with recorded poses. Collision-enabled and suppression-group
rules remain effective. Without a TerrainQuery the prior contact path is used.
# Native ground execution boundary
Calls the reconstructed complete `Ground::UpdateSkateboard` on existing Zero Body entities. It consumes explicit native records supplied by the controller/animation observation producer; it is not a standalone input controller. The live producer connection is still under development.
Bind a World, active BoardFeedback and the two truck Drive entities. Supply the resolved numeric profile, native history after entry, current GroundBoardInput/physical observations and truck base frames. Set `entered` only after the native entry lifecycle has completed; update is refused before that. Enable only after all records are prepared. `inputTick` must match the World tick. Ground uses one substep per observation; stale records are refused. Full ground and standalone BoardSteering cannot own the same feedback binding.
`forcesBefore` preserves any already-queued native point forces before this update appends its records. Every force uses the existing queue and native point-force consumer. Returned history, drive frames, material and linear drag publish on Zero components. No hidden body or second solver is created. Missing required wall-jump trajectory launch/update currently rejects the entire transaction; that provider remains required before this branch is usable. Never treat ordinary-ground success as proof of trajectory support.
Reset restores the explicit controller history and drive frames with the body snapshot. The producer must prepare observations for the reset tick before resuming.
## Live body observation stage
`inputSource` optionally supplies the shared native input-builder record instead of a complete `input` record. Each transaction derives current board motion, mass, wheel normal, contact flags and wheel count from its actual bodies and BoardFeedback. The original native mapping is retained: processed416 is ground-linear velocity; processed720 is angular velocity. `producedInput` exposes the generated record locally for inspection without entering the solver's retained state.
Other observations still require real providers: animation/control attributes, reckoning/pose observations, lifecycle times, pumping and geometry/state-machine results. They must be prepared for `inputTick`; a diagnostic snapshot is not a continuous controller. The live clock/pose/control producer remains unfinished.
## Native input clocks
An `inputSource.lifecycle` record supplies `captured_category`, `signed_ground_step`, and the one-tick `teleported` signal. The native input-clock owner then maintains ground duration, signed ground time, inactivity, teleport frames, spin history and crouch difference in `state.input_clocks`. It advances only in a submitted physics transaction and is restored with the normal World state snapshot. Without this optional record, externally supplied timing remains authoritative.
The category/signed-step signals and per-frame flags must come from their real state/input owners. This does not perform physical Ground entry/exit, update its separate elapsed-state timer, provide pose/geometry observations, or make a continuous controller out of a captured context.
## Exit and observation
Set `operation=exit` with current observations, an entered controller, `inputSource` (the pumping owner), and `standardWheelMaterial` containing explicit static/dynamic friction and restitution. The native exit resets steering history/pumping, clears all seven linear drags, restores wheel material and runs the original animated-velocity clamp when that branch is active. The result clears `entered` and changes `operation` to `observe`.
Observe continues current input observation/history without applying Ground forces or writing wheel materials/drive targets. A separate BoardSteering may own those drives. Exit is required before observing an entered Ground controller. Update after exit is refused until real entry completes. Physical entry and continuous state selection remain under development.
World.restoreState restores the saved drive frames and pumping state; current configuration and unrelated input-source fields remain owned by their producers.
## Explicit physical entry
Set `operation=enter`, bind the existing `hookDrive`, and supply `entrySettings`: explicit `rider_mode`, previous category/state, deck angular drag, powerslide-exit scale, landing strength/offset, and the standard wheels/trucks/deck materials. Entry uses the real source/pumping state and current bodies. `rider_mode=none` means no simulated rider; no hidden body is created. `bound` currently refuses entry until the real Zero rider owners are connected.
The shared native executor initializes physical rates/controllers, disables the actual hook drive, resets pumping/wipeout state and handles the manual/re-entry/landing-force branches. Standard collider enables and materials reach the current solve and the actual Body/CollisionVolume components. The native assembly class is retained separately from Zero's self-collision group. RestoreState restores collider flags and hook parameters and checks their topology first.
This is body-only entry support, not completed rider-bound entry or a continuous gameplay controller.
Fresh entry may use state `{}`; the kernel creates native initial history and then executes entry. Full update/exit still requires entered state.
`inputSource.body_update` opts into the original Ground begin/pumping/prediction/finish sequence for an explicitly riderless rig with `pose.observation.mode="body_com"`. Pumping settings and selected mode remain authored inputs; history is retained in `state.body_update`. Bound-rider target owners and the normal command/geometry producer are not yet connected. This option alone is not a finished playable controller.
`inputSource.kind="body_commands"` enables a fresh riderless producer. Supply native `settings`, `pose` (body_com) and `body_update` tuning. Current commands are the component's editable fields; callers need no captured input/physical record. For first entry, use state/input/physical `{}` and explicit entry settings. W/S/A/D mapping is available through InspectionSession.ground. This path is verified for live push/coast/brake/steer/reset, but sustained rest still fails validation and saved-default/installation acceptance is pending.
The riderless `body_commands` source can now include `flight` settings for native
Ground/Air selection, jump calculation, Air reckoning and the angular hook drive.
Increment `jumpSequence` once per jump; `jumpStrength` selects the configured
height response. Full rider/trajectory/trick integration remains unfinished.
# BoardFeedback
The reconstructed board post-physics phase using actual solved reports, not
speculative contact candidates. Assign a World and its seven physical parts.
Before each solve it runs the original wheel-line query against that World's
static mesh surfaces. After every body has integrated it runs native report
selection, ground-normal/contact classification, acceleration sampling and
contact-time update. Contact-dependent wheel angular drag is then written for
the next step, in the original phase order.
All history and output are in the synchronized, readable state field. Contact
counts, normal and time without contact are also visible directly. Disabling
this component stops its updates; while active it owns wheel angularDrag.
No rider, animation bank, game-disc pack or hidden WASM actor is created.
The up vector, ground-angle limit, probe length and wiping-out mode are explicit
inputs. A matching reference profile must supply matching values; 60 degrees is
an authoring default, not a claim about all game modes. Dynamic-body collisions
are still solved, but this native ground classifier consumes static-world
reports, as in the preserved runtime.
# Joint.component
Typed body references, local frames and angular/linear constraint limits.
`separateLinearFrame` enables an independent parent orientation for the three
linear constraint axes: `linearFrameBX/BY/BZ/BW` is a unit quaternion in body B's
authored frame. The angular axes still use `frameBX/BY/BZ/BW`. When disabled,
linear axes follow the angular frame, preserving existing joints. JSON callers
use optional `linear_rotation_b`; omission uses `rotation_b`. Both frames are
converted through the body's mass frame before solving.
The reconstructed character requires this distinction for all22 skeleton joints.
The private121frame reference comparison checks every consumed frame word and
the full96word constraint workspace for all2662joint states. Two unused anchor
padding lanes are excluded from frame-byte comparison (native signed zero there
does not enter the decoder); constraint workspaces still match bit-for-bit.
This verifies joint-frame representation, not complete character simulation.
## Angular modes and independent speed limits
`free` permits all angular directions selected by the joint. Native swing mode 3
is exposed as `hinge`, not `free`: it retains a constrained perpendicular axis.
`limited_hinge` preserves native swing mode 2. Stock board wheel joints explicitly
use `hinge` and retain their original speed allowances.
Angular velocity allowances are independent relative-speed limits in radians per
second. Zero is a zero-speed limit, not an unlimited value. New generic joints
default to 1,000,000 rad/s so an open angular limit does not accidentally act as
a brake. Explicitly authored values (including zero) remain authoritative.
Migration: stock-board definitions using the former `free` spelling for native
mode 3 must use `hinge`. Rebuild the provided scene after changing the kernel and
component together. Old generic joints with explicit zero velocity allowances
must be reviewed; do not overwrite intentional speed limits automatically.
## Native rider slots
A Joint beneath NativeRiderDriver.constraintsRoot may reference two rider
NativeActorPart entities from the same physicsRoot. Set world to that physicsRoot
and nativeRiderSlot to 0..21. readRiderJointDefinitions() on a ready driver returns
the current slot, endpoints, anchors and frames for authoring. Body A is the
native child and body B its parent. Preserve the separate linear frame when
copying definitions. Each slot may have one override; other slots remain native.
nativeRiderAngular defaults to native: mode-dependent normal/ragdoll angular
settings still come from the native owner. Select authored to use this Joint's
angular fields instead. nativeRiderEnabled=false suppresses that slot's rows.
Deleting the override restores the native slot. These edits survive R recovery.
Animation drives remain active and can resist contradictory anchor edits.
Mixed board/rider endpoints are explicitly unsupported by this adapter.
A copied default slot passed the full 520-frame Zero replay unchanged. A 20 mm
anchor edit produced approximately 19.1 mm in the ragdoll test; native mode
limits, authored angular values, disabling, reset and restoration were checked.
# InputControl
Select a Zero inputMap, its action name and an Actuator entity. scalar accepts
a button/number action; x/y select an axis from a vector action. deadzone removes
small values and rescales the remaining range. scale changes strength or sign.
The map defines keyboard, mouse, gamepad and touch bindings inside Zero.
Only the local control and actuator owner activates input. The World and physical body may be owned by a different peer: synchronized command state reaches that solver authority. Losing command ownership,
disabling or destroying the component releases its activation claim. Rebinding
resets the previous locally-owned actuator command; stale callbacks are ignored.
Use one InputControl per actuator. Multiple forces use separate actuators.
feed(value,pressed) exercises the same path for authored tests or synthetic input.
This component writes command state, never physics transforms or plugin internals.
# CollisionVolume
Put this component on a direct child of a Body whose shape is `compound`.
Edit the child's local position and rotation with Zero's normal transform tools.
Positive uniform scale on the body and child is included in collision dimensions;
nonuniform/mirrored scale is rejected. Shape fields define sphere, rounded-box
core, Z-axis capsule, or triangle geometry. Triangle transforms are baked into
vertices when the Body reads its state, preserving native mass conventions.
Give each child a unique integer `order`. It preserves the authored accumulation
order independently of entity IDs. `collisionEnabled=false` suppresses contacts
but retains mass. Delete a child to remove both its geometry and mass contribution.
The Body supplies material and total mass. It may have at most64 volume children.
Use `API.attachVolume(child, settings)` to attach this component and automatically
choose the next free order; the child's parent must already be a compound Body.
All properties and transforms are ordinary synchronized Zero entity data.
## Native actor bodies
CollisionVolume can also be a direct child of a NativeActorPart with role=board or role=rider.
One or more volume children replace that body's native contact geometry; parts
without volume children inherit their defaults. Removing the last child restores
the defaults. Disabled children suppress contacts; use a disabled child when the
intent is no contacts rather than inherited defaults. Child local transforms are
in the body entity's centre-of-mass frame. No host files are needed.
For native bodies, geometry editing does NOT recalculate mass or inertia: those
remain separate NativeActorPart fields. It also does not alter the animation or
wheel-probe/controller profile. Materials and controller collision gating stay
native. Rider shapes retain native mode-dependent enable flags, collision groups and
materials. A shape cannot enable a body the current native mode disables.
The ready NativeRiderDriver:readColliderDefinitions() method reads current
body-local native geometry, including disabled children, for inspection or
in-engine authoring. Spheres were checked with actual Zero physical response,
reset and restoration. Rounded boxes, capsules with offsets/rotation, and two
triangle volumes were also checked against their calculated support height.
Disabling the triangles removed their support; deleting them restored all 15
default deck children. Rider sphere authoring, disable/reset/restore and native masking have been
checked. Additional rider multi-volume/self-contact scenarios remain to verify.
The ready driver readRiderColliderDefinitions() method returns each rider body
with its current native enabled flag, volume_group, and body-local shapes.
Vehicle-only mode returns an empty rider list and rejects rider shape input.
# Drive
An editable Skate solver motor between Body A and Body B in the selected World.
Local anchors and frame quaternions describe frames the motor tries to align.
Animate either frame to drive a limb, suspension or steering assembly. The motor
applies impulses through the same solver as contacts and joints; it never teleports
the bodies. Linear and angular drives have independent disabled, soft and hard modes.
Soft mode uses spring and damping. Hard mode uses maximum correction velocity.
MaxStrength limits each solver axis; zero provides no motor force. Disabled ignores
the saved tuning values, so toggling it preserves tuning without applying impulses.
The reconstructed solver retains its original drive coefficient conventions.
All fields synchronize through Zero. No rider or animation clip is required.
Strength values retain the Rust engine's native coefficient convention. They
are not a direct force in newtons or torque in newton-metres. The solver limits
each row using `dt * dt * maxStrength * inverseEffectiveMass`; the latter is
the reciprocal of the row's inverse-mass/inertia denominator. In particular,
a small-inertia body needs a larger angular strength number to support an
offset load. Check the complete connected assembly, not just a free body.
A native regression uses a 2kg, radius-0.15m root supporting a fixed 10kg load
0.5m to its side. At 120Hz/64 iterations, angular hard strength 1000 saturates;
10000 holds the orientation. This is an explanatory test, not a universal
humanoid tuning preset. Changing collider dimensions changes inertia as well
as contacts; tune limits against the mass properties of the intended body.
# Actuator
Connect world and body, then set force/torque at full command. command is a
synchronized scalar from -1 to1; input, AI or other Zero components can write it.
For a vehicle, one actuator can apply forward thrust and another yaw torque.
Choose body space to follow the chassis orientation, or world space for fixed
directions. Set command0 to release or active=false to disable. Multiple actuators
sum in deterministic entity-id order without overwriting Body.force/torque.
Commands are sampled at each World request boundary (up to four fixed steps).
They feed the existing Skate solver and do not move transforms directly or add
a rider. Input-device bindings stay in normal Zero input components; this asset
does not assume keyboard keys, a game genre or a multiplayer transport.
# TrajectoryTarget
Samples one named bone from a normal Zero animation and calls the reconstructed
trajectory-delta operation. Edit clip, bone, previousTime, currentTime, wrapped,
loopTranslation/loopX/Y/Z/W and weight in the Inspector. Increment requestId to
request work, or call submit(previousTime,currentTime,wrapped) on the owner.
Wait for appliedRequestId before treating the request as applied; status reports
validation errors and pending reports work in flight. rebind() invalidates the
cached clip for the next unapplied request after editing clip bytes.
Output mode publishes synchronized deltaTranslation, deltaX/Y/Z/W, deltaScale
and deltaWeight. Target mode additionally advances a selected static Body in a
locally owned physics World. Connect a normal Drive from a dynamic Body to that
target. The controller, World and target must share authority. Use one pose
controller per target. The dynamic body is moved by the physics solver.
Translation uses the target's prior world rotation. Rotation maps the native
clip-parent delta through the previous clip frame into the target world frame.
Applied request IDs prevent replay after a rebind. A changed request, target,
owner, world or mode rejects an outstanding result rather than overwriting edits.
No accepted clock or root offset is hidden outside synchronized component fields.
Times must be within the clip duration. The caller explicitly selects whether
this interval wraps and supplies its authored loop transform. Submit separate
requests for multiple wraps; the native kernel applies a supplied loop transform
once. This component does not advance a playback clock automatically. It supports
riderless use and needs neither a mesh nor a skeleton entity.
# PoseTarget
Map an exact joint name on any supported Zero skinned rig to an explicit static
physics target. Set source to the animated skinned entity, bone to the joint name,
target to a static Body entity and world to its World. Connect a Drive between
your dynamic limb and that target. Drive anchors/frames provide bone-to-body offsets.
Choose collision groups to suppress target/limb collisions as appropriate.
World samples mappings before submitting a new solve. Zero's own AnimGraph,
retargeting and user clips produce the source pose; this component selects no clip
and assumes no Skate skeleton. Remove mappings and rider bodies for vehicle-only use.
The target is an ordinary owned, synchronized entity. Missing bones are explicit
errors rather than silently substituting a stock rig. Mirrored transforms are
rejected. Render-to-physics scale comes from the source joint world transform;
collider dimensions remain independently authorable.
This provides animation-to-physics targets. A complete bidirectional ragdoll visual
binding and packaged original character remain separate unfinished work.
# SkatePhysicsKernel.plugin
Stateless WASM adapter over the existing Skate Rust contact/joint/integration functions.
The low-level `step` request accepts a compound shape:
```json
{"type":"compound","children":[{"shape":{"type":"sphere","radius":0.2},"position":[1,0,0],"collision_enabled":true}],"authored_mass_frame":false}
```
Children retain their declared order and may be sphere, capsule, box or triangle.
Each has a position and optional column-major rigid `basis` (identity by default).
Triangle children provide `vertices`, `fatness`, `edge_cosines` and `volume_flags`;
bake any child transform into triangle vertices. Non-rigid or mirrored bases,
degenerate triangles and unsupported dimensions are rejected. Limits are64
children per compound and512 total collision volumes per request.
Mass includes collision-disabled children. The engine computes the native center
of mass and principal axes internally. Body position/rotation and constraint
anchors stay in the authored body frame; linear velocity describes the center
of mass and angular velocity uses world axes. `authored_mass_frame=true` is an
explicit source-owned override (the stock deck constructor uses it), not the
normal choice for a user-defined asymmetric body. It keeps aggregate inertia
while retaining the authored mass frame.
Child contacts use the existing primitive/triangle routines. Mesh contacts retain
world-face order followed by child order. Friction/restitution come from the
owning Body. No implicit rider is created.
Compound input is available through kernel/API.solve and Body.shape="compound"
with editable CollisionVolume child entities. The complete board preset and
remaining package acceptance gates are still under integration.
## Trajectory delta
`await(API.trajectoryDelta(request))` calls the reconstructed animation kernel.
The request contains `previous` and `current` poses with `translation` (xyz),
`rotation` (xyzw), `scale` (xyz), and `weight`. Pose defaults are zero translation,
identity rotation, unit scale and weight1. Supply optional `loop_transform` with
explicit rotation and translation when a wrap requires the authored transform.
The result has the same pose fields. It retains current scale/weight and computes
translation in the previous pose's rotation frame. Quaternion lanes follow the
native operation without additional normalization. Nonfinite inputs/results fail.
The loop transform is applied once when supplied. It is not raised to a loop
count; callers retain the playback clock and wrap policy as normal Zero state.
This operation returns data and never changes an entity, input or ownership.
`step_batch({steps,state})` performs1..16 native fixed steps and returns the final state. Multiple Ground steps require entered live body_commands updates; lifecycle transitions and external observation records are rejected for multi-step batches. No host-visible state is published from a failed batch.
# Body.component
Editable collider, mass, forces and complete velocity state on an ordinary Zero entity.
For static mesh collision, select shape=mesh, enable isStatic and assign a normal
Zero mesh asset to mesh. meshScale sets the positive local collision scale;
entity position/rotation place it in the world. Primitive sizes remain explicit.
Changes to stored mesh geometry refresh collision automatically. No CPU-resident
render copy or host files are required. Use the same mesh and corresponding
scale for the visual Model when matching rendered and collision geometry.
Meshes currently support up to8192 vertices/4096 triangles, static only; triangle
winding determines the front face. Large-terrain acceleration remains unfinished.
`collisionEnabled` defaults to true. Disable it for an explicit animation/motor
target or other noncolliding body. Mass, integration, joints and drives continue
to work; only contact generation is disabled. This differs from collisionGroup,
which suppresses pairs sharing the same nonzero group. The WASM state field is
`collision_enabled`; omitted means true for existing saved states.
For `shape="box"`, `halfExtents` describes the unrounded core and `rounding`
adds the radius outside that core. An axis's total outer size is
`2 * (halfExtents[axis] + rounding)`. The rounding radius may exceed the core's
half-height (as it does for the stock deck). Core extents must be nonnegative,
and every outer extent must be positive. These are the reconstructed engine's
rounded-box conventions; rounding does not subtract from the entered core.
For `shape="compound"`, add CollisionVolume components to direct child entities.
Their local transforms and shape fields supply the ordered collision volumes;
use unique integer orders. The Body's mass is the total compound mass. Changing
child transforms or dimensions updates the submitted shape, and collision-disabled
children retain their contribution to mass. Positive uniform body/child scales
are supported. Position/rotation remain in the authored body frame while linear
velocity describes its center of mass. Leave `authoredMassFrame=false` for normal
compounds; true is an explicit source-specific override used by the stock deck.
`maximumLinearVelocity` and `maximumAngularVelocity` pass the native speed caps
through to integration. Defaults remain1000000 for existing bodies; stock board
construction carries its native unbounded/ wheel-specific values. Caps must be
finite and nonnegative. `solverOrder` controls registration order within the World;
entity ID breaks ties. Give assembly parts distinct orders when matching a source
construction sequence. The same ordering field exists on Joint and Drive.
Enable `customMassProperties` to supply `inverseMass`, principal `inverseInertia`,
and `rotationalEnergyCoefficient` explicitly. These replace inferred mass/inertia
while retaining the selected collision geometry. All must be finite and positive;
`isStatic` still suppresses inverse mass and inertia in the solver. With the switch
off, existing geometry-derived behaviour remains unchanged.
`massFramePosition` and `massFrameX/Y/Z/W` describe the authored body frame in
center-of-mass coordinates, using a unit quaternion. Entity transforms, collision
geometry and Joint/Drive anchors remain in authored coordinates; linear velocity
is the center-of-mass velocity. The kernel converts input/output poses and
constraint frames consistently. This supports the reconstructed skeleton's
independently adjusted inertia rather than forcing it into primitive estimates.
The JSON field is `mass_properties: {inverse_mass, inverse_inertia, spherical,
frame_position, frame_rotation}`; omission preserves old behaviour. This is a
body capability, not a completed native character preset or animation controller.
Native ground probes now include static boxes with positive half-extents. Rounding uses the original query fatness path. Solid box contacts remain native primitive-pair contacts, so a box does not need a TerrainQuery component; that component is for static triangle meshes. The visible Model and collision definition are independent. This does not add probe support for degenerate rounded boxes, static spheres or capsules.
# API.module
In-engine authoring helpers for attaching World, Body and Joint, plus a direct explicit-state solver call.
`attachBoneBody(target, skin, body, settings)` and
`attachPoseTarget(target, world, source, body, settings)` expose the two directions
of rig binding. References are assigned through normal component setters so Zero
can replicate them. These are the same components the Avatar physical-rig helper
assembles; users can author, inspect, or replace them individually.
`attachVolume(child, settings)` adds a CollisionVolume to a direct child of a
compound Body, chooses the next free order when omitted, and marks the child
entity synchronized. Create the parent with `attachBody(parent, world,
{shape="compound", mass=...})`, then author its volume children inside Zero.
`attachBoardSteering(target, world, feedback, frontDrive, backDrive, settings)` binds the native steering component to explicit existing entities. Steering owns the two Drive frame targets while active; it creates no bodies. Its readable profile/history live inside Zero. It is not the complete ground controller.
`attachNativeGround(target, world, feedback, frontDrive, backDrive, settings)` binds the native ground execution boundary. It is inactive until complete native records and entry state are supplied. It is not the unfinished live input producer.
# Physics pose node
AnimGraph overlay for BoneBody mappings. Reuses Zero rigmath and the existing graph sink; owns no physics or network state.
# AnimationSource
Attach to a skinned mesh entity and choose a normal Zero animation asset.
Direct binding matches exact bone names and requires every target bone to have
a clip channel. Retarget binding uses Zero's rig profiles and optional sourceRig.
It reports matched/total bones and refuses zero coverage. Use one pose-writing
animation component per skinned body; remove competing ClipPlayer/AnimGraph owners.
The owned entity advances synchronized playhead; replicas sample that same state.
playing, looping, speed and playhead are ordinary editable fields. Pausing playing
holds the current pose. Clip/rig/binding or skeleton definition changes rebuild
the graph; rebind() also rebuilds after an asset's content is edited in place.
PoseTarget reads the resulting animated joints for physical Drive targets.
No default character, stock animation or rider body is instantiated.