A world never writes the physics of standing, falling or bumping. It says what each part is to the engines, and the engines enforce it: this part is solid (a walker cannot pass it); this one is a body (physics owns where it is once struck); this one is a platform (it carries whoever stands on it); a seat; an area that senses who comes in; a gate that moves whoever crosses it somewhere else. Each is written as a vocabulary function naming the part. The rules that act on them (walking, carrying, sitting, crossing in step with prediction) are built-in rules of the browser and server, the same in every world; the world states only their numbers and places.

Words used on this page:

Solid
A part's shape for physics: simpler than its drawn mesh, often a box, a cylinder or a convex hull (the tightest shrink-wrapped convex skin round points).
Rigid body
A part physics moves as one piece: it falls, tumbles, is pushed, and sleeps (stops being stepped) when still.
Kinematic
Moved by the script, not by forces, but pushing what it meets: the balloon's basket.
Collision layer
A named set of bodies, and which sets each collides with.
Prediction
A visitor's browser moving its own walker ahead of the server's word, so walking feels immediate; it must reach the same answer the server does.

How you write it

enum layer { props }                                           // the world's own layers; the engine provides ground and solids
collisionLayers(layer)                                         // the engine gives each name its bit
collisionLayer(props, meets: [ground, solids, props])          // not beings, not ragdolls

enum propMode { atHome, live, gliding }

part prop                                                      // the design a pin and the ball each copy: state and rules
  field play : propMode = atHome, mutable: true, lives: server // own: each prop its own
  field glide: ?handle = None, mutable: true, lives: server
  on(struck(self), { if play == atHome { set(play, live); } })      // knocked, by the ball or by another pin
  on(ended(glide), { if play == gliding { set(play, atHome); } })   // home, and asleep

part ninepin: prop                                             // the amphora reused as a bowling pin: a design
  field rings: List[(meters, meters)] = [(0.13, 0.02), (0.195, 0.2), (0.2985, 0.4), (0.334, 0.6), (0.3368, 0.71),
    (0.3338, 0.8), (0.2994, 0.9), (0.19, 1.0), (0.15, 1.1), (0.2, 1.25), (0.21, 1.36)]   // a fixed field: worked out once, at build
  part shape: amphora                                          // the drawn jar is a child; the prop is the body
  body(self, mass: 3 kg, layer: props, material: wood,
       damping: rate(0.02, per: sim(1 s)), spinDamping: rate(0.1, per: sim(1 s)))
  solid(self, hull(rings: rings, sides: 8, tip: (0, 1.45)))    // the hull reads the fixed field, in the amphora's own units

part ball: prop,                                               // the other prop: the same state and rules
           at: (-9, land.height((-9, 0, 342)) + 0.5 m, 342), rotation: rotation(0.6 rad),
           home: bowlingPins.laneHead
  part shape: sphere(radius: 0.5 m), material: materials.checkeredOrange
  body(self, mass: 25 kg, layer: props, material: wood,
       damping: rate(0.35, per: sim(1 s)), spinDamping: rate(0.35, per: sim(1 s)), continuous: true)   // grass slows it
  solid(self, derived)                                         // the sphere is its own solid
part materials
  part checkeredOrange: [plain(white), paintedBy(painted(size: (64 texels, 64 texels), colorAt: checksAt))]
fn checksAt(uv: (number, number)) color {                     // two squares by two over the ball's texture coordinates
  let orange = srgb(240, 150, 30);
  if (floor(uv.0 * 2) + floor(uv.1 * 2)) % 2 == 0 { orange } else { mix(black, orange, 0.25, in: srgb) }
}

part rock      ... solid(self, derived(uprightCylinder))             // radius 0.55 times its size (0.45 for a stone in the bed)
part maple     ... solid(self, derived(trunkAt(1 m), upTo: 40 m, below: 6 m))   // from 6 m under its foot to 40 m over it
part cottage   ... solid(self, boxes(walls, wing, chimney), walkable(deck, steps))
part labRoom   ... solid(self, from(construction))
part fern      ... solid(self, none)

