Components
Physics Components
Rigidbody
Makes an entity a dynamic physics body that responds to forces, gravity, and collisions.
| Property | Type | Default | Description |
|---|---|---|---|
mass | Float | 1.0 | Mass in kilograms |
linear_velocity | Vec3 | {x:0, y:0, z:0} | Initial linear velocity |
angular_velocity | Vec3 | {x:0, y:0, z:0} | Initial angular velocity (radians/second per axis) |
is_kinematic | Bool | false | If true, physics doesn't move this body — scripts control it directly |
Dynamic vs Kinematic
- Dynamic (
is_kinematic: false): Affected by gravity, forces, and collisions. Use for physics-driven objects like crates, balls, ragdolls. - Kinematic (
is_kinematic: true): Moved only by scripts. Still collides with dynamic bodies. Use for moving platforms, doors, elevators.
Example: Bouncing Ball
[
{
"op": "CreatePrimitive",
"params": { "primitive_type": "Sphere", "entity_name": "Ball", "position": [0, 10, 0] }
},
{
"op": "AddComponent",
"params": {
"entity_name": "Ball",
"component_type": "Rigidbody",
"data": { "mass": 1.0 }
}
},
{
"op": "AddComponent",
"params": {
"entity_name": "Ball",
"component_type": "Collider",
"data": { "shape": "sphere", "params": { "radius": 0.5 } }
}
}
]
Scripting: Apply Forces
void OnUpdate(ScriptContext* ctx) {
// Apply upward impulse on Space
if (ctx->is_key_pressed(ctx, 32)) { // Space
float impulse[3] = {0, 10, 0};
ctx->apply_impulse(ctx, ctx->self, impulse);
}
// Read current velocity
float vel[3];
ctx->get_linear_velocity(ctx, ctx->self, vel);
}
Collider
Defines the collision shape for an entity. Required for physics interactions.
| Property | Type | Default | Description |
|---|---|---|---|
shape | Enum | box | Shape type: box, sphere, capsule, cylinder, convex_hull |
params | Nested | (see below) | Shape-specific parameters |
offset | Vec3 | {x:0, y:0, z:0} | Offset from entity center |
is_trigger | Bool | false | If true, detects overlaps without blocking movement |
layer | String | "Default" | Collision layer name for filtering |
Shape Parameters
The params object contains shape-specific fields:
| Shape | Parameters |
|---|---|
box | extents (Vec3) — Half-extents on each axis. Default: {x:0.5, y:0.5, z:0.5} |
sphere | radius (Float) — Sphere radius. Default: 0.5 |
capsule | radius (Float), height (Float) — Capsule dimensions |
cylinder | radius (Float), height (Float) — Cylinder dimensions |
convex_hull | mesh_guid (String) — GUID of mesh to generate hull from |
Convex Hull Decomposition (V-HACD)
The convex_hull shape uses V-HACD 4.1 to automatically decompose complex meshes into a set of convex hulls for efficient physics simulation. This is especially useful for AI-generated meshes from Text-to-3D:
- Decomposition runs asynchronously and is cached (content-addressed by mesh hash)
- A 50-hull quality gate prevents mesh explosion on overly complex geometry
- Results are stored in
Library/for fast retrieval after initial cooking
{
"op": "AddComponent",
"params": {
"entity_name": "GeneratedModel",
"component_type": "Collider",
"data": {
"shape": "convex_hull",
"params": { "mesh_guid": "<mesh-asset-guid>" }
}
}
}
Triggers
Trigger colliders detect overlaps without physically blocking other objects. Use them for:
- Pickup zones
- Damage areas
- Level transitions
- Detection volumes
{
"op": "AddComponent",
"params": {
"entity_name": "PickupZone",
"component_type": "Collider",
"data": {
"shape": "sphere",
"params": { "radius": 3.0 },
"is_trigger": true
}
}
}
CharacterController
A full-featured character movement controller with jumping, crouching, sprinting, coyote time, and slope handling. Uses a capsule shape internally.
| Property | Type | Default | Description |
|---|---|---|---|
capsule_radius | Float | 0.3 | Capsule collision radius |
capsule_height | Float | 1.35 | Capsule height (standing) |
move_speed | Float | 5.0 | Base movement speed (units/second) |
jump_speed | Float | 6.0 | Initial jump velocity |
max_slope_angle | Float | 50 | Maximum walkable slope in degrees |
mass | Float | 70 | Character mass in kg |
max_strength | Float | 100 | Force applied to push dynamic objects |
step_height | Float | 0.4 | Max step-up height for stairs |
stick_to_floor | Float | 0.5 | Downward force to keep grounded on slopes |
gravity | Float | 14.7 | Gravity strength |
fall_gravity_multiplier | Float | 1.5 | Extra gravity when falling (snappier feel) |
terminal_velocity | Float | 20 | Maximum fall speed |
layer | String | "Default" | Collision layer |
crouch_height | Float | 0.8 | Capsule height when crouching |
crouch_speed_multiplier | Float | 0.5 | Speed multiplier when crouching |
sprint_multiplier | Float | 1.5 | Speed multiplier when sprinting |
coyote_time | Float | 0.12 | Seconds after leaving ground where jump still works |
jump_buffer_time | Float | 0.12 | Seconds before landing where jump input is buffered |
jump_cut_multiplier | Float | 0.5 | Velocity multiplier when releasing jump early (variable-height jump) |
Scripting: First-Person Controller
void OnUpdate(ScriptContext* ctx) {
float dt = ctx->get_delta_time();
// WASD movement
float move_x = 0, move_z = 0;
if (ctx->is_key_down(ctx, 87)) move_z -= 1; // W
if (ctx->is_key_down(ctx, 83)) move_z += 1; // S
if (ctx->is_key_down(ctx, 65)) move_x -= 1; // A
if (ctx->is_key_down(ctx, 68)) move_x += 1; // D
float vel[3] = {move_x * 5.0f, 0, move_z * 5.0f};
ctx->set_character_velocity(ctx, ctx->self, vel);
// Jump
if (ctx->is_key_pressed(ctx, 32)) { // Space
ctx->character_jump(ctx, ctx->self);
}
// Sprint
ctx->set_character_sprint(ctx, ctx->self,
ctx->is_key_down(ctx, 340)); // Left Shift
// Crouch
ctx->set_character_crouch(ctx, ctx->self,
ctx->is_key_down(ctx, 341)); // Left Ctrl
}