Skip to main content

Balance

The balance model behind a stagger: a small, deterministic simulation in the spirit of NaturalMotion's Euphoria (the ragdoll behaviour in GTA IV / V and Red Dead). It does not know about parts or joints; it turns "you were shoved this hard in this direction" into a stream of numbers the Controller turns into steps, leaning and a decision.

The character has a lurch (horizontal velocity they are being carried by) and a balance from 0 to 1. Balance drains while they are lurching. At irregular intervals they take a catch-up step: a clean step kills part of the lurch and buys some balance back, a stutter is a half step that buys less and comes sooner, and a misstep kicks them sideways and costs balance. When the lurch has died down with balance to spare they have recovered; when balance hits zero they fall.

Everything random comes from a Random seeded by the stagger, so the server and the simulating client agree on what happens without talking.

Types​

Outcome​

type Outcome = "Staggering" | "Recovered" | "Fell"

What Balance:Step returns.

Leg​

type Leg = "Left" | "Right"

Functions​

new​

Balance.new(
config: Config,
direction: Vector3,--

Horizontal direction of the shove (it is flattened and normalised for you).

intensity: number,--

1 is the preset as tuned; 0.5 half a shove, 2 a big hit.

seed: number--

Seed for the model's Random.

) → Balance

Creates a balance model.

Disturb​

Balance:Disturb(
amount: number,--

Balance to remove, 0 to 1.

direction: Vector3?--

Direction of the extra lurch; the lurch added is amount * LurchSpeed.

) → ()

Knocks the model again without restarting it: adds lurch in direction (or the current direction) and takes amount off the balance. The controller feeds bumps into this; you can too.

Step​

Balance:Step(
dt: number,
catch: number?--

0 to 1: how much the player is running the stumble out (walk input lined up with the lurch). Earns balance back and bleeds speed.

) → Outcome--

"Staggering" while undecided, then "Recovered" or "Fell" once and for all.

Advances the model by dt seconds. Call it every frame on the simulating side.

Lean​

Balance:Lean() → number

How far the torso should lean into the lurch right now, in radians.

ArmRaise​

Balance:ArmRaise() → number

How far the arms should be out, 0 to 1.

Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "Creates a balance model.",
            "params": [
                {
                    "name": "config",
                    "desc": "",
                    "lua_type": "Config"
                },
                {
                    "name": "direction",
                    "desc": "Horizontal direction of the shove (it is flattened and normalised for you).",
                    "lua_type": "Vector3"
                },
                {
                    "name": "intensity",
                    "desc": "1 is the preset as tuned; 0.5 half a shove, 2 a big hit.",
                    "lua_type": "number"
                },
                {
                    "name": "seed",
                    "desc": "Seed for the model's `Random`.",
                    "lua_type": "number"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Balance"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 82,
                "path": "packages/src/Stagger/Balance.luau"
            }
        },
        {
            "name": "Disturb",
            "desc": "Knocks the model again without restarting it: adds lurch in `direction` (or the current\ndirection) and takes `amount` off the balance. The controller feeds bumps into this; you\ncan too.",
            "params": [
                {
                    "name": "amount",
                    "desc": "Balance to remove, 0 to 1.",
                    "lua_type": "number"
                },
                {
                    "name": "direction",
                    "desc": "Direction of the extra lurch; the lurch added is `amount * LurchSpeed`.",
                    "lua_type": "Vector3?"
                }
            ],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 125,
                "path": "packages/src/Stagger/Balance.luau"
            }
        },
        {
            "name": "Step",
            "desc": "Advances the model by `dt` seconds. Call it every frame on the simulating side.",
            "params": [
                {
                    "name": "dt",
                    "desc": "",
                    "lua_type": "number"
                },
                {
                    "name": "catch",
                    "desc": "0 to 1: how much the player is running the stumble out (walk input lined up with the lurch). Earns balance back and bleeds speed.",
                    "lua_type": "number?"
                }
            ],
            "returns": [
                {
                    "desc": "`\"Staggering\"` while undecided, then `\"Recovered\"` or `\"Fell\"` once and for all.",
                    "lua_type": "Outcome"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 195,
                "path": "packages/src/Stagger/Balance.luau"
            }
        },
        {
            "name": "Lean",
            "desc": "How far the torso should lean into the lurch right now, in radians.",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 254,
                "path": "packages/src/Stagger/Balance.luau"
            }
        },
        {
            "name": "ArmRaise",
            "desc": "How far the arms should be out, 0 to 1.",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 267,
                "path": "packages/src/Stagger/Balance.luau"
            }
        }
    ],
    "properties": [],
    "types": [
        {
            "name": "Outcome",
            "desc": "What [Balance:Step] returns.",
            "lua_type": "\"Staggering\" | \"Recovered\" | \"Fell\"",
            "source": {
                "line": 29,
                "path": "packages/src/Stagger/Balance.luau"
            }
        },
        {
            "name": "Leg",
            "desc": "",
            "lua_type": "\"Left\" | \"Right\"",
            "source": {
                "line": 35,
                "path": "packages/src/Stagger/Balance.luau"
            }
        }
    ],
    "name": "Balance",
    "desc": "The balance model behind a stagger: a small, deterministic simulation in the spirit of\nNaturalMotion's Euphoria (the ragdoll behaviour in GTA IV / V and Red Dead). It does not\nknow about parts or joints; it turns \"you were shoved this hard in this direction\" into a\nstream of numbers the [Controller] turns into steps, leaning and a decision.\n\nThe character has a **lurch** (horizontal velocity they are being carried by) and a\n**balance** from 0 to 1. Balance drains while they are lurching. At irregular intervals\nthey take a **catch-up step**: a clean step kills part of the lurch and buys some balance\nback, a **stutter** is a half step that buys less and comes sooner, and a **misstep** kicks\nthem sideways and costs balance. When the lurch has died down with balance to spare they\nhave **recovered**; when balance hits zero they **fall**.\n\nEverything random comes from a `Random` seeded by the stagger, so the server and the\nsimulating client agree on what happens without talking.",
    "source": {
        "line": 19,
        "path": "packages/src/Stagger/Balance.luau"
    }
}