part balloon
  part envelope: ...                                           // 9 m a unit
    part basket: scale(wickerBasket(), by: meterUnit), material: paints.wicker   // scaled with the envelope; meterUnit is a meter in its units, 1/9
      platform(self, floor: -5.46 m * meterUnit, standOn: box(x: -0.95 m * meterUnit ..= 0.95 m * meterUnit, z: -0.95 m * meterUnit ..= 1.02 m * meterUnit),
               walls: 1.1 m * meterUnit, on: [left, right, back])
      area(self, box(x: -0.95 m * meterUnit ..= 0.95 m * meterUnit, y: -5.56 m * meterUnit ..= -3.56 m * meterUnit, z: -0.95 m * meterUnit ..= 1.02 m * meterUnit))

part pathLantern
  part post: stake(), material: materials.lanternBlack
    area(self, sphere(radius: 4 m, at: (0, 0.2, 0)))
  derive(near, occupied(post, by: me))

part rockingChair
  part frame: chair(), material: materials.chairWood
  seat(frame, at: (0, 0.45, 0.03), facing: forward, height: 0.45 m, rocks: 0.09 rad, period: sim(3.2 s))

part cottage
  part house: ...                                              // the cottage's walls: one closed block
  part pane  : viewSurface(...)
  part wayIn: gate(across: pane, shift: link, when: open)
  derive(house.solid, { if open { difference(house.shape, notch(at: pane, wide: 1.1 m, deep: 1 m)) }
                        else { house.shape } })

body, solid, seat, gate, area and platform are the notation's vocabulary functions for "things a part is": each is a call in the part's body that names the part (collisionLayer names a layer instead); whether they are declared on the part instead is open (Areas, Platforms). A sphere carries a sphere's natural texture coordinates (round it, and from pole to pole), so checksAt, two squares by two over them, paints the ball in four checks (Shape tools: primitives). The ball's sphere(radius: 0.5 m) and the post's area(self, sphere(radius: 4 m, ...)) hold the same call: the first is drawn as a surface, the second, as the volume argument of area, is read as the space within (Shape tools: primitives as volumes).

A body and its solid

body(p: part, mass: kg, layer: name, material: standard | wood | ice | rubber | steel | bouncy = standard,
     damping: rate = rate(0, per: sim(1 s)), spinDamping: rate = rate(0, per: sim(1 s)), continuous: bool = false)

Acting on physics: bowling on the lawn

Ten pins stand in a triangle of four rows on the lawn behind the cottage, the apex toward the head of an 11 m lane that runs west. A visitor presses B and the ball is rolled from just ahead of their feet toward where they look. Each pin it knocks, or that a falling pin knocks, wakes and is live; pins nothing touched stay as they stand. When every live prop has been still for 0.8 s they are all put to sleep together; when every live prop has been asleep for 5 s, each live prop rises and glides home in 1.4 s, and is a sleeping body there again.

part bowlingPins                                               // a frameless holder: the rack, the lane, the ten pins
  field rack      : place = (-36, 0, 298), common: true        // the apex pin's spot on the land's plan
  field rackRow   : meters = 0.72 m, common: true              // between rows, and between pins in a row
  field lane      : direction = rotation(90 deg, about: up) * back, common: true   // head to apex: a quarter turn from north
  field laneLength: meters = 11 m, common: true                // from the lane's head to the apex
  field laneHead  : place = onGround(rack - lane * laneLength) + (0, 0.5 m, 0), common: true   // the ball's home: its center
  fn onGround(p: place) place { (p.x, land.height(p), p.z) }
  fn pinSpot(k: count) place {                                 // the apex first, then rows of two, three and four
    var row: count = 0;
    var first: count = 0;                                      // the number of the row's first pin
    while first + row + 1 <= k { first += row + 1; row += 1; }
    let right = rotation(-90 deg, about: up) * lane;            // the lane's right
    onGround(rack + lane * (row * rackRow) + right * ((k - first - row / 2) * rackRow))
  }
  each k in 0 ..< 10 {
    part pin[k]: ninepin, at: pinSpot(k), scale: 0.6           // 0.89 m tall, 0.4 m across the belly
  }

