Reference

Posecode Protocol Specification v0.1

Posecode is a small text language for describing a single person's kinematic movement so it can be rendered as an animated 3D figure in a web browser.

It is to human movement what Mermaid is to diagrams: an LLM (or a human) writes a compact, readable document; a client-side parser + renderer turns it into a moving mannequin. The model never produces 3D matrices: it expresses the *semantic phases* of a movement, which it already understands.

on the client (Three.js). See the project research §6.


1. Grammar

Posecode is line- and indentation-oriented. Comments start with # or //.

document   = header { directive } ;
header     = "posecode" kind STRING ;
kind       = "exercise" | "stretch" | "posture" ;       (* free-form word *)
directive  = rig | prop | pose | step | repeat ;
rig        = "rig" WORD ;
prop       = "prop" WORD ;                              (* chair|wall|bar|box|dip-bars, repeatable *)
pose       = "pose" "start" "=" WORD ;                  (* neutral|standing|plank|supine|prone|seated *)
repeat     = "repeat" NUMBER ;
step       = "step" STRING DURATION easing ":" { child } ;
easing     = "linear" | "ease-in" | "ease-out" | "ease-in-out" ;
child      = jointTarget | groundLock | reach | pin | turn | travel | cue ;
jointTarget= joint ":" action [ NUMBER ] ;
groundLock = "ground-lock" ":" effector { "," effector } ;
reach      = "reach" ":" effector target ;             (* effector → world target via ROM-constrained IK *)
pin        = "pin" ":" effector anchor ;               (* move the BODY so effector sits on anchor *)
turn       = "turn" ":" NUMBER ;                       (* face this yaw (deg) by phase end *)
travel     = "travel" ":" NUMBER NUMBER ;              (* move to this x z (metres) by phase end *)
cue        = "cue" STRING ;
DURATION   = NUMBER "s" ;                                (* e.g. 2s, 1.5s *)

A step is one phase of the movement. Phases run in sequence; within a phase, all joint targets apply concurrently.


2. Joints

Group (plural)BonesSingular forms
shouldersshoulder_left, shoulder_rightyes
elbowselbow_left, elbow_rightyes
wristswrist_left, wrist_rightyes
hipship_left, hip_rightyes
kneesknee_left, knee_rightyes
anklesankle_left, ankle_rightyes
axialpelvis, spine, chest, neck, headn/a
fingers (or fingers_left / fingers_right)thumb_*, index_*, middle_*, ring_*, pinky_*yes

Plural names move both sides symmetrically (left-side bones mirror the Y and Z axes). Use a singular *_left / *_right name to move one side. Each finger is a single curl (flex) joint; the thumb also takes abduct/adduct.


3. Actions

Each action maps to a rotation about one local axis. Degrees are absolute targets for that direction (a phase that doesn't mention a joint leaves it where the previous phase left it).

ActionAxisMeaning
flex / extendX (sagittal)bend / straighten
abduct / adductZ (frontal)away from / toward midline
rotate-in / rotate-outY (longitudinal)internal / external rotation
supinate / pronateYforearm turn
dorsiflex / plantarflexXankle up / down
hingeXtip the torso forward over the hips (pelvis only)
hold neutraln/akeep at rest

hinge is a hip hinge: applied to the pelvis, it pivots the torso forward over the hip line while the legs stay planted and vertical (the renderer counter-rotates the hips). Use it, not spinal flex, for a flat-back forward bend: deadlift, bent-over row, good-morning, or a bow.

Coordinate convention: rest pose is standing, arms at sides, facing +Z. The renderer's mannequin is built in this same convention so the parser's resolved Euler angles apply directly.


4. Range of Motion (safety)

Every angle is hard-clamped to a healthy Range of Motion before rendering; a clamp emits a warning (it does not fail the parse). Limits follow the research §5.1 normative tables. Selected ceilings (degrees):

Jointflexextendabductother
shoulder18060180rot-in 70 / rot-out 90
elbow15410n/asupinate 92 / pronate 84
hip1352045n/a
knee1445n/an/a
anklen/an/an/adorsiflex 15 / plantarflex 50
pelvisn/an/an/ahinge 120
finger10020n/an/a
thumb802050adduct 30
spine903035rotate 45
neck506045rotate 80

> ⚠️ These are general literature values, not medical advice. Consult a > qualified professional for physiotherapy or exercise prescription.


5. Rendering model

  1. Forward kinematics: each phase sets joint angles; the renderer slerps

bone rotations between phases with the phase's easing.

  1. Grounding: the figure is dropped so its lowest point rests on the floor

(a bounding-box drop), which grounds standing, plank, and the lying/seated poses alike.

  1. Ground-lock IK: effectors listed in ground-lock (hands, feet) are

pinned to their planted floor position so they stay put while the body moves.

  1. Reach-IK: a reach: line drives an effector (`hand_left|hand_right|

foot_left|foot_right, or the groups hands/feet for both sides) to a world target via Cyclic Coordinate Descent (CCD) over the arm/leg chain. A target is a body landmark bone (e.g. ankle_left), the keyword floor, or a prop anchor (bar, seat, wall`). The solve is ROM-constrained: each iteration clamps every chain joint into its §4 Range-of-Motion limits (expressed as a per-axis box in the bone's local Euler frame), so a reach toward an unsafe or unreachable target settles on the closest *healthy* pose; solved angles obey the same hard limits as authored ones.

  1. Props: prop chair|wall|bar|box|dip-bars adds a scene object at a

fixed default placement (chair/wall behind, bar overhead, box in front, dip bars either side); its named anchors (seat, wall, bar, box, bars) become reach/pin targets.

  1. Pins: pin: <effector> <anchor> translates the whole figure so the

effector sits on the anchor (effectors accept the same hands/feet groups as reach: pin: hands bar pins both). Where ground-lock keeps a foot on the floor and reach moves a limb to a target, a pin moves the body while the contact stays put, so the figure hangs from a bar, pulls up toward it, rises onto a box, or lowers into a dip as the joints work.

  1. Spatial choreography: turn: <deg> rotates the figure's facing (yaw

about vertical) and travel: <x> <z> moves it across the floor (world metres from the load spot). Both are absolute targets carried across phases (like joint angles) and both return home on the loop wrap, so a box-step traces a square back to start and a pirouette spins a full turn. They layer under grounding (feet still rest on the floor) and power pirouettes, grapevines, traveling combos, and walk cycles. Standing poses only: combining with lying/seated bases (whose root is already tilted) is out of scope.

  1. Looping: the timeline loops base → phases → base; repeat is the rep

count surfaced to the UI.

Start poses: neutral, standing, plank, supine (face-up), prone (face-down), seated (long-sit on the floor).

IK note: Three.js's bundled CCDIKSolver targets SkinnedMesh; the Posecode mannequin is rigid capsule segments, so Posecode implements CCD directly over the Object3D bone hierarchy (posecode-render/ik.ts) for both ground-lock and reach. Two-person/dual-IK and collision detection remain deferred (research §5.2, §6.2).


6. Intermediate Representation (IR)

parse(source) returns { ir, warnings, errors }. The IR is renderer-agnostic; angles are in degrees.

interface PosecodeIR {
  version: string;          // "0.1"
  kind: string;             // "exercise" | "stretch" | "posture"
  name: string;
  rig: string;              // "humanoid"
  startPose?: string;       // "plank" | "standing" | ...
  repeat: number;
  phases: {
    name: string;
    durationSec: number;
    easing: "linear" | "ease-in" | "ease-out" | "ease-in-out";
    targets: { boneId: string; euler: { x: number; y: number; z: number } }[];
    groundLock: string[];   // ["hands","feet"]
    cue?: string;
  }[];
}

See llm-authoring.md for the prompt that teaches an LLM to write Posecode, and examples/ for complete documents.