action(bowl, to: ray, suggestKey: "B", offered: v.standing && v.active)   // a world's own action: it carries the eye's ray

part playground                                                // the rules over every prop
  fn allProps() List[prop] { List[prop]() <- ball, each copiesOf(ninepin) }
  field allStill: bool = false
  derive(allStill, {                                           // every live body asleep or nearly still
    var still = true;
    each p in allProps() {
      if p.play == live && !p.asleep && p.speed + 0.3 m * p.spin >= 0.45 m/s { still = false; }
    }
    still
  })
  on(held(allStill, for: sim(0.8 s)), {                        // all put to sleep together
    each p in allProps() { if p.play == live { sleep(p); } }
  })
  field quiet: bool = false
  derive(quiet, {                                              // something has moved, and all of it is asleep
    var anyLive = false;
    var allAsleep = true;
    each p in allProps() {
      if p.play == live { anyLive = true; if !p.asleep { allAsleep = false; } }
    }
    anyLive && allAsleep
  })
  on(held(quiet, for: sim(5 s)), {                             // five quiet seconds: each moved prop glides home
    each p in allProps() {
      if p.play == live {
        set(p.play, gliding);
        set(p.glide, start(transition(p.pose, to: p.home, over: sim(1.4 s), ease: smoothstep,
                                      lift: fn(s: fraction) meters { 0.7 m * sin(180 deg * s) })));
      }
    }
  })
  on(action(bowl, to: r, by: v), {                             // B: bowl the ball where the visitor looks
    set(ball.play, live);
    throw(ball, from: v.feet, aim: r, reach: 60 m, missedAt: 30 m, ahead: 1 m, flat: true,
          speed: 13 m/s, rolling: true, otherwise: bowlingPins.lane);
  })

All of it is the server's: props run only on the server, and every machine is told where they are (Bodies).

What it means

Solids: the collision facet

The shape a part has for physics is one of its products (Construction). There are four practices for it:

PracticeExample
Derived from what the part already saysa rock: an upright cylinder of radius 0.55 times its size (0.45 for a stone in the bed), as high as its mesh stands less the 0.2 m it is sunk, times its size; a tree: a cylinder the trunk's width at 1 m up, from 6 m under its foot (below: 6 m) to 40 m over it, worked out from the same numbers that grow the tree
By hand, from shared numbersa cottage: boxes for the walls, the deck and steps with tops a walker stands on; a bridge's crest, ramps and parapets
From the constructiona labyrinth: the same plan run with meshes turned off, so a server needs no meshes
Noneferns, flowers, edging stones, posts, pots: not solid, by omission

Derived solids cannot drift from what they stand for; a hand copy can (a pin's hull typed out from an amphora's outline). If solids are derived by default, the content must be able to say none for a fern and walkable for a deck. Fixed solids are upright prisms: a circle, a box or a ramp between a bottom and a top; a top within a step of a walker's feet is something to step onto, a higher one a wall. They are built on the server, the truth, and again in each browser from the same numbers, so a predicted walk meets the same walls.

The land

The land is handed to physics whole, as a heightfield. A land part is solid on the ground layer with no call: nothing in the content makes it solid, and what a walker or a prop stands on is what is drawn, to within 1 mm, which is the engine's guarantee (Terrain: height is a method of the land). The land's edge: says what happens at its border; the island's, sea(wade: 0.6 m), lets a walker go no deeper than 0.6 m under the sea, sliding along the shore (Terrain: edges).

Bodies: who owns the place

One declaration changes who owns a part's pose, its place and its rotation. Before it, the content places the part; after it, the content places it only at the start, and once struck, physics owns where it is and how it lies. A body starts asleep where it is placed. Its home is unchanged: by default its defined place, which a reset brings it back to (Frames: a part's home).

An animator on a body's pose takes the body out of the physics world for as long as the animator drives it: it is moved by the animator alone, passes through whatever it meets, and pushes nothing, so a pin gliding home cannot knock down one still standing. When the animator ends, or is stopped, the body is made again where the animator left it, with no speed, asleep. A throw takes a body back from an animator the same way, at once.

Physics output on a body is everyone's by its nature: once any prop has moved, every prop's place is in every snapshot the server sends. Props run only on the server; no browser predicts them.

Reading a body

WrittenTypeWhat it is
p.speedmeters a secondhow fast the body moves, any way; 0 asleep
p.spinradians a secondhow fast it turns, about any axis; a radian is a plain number, so 0.3 m * p.spin is a speed
p.asleepboolwhether it is asleep: still and not stepped
p.pose, p.place, p.rotationpose, place, rotationwhere it is and how it lies now (Values: rotations and poses)
p.homeposewhere a reset brings it (Frames: a part's home)

Two actions put a body to sleep and wake it: sleep(p) stops it where it is, and with it every body resting on it or touching it; wake(p) wakes it and every body asleep with it. Each is an act, written in an acting block (Actions: bodies).

A body's events

World logic holds only values and ids and never reaches into an engine, so what happens to a body arrives as a message. Two are told, with the rigid-body package's own thresholds:

Reporting every contact between bodies already awake would flood the world, so it is not told; which further contacts are worth a message is open. The other physical event the world is told of is a hard landing, a fall of 2.5 m or more (hardLanding(b, speed:, cost:), Events).

Throwing a body

throw(p, from: place, aim: place or ray, speed: m/s, reach: meters, missedAt: meters,
      ahead: meters = 0 m, flat: bool = false, rolling: bool = false, otherwise: direction)
  1. The aim. A place is aimed at as it is. A ray (the eye's, as an action carries it, Visitors: declaring an action) is aimed where it first meets the ground or a solid within reach; props do not stop it. If it meets nothing, the aim is the point missedAt along it.
  2. The way. From from toward the aim. With flat, the aim's height is dropped, so the throw is level along the ground; if the aim is then within a millimeter of from, the way is otherwise.
  3. The start. The body is taken from whatever had it (rolling, gliding home, or at rest) and placed ahead along the way from from. With flat it rests on the ground there with 5 cm to spare: its lowest point 5 cm over the land.
  4. The motion. It is set moving at speed along the way, awake; with rolling, spinning as it would roll without slipping (its spin the speed over its radius, about the level line across the way).

The bowl is throw(ball, from: v.feet, aim: r, reach: 60 m, missedAt: 30 m, ahead: 1 m, flat: true, speed: 13 m/s, rolling: true, otherwise: bowlingPins.lane): from 1 m ahead of the feet, 5 cm over the grass, at 13 m/s, rolling. The body's mass, material, damping and continuous are its own, from its body(...). throw is an action (Actions: bodies); the same word in Cone returns an error, a clash listed on Actions.

Collision layers

Which things collide with which is a content decision about how the world behaves: the pins must be knocked down by the ball and not by a person walking past. The engine provides two layers, ground (the land) and solids (everything else that stands still or is carried: the cottage, trunks, rocks, a platform's floor); falling figures have a layer of the engine's own, which content does not name. A world names its own layers in an enum and gives it to collisionLayers(...), as layer above does with props, and the engine assigns the bits. The names and the "meets" list are content; the bit numbers are mechanism. The rigid-body package's filter is two-way: each body's layers must be in the other's mask. A walking character collides with the ground and the world's solids and never with a ragdoll or another character.

A clear line. clearLine(from: place, to: place, layers: [ground, solids], stopShort: meters = 0 m) returns a bool: true when a straight line from one place to the other meets nothing of the named layers before it ends, the end drawn back by stopShort. Beings and props do not stop it. The spells ask clearLine(from: eye, to: t.chest, layers: [ground, solids], stopShort: 0.3 m): the line from the caster's eye to the target's chest, stopping 0.3 m short of it.

Platforms: carrying

A platform is a part a being can stand on and be carried by: a balloon's basket under its envelope, a lift's car, a raft. It is a floor in the part's frame with optional walls on its four sides, written as a call in the part's body that names the part:

platform(p: part, floor: meters, standOn: shape, walls: meters = 0 m, on: List[side] = [])

platform(self, floor: -5.46 m, standOn: box(x: -0.95 ..= 0.95, z: -0.95 ..= 1.02),
         walls: 1.1 m, on: [left, right, back])                // the balloon's basket

Its numbers are in the part's own units, so a basket scaled with its envelope has them in the envelope's units, each meter number times a ninth for the balloon's (Frames: a turn and a scale). Carrying is a built-in rule, the same for every platform: each frame, after the placements are composed, the scene works out how each platform moved and carries each body on it by that move: its feet, heading, planted feet and, for the player's own, the camera. A rider standing still is kept in the floor's own frame, so a ride far from the world's center does not drift by rounding. One who walks off the open side falls, keeping the floor's speed (the horizontal speed the floor had, and its rise or fall). An animator that moves a part's place moves everything under it, platforms, areas and their physics bodies with it (Animators: along a curve). Carrying runs on the server and in each player's browser for its own body. A floor tilted by its part is not supported. A platform is a kinematic body in the physics world.

Seats: sitting

A seat is data on a part: a sit point, a facing, a height above the floor the sitter's feet stand on, an optional rocking. Any part can be a seat: a rocking chair, a throne (0.65 m, facing east), a bridge's parapet (0.69 m, facing west). Sitting is a built-in rule answering the sit action: the being walks to the nearest free seat whose standing place is within 2.8 m across the ground and within a step up or 0.75 m down, turns, and sits with the library's 1.7 s movement; a jump, asking again, or not arriving in 7 s gives up. A chair rocks about 5 degrees each way every 3.2 s while sat in, a sine of the clock each view works out alike. Seats are not sent; the server sends who sits where.

Areas: sensing

One form. An area is a space in a part's frame, moving with it. It is written as a call in the part's body that names the part, and is registered once, when the part is made:

area(p: part, volume: shape)

part post: stake(), material: materials.lanternBlack
  area(self, sphere(radius: 4 m, at: (0, 0.2, 0)))
part entry, at: (...)
  area(self, sphere(radius: 1.2 m))

The space is written with the same sphere, box and cylinder calls a shape uses, read as the space inside them (Shape tools: primitives as volumes). A part has at most one area, so the area is named by its part: rules read it through the part's own name. An area may be unbounded upward or downward: cylinder(radius: 15 m, above: y) reaches from height y without end, and below: y does the same downward. Left without a radius:, such a cylinder covers the whole plan. The labyrinth's underground is area(self, cylinder(below: -150 m)): everything below y = -150 m, anywhere. The test is the height of the being's feet (or of the ear, for a sound).

WrittenMeaning
occupied(post)a bool: true while any being is inside post's area
occupied(post, by: me)true while this machine's visitor is inside: the being the person at this machine drives. On each visitor's machine it has its own value; a field defined from it has lives: client (Fields)
occupied(post, by: visitors)true while any being driven by a visitor is inside: a villager or a guard does not count. by: takes me, visitors, or a part, a being or a place, which is tested by its height and position (occupied(underground, by: ear), occupied(underground, by: v))
entered(post), left(post)triggers: a being came in, went out; by: v names it (Events)
part pathLantern: lanternHead
  field near: bool = false, lives: client                 // each visitor's own, derived (so not mutable): their own lantern brightens
  part post: stake(), material: materials.lanternBlack
    area(self, sphere(radius: 4 m, at: (0, 0.2, 0)))
  derive(near, occupied(post, by: me))

The content says what space to watch and whose presence counts; the browser does the watching, by a plain point test each frame with no physics. me is never a person: it is the being this machine's visitor drives, compared as any being is (Visitors). What else an area senses (props, a named kind, how many, who left) is open; the proposal below answers it in part.

One mechanism for triggers, zones and waking

An area is a volume a part holds, written in the one form above: on a part with no drawing (part entry, at: (...) with area(self, ...) in its body), or on a drawn part (the basket, the post). It states what it senses: visitors, any being, props, a named kind. It sends entered and left, with who, and held conditions can be written against it (Events). The same mechanism serves five uses:

UseExamplesWhere the use is described
Triggersthe balloon's basket; the lantern stakes' nearnessEvents; The balloon ride; The lanterns
Zones with settingssheltered; underwater, where posture changes to swimming; a sound zoneSky and weather; Sounds
Portal mouthscrossing the area is the passageGates, below; Portals
Waking regionsthe area a region can be seen from; an eye entering it wakes the regionWorlds: waking a region
Ownership of spacewhat the server tracks per areaDistribution

A waking area senses eyes (cameras drawing a picture; which ones is open on Cameras) rather than beings; a portal mouth senses whatever may pass (Portals: who and what may pass).

Gates: crossing

A gate is a flat opening (a plane and its edges), a shift, and a rule: a being whose eyes cross the plane inside its edges comes out shifted. Crossing is decided where bodies are stepped, both on the server and in the visitor's own predicting browser, so both cross at the same step and nothing is corrected. The being, its planted feet, its drawn place and the camera move together. A gate is a translation: a rotation would need more machinery. A gate is written gate(across: pane, shift: link, edges:, oneWay: true, when:). edges: are the opening's edges and default to the pane's; a gate may be smaller than its pane. oneWay: true acts only on a being moving the way it faces: a corridor that will not end sends back only such a being, and one walking backwards goes through untouched. A gate is crossed in one direction of its plane in any case; the way back is the gate at the other end. when: is a condition read at every step (open, a quest stage), and the gate works only while it is true. It may read the being that crosses, which is how a gate lets some through and not others (Portals: who and what may pass). A gate needs a hole in the world: while a looking-glass is open, the cottage's solid gets a slot 1.1 m wide and 1 m deep, three boxes in place of one, rebuilt on the server and in every predicting browser. A physical product derived again while the world runs must change in step everywhere walkers are stepped. What a gate shows is on Cameras and views.

A gate is a portal's passage: its mouth is an area, and crossing it moves the being to the portal's destination. To a place in the same scene, the being keeps its facing and motion unless the portal gives a facing; to an arrival, in this scene, another or another world, it takes the arrival's place and facing (Portals: which way you face). The portal's rules decide who and what may cross; what may not stays behind. Crossing stays a built-in rule, decided in step on the server and in each predicting browser as today (Portals).

Built-in rules and their numbers

Walking, jumping, falling, landing, going limp, lying still, getting up and being set down are rules of the engine, the same in every world. Their numbers are the engine's settings, not fields of the world: a world does not state them, and the island's code has them as constants. Whether a world may change them is open. The one thing a world states about them is where a being that is lost is set down (recoverAt, below).

RuleSettingValue
Walking (a kinematic capsule)walking speed1.8 m/s (backward is the same speed)
running speed4.5 m/s
acceleration, and slowing12 m/s², in a straight ramp to the speed asked for
rotation1.05 rad/s (60 degrees a second), at once, with no ramp
capsuleradius 0.15 of the being's height, as tall as the being; steeper ground than 45 degrees is a wall
step up; snap down; skin0.4 m; 0.35 m; 4 mm
Jumping and fallingjump4.2 m/s upward (a rise of 0.9 m), only from the ground; a jump from a platform adds the platform's own speed
gravity; fall cap9.81 m/s each second; 55 m/s
in the airno control: the horizontal speed at take-off is kept
Landinghard landing7 m/s or more (a drop of 2.5 m): the crouch below, the health cost, and the hardLanding trigger
soft landingabove 1.5 m/s and below 7 m/s: the crouch, at 0.4 of the speed
health costa straight ramp from 0 at 10 m/s (a drop of 5 m) to 1, all of it, at 24 m/s (29 m)
limpa fall faster than 5 m/s down (a drop of about 1.3 m) sends the being limp
wadinga walker goes no deeper than 0.6 m under the sea (The land)
Limp and getting uplying stillevery body under 0.15 m/s for 0.4 s, then 2 s more: 2.4 s from stillness to the get-up
get-upthe clip is blended in from the lying pose over 0.3 s
lostlower than 60 m below the sea's surface; or limp for 40 s

The walking response. The standard actions walk, run, turn and jump are answered by this rule with no line from the world: the speed ramps toward what the action asks, the heading turns, a jump leaves the ground, and the same step of 1/60 s is run on the server and in the visitor's predicting browser (Distribution). A world writes a response only to add to it. The ground a being stands on is the highest of the land, a platform's floor and the top of a solid, within a step up of its feet. v.speed is signed along the being's heading (negative backing up) and is the speed it left the ground with while in the air. In the air there is no control: the take-off speed is kept, and on landing the speed along the heading is kept, so a turn made in the air changes it. Hard landings of 7 m/s or more are, in the island, a limp being's (a fall is limp from 5 m/s, so a capsule does not reach 7).

Landing: the crouch and the cost

On a hard landing the pelvis drops by 0.04 of the being's height for each m/s of landing speed, at most 0.30 of the height, within 0.06 s, and comes back by a smooth step over the rest of the first 0.5 s (a landing at 7 m/s drops 0.28 of the height; the cap is reached at 7.5 m/s). A soft landing, above 1.5 m/s and below 7, takes the same crouch at 0.4 of the speed (5 m/s drops 0.08 of the height; 1.5 m/s, 0.024). The gait then begins afresh (Package behaviors: walkgait).

The health cost is a straight ramp from 0 at 10 m/s to 1 at 24 m/s of landing speed, clamp((speed - 10) / 14, 0, 1), written by the engine into the being's health; a world reads it as cost in hardLanding and as v.health. A limp being's landing speed is the peak speed of its bodies divided by 1.1, and it is charged the cost of that speed less what this fall has already been charged, so a bounce charges only the increase.

The ragdoll: a being gone limp

A being that falls faster than 5 m/s goes limp: its body becomes a ragdoll, fourteen rigid bodies joined at the joints, stepped by physics, and keeps the speed it fell with (not its health: an emptied health only decides where it gets up, below). It is the engine's, the same in every world, and a world sees only the being's mode (Visitors: what a being handle reads).

The body

A person of 70 kg and any height, in fourteen bodies. Masses are shares of the 70 kg and sizes are fractions of the height H; the head, hands and collar bones have no body of their own and ride the nearest one.

BodyShapeSizeShare of massJoint to its parent
pelvisboxhalf-sides 0.112, 0.055, 0.068 H0.142the root
spinebox0.100, 0.065, 0.062 H0.139cone-twist
chestbox0.118, 0.075, 0.068 H0.216cone-twist
neck and head (one body)sphereradius 0.065 H0.081cone-twist
upper arm, twocapsuleradius 0.030 H0.028 eachcone-twist
forearm and hand, twocapsuleradius 0.024 H, the hand's length added0.022 eachhinge
thigh, twocapsuleradius 0.046 H0.100 eachcone-twist
shin, twocapsuleradius 0.034 H0.0465 eachhinge
foot, twobox0.029, 0.0225, 0.076 H0.0145 eachhinge

The joints' ranges, in radians from the standing pose. A cone-twist turns about its own axis within the twist range and swings within an ellipse whose four quarter-axes are given:

JointTwistSwing: forward, back, out, in
spine±0.200.55, 0.35, 0.35, 0.35
chest±0.400.35, 0.20, 0.30, 0.30
neck±1.400.80, 1.05, 0.70, 0.70
upper arm±1.302.60, 0.90, 2.40, 0.50
thigh±0.752.10, 0.35, 0.80, 0.50

The hinges bend about one axis: the forearm from -0.05 to 2.50, the shin from -2.45 to 0.03, the foot from -0.90 to 0.60. The bodies collide with the ground and the solids, and with each other unless they are joined; a walking being never collides with a ragdoll. Friction is 0.8, with no bounce; the bodies slow by a damping of 0.3 on their spin and none on their travel, so a fall is gravity's alone; the world is stepped eight times to a step.

Where it runs

The server steps a ragdoll; no browser does. Each snapshot carries the fourteen bodies' rotations, four bytes each (56 bytes), and the browsers set their own parked ragdoll to them and draw it. A limp being is not predicted.

Lying still, and getting up

A limp being is still when every body has been under 0.15 m/s (a body's speed plus half its spin times its reach) for 0.4 s; it then lies 2 s more, 2.4 s in all, and the count starts again whenever it moves. Then it gets up by one of three clips, chosen by how it lies: face up (3.4 s), face down (3.3 s), or, if it ended upright, the short one (1.2 s); a being on its side takes the face-up clip if its front is turned up and the face-down if down. The clip is set on the floor under its pelvis, turned so that its head lies where the ragdoll's did, and blended in from the lying pose over 0.3 s. When the clip is done the being walks.

Recovery

When it has lain still its 2 s, a being is set down whole at a named place instead of getting up, if it is dead (its health is empty), lost (lower than 60 m below the sea's surface, or limp for 40 s), or lying where the ground is deeper than the wade (0.6 m under the sea). The place is the world's setting recoverAt, a fixed field of the world: field recoverAt: place = (-22, land.height((-22, 0, 499)), 499), the landing beach. It is set down with its health whole, its speed none and its gait begun afresh. Otherwise it gets up where it lies.

The packages

rigiddynamics

Bodies static, kinematic or dynamic; mass or density; damping; gravity factor; layers and masks; sensors ("detects overlap (events) but does not collide"); sleep after half a second of stillness; continuous collision for fast bodies, against all if a "bullet". Joints: point, fixed, hinge, slider, distance, cone-twist, with motors, drives and breaking. Materials: standard, ice, rubber, wood, steel, bouncy. Forces and impulses, ray and shape casts, overlap queries. A character controller, a capsule that is not a rigid body, carried by a moving ground. Not here: a six-way joint, soft bodies.

rigidcollide

Shapes: sphere, box, capsule, cylinder, convex hull, triangle mesh, heightfield, and compounds of them. Not done: one-sided triangles, a plane shape, scaled shapes.

Floating (buoyancy, which takes the water as a function of position), cloth and rope coupled to bodies (clothrope) and soft bodies (xpbdsoftbody) are further packages.

How it connects

Open questions

  1. A form for what a part is: vocabulary functions naming the part, or declarations on the part.
  2. Two areas on one part. Under the one-form proposal a part has at most one area, named by the part (occupied(post)); a part that needs two (a near zone and a touch zone) holds a child part for the second. Whether that is enough.
  3. Which further collisions are messages. struck and cameToRest are proposed (A body's events); whether a world needs contacts between bodies already awake, and with what threshold.
  4. Requests to engines beyond throw, sleep and wake: a push, an impulse, a contact test.
  5. One facet, several practices: whether content names its solid at all; the default (solid or not).
  6. Determinism: whether some props should be predicted, which needs the same physics bit for bit on every machine.
  7. What an area senses; areas across regions; who left. A proposal answers what an area senses and who left (Areas: one mechanism); an area spanning a waking and a sleeping region remains open (Worlds, scenes and regions).
  8. A portal as one thing: a pane and a gate that must agree, written as two; one way stated or by absence. A proposal answers this (Portals); whether one declaration makes both ends of a two-way portal is still open there.
  9. Zones with settings as areas: whether "underwater, so swimming" and "sheltered" are settings on an area that every engine reads, and how a being's posture follows them.
  10. Seat rules: whether a world may change the reach or reserve a seat; a bench for two.
  11. The built-in numbers: walking, jumping, landing and the ragdoll's settings are the engine's; whether a world may change any of them is open.
  12. Gravity as a field: a world with gravity per surface needs each body's down to follow the surface under it.

← Overlays, HUDs and speech | Contents | Cameras and views →