How it works.

Four parts: a body in a physics engine, a trainer on a rented GPU, a feed of published files, and a contract that will record them. Each section says what the part is, what it is not, and how to check it without trusting this page.

The body

A Unitree G1 humanoid, described by files nobody here drew. The same files train on the GPU and run in your browser.

The robot is the unitree_g1 model from MuJoCo Menagerie, pinned to commit 8161bba2. The scene, the actuator gains and the reward terms come from MuJoCo Playground's G1 joystick task, pinned to commit 4057c147. Every generation records a hash over every source file its scene reads, so anyone can rebuild the exact model it trained on.

Physics
MuJoCo 3.13.0, in Python on the trainer and as WebAssembly here
Degrees of freedom
29 hinge joints on a floating base: nq 36, nv 35, 29 position actuators
Rates
control at 50 Hz, physics at 500 Hz (ten 0.002 s substeps per control step)
Action
motor target = knees_bent pose + 0.5 × policy output
Episode
20 s, 1000 control steps

The policy never commands a torque. It moves the target of a position servo on each joint, and MuJoCo computes the force inside that joint's limit. A fall has a precise definition: the torso turns past horizontal, a foot touches the wrong body, the state stops being finite, or the pelvis drops below 0.35 m. The first one to happen is recorded by name, with its frame.

Your browser gets the same model with two changes, both written into the web bundle's manifest: lighter visual meshes, checked against the originals for identical masses and inertias, and a weld from the pelvis to a fixed anchor. That weld is the rig on the Body page. Replay and live mode switch it off, and the training model never had it.

The trainer

PPO on an RTX 4090, evaluated away from the training code, published as files.

Training uses MuJoCo Playground's G1 joystick environment with brax PPO, on flat or rough ground depending on the stage. Thousands of copies of the robot step in parallel on one GPU while a three-layer network learns to stay upright and follow a velocity command.

Algorithm
PPO, brax 0.14.2, policy and value networks of 512, 256 and 128 units
Parallel robots
8192
Hardware
one rented RTX 4090 on RunPod, plus CPU workers for evaluation
One generation
10,000,000 environment steps, then an evaluation, then a publish
Evaluation
100 episodes of 20 s in plain C MuJoCo, no observation noise, fixed seeds

A generation is a fixed amount of experience, not a length of time. When its ten million steps are done, the evaluator loads the exported ONNX policy into the plain C build of MuJoCo on the same scene and runs the same seeds every time. Those results are what gets published and what the ledger will record.

A stage is a target with a pass rule. S0 asks the robot to stand at a zero command. S1 asks it to walk at 0.8 m/s with a small velocity error. S2 moves to rough ground, S3 adds turning and walking backwards, S4 raises the command to 1.8 m/s, and S6 pushes the robot while it walks. Stages pass in order and never go back to pending. S5, getting up after a fall, cannot run: the pinned Playground has a get-up task for two quadrupeds and none for the G1, so the trainer stops there rather than report a number it never measured.

The feed

Every number on this site comes out of these files.

Each generation is a folder. Three small files at the root point at the rest: latest.json names the newest generation and the trainer's status and heartbeat, index.json lists every generation with its headline numbers and the sha256 of its manifest, and stages.json holds the seven stages with their thresholds and status.

manifest.json
stage, kind, model hash, the evaluation with one row per episode, and the sha256 of every other file in the folder
config.json
every environment, PPO, control and torque setting the generation used, including the 29 torque scales
rollout-0..2.bin
three recorded episodes as raw little-endian float32, 36 values per frame, 1001 frames at 50 Hz
policy.onnx
the network that was evaluated, and the file live mode runs in your browser; absent for an untrained generation

Publishing is atomic. The trainer writes the files first, the manifest second, the index and stage board third and latest.json last, each under a temporary name that gets renamed into place, so nobody ever reads half a generation. It publishes into a public Supabase Storage bucket, and a copy of the feed ships with the site. Every page reads the bucket first, falls back to the copy when the bucket does not answer, and tells you which one it used.

Check a generation yourself

Two commands. No account, no key, no trust in this page.

index.json carries the sha256 of each manifest's exact bytes, which is also the hash the ledger will record. The manifest carries the sha256 of every file beside it. One hash checked from a shell ties a chain entry to a set of files and to the numbers here.

curl -s https://gaitlabs.xyz/feed/latest.json
# take "manifest" from that answer, then hash its exact bytes
curl -s https://gaitlabs.xyz/feed/gen/000000/manifest.json | shasum -a 256
# compare with manifestSha256 for that generation
curl -s https://gaitlabs.xyz/feed/index.json

JSON files are written with sorted keys, a two-space indent and a trailing newline, and nothing re-serializes them before hashing, so the bytes you download are the bytes that were hashed. The training console prints the same commands for whichever generation you open, and its Verify button runs the whole check inside your browser.

The ledger

Written and tested. It deploys at launch, and this page will show its address then.

GaitLedger is a Solidity contract for Robinhood Chain, chain id 4663. It is the permanent record of the run: one entry per posted generation, one per stage passed, nothing else. It holds no funds, cannot be upgraded and cannot destroy itself.

Per entry
generation number and stage, sha256 of the manifest bytes, survival in basis points, mean distance in centimetres, falls, the root of the seat table in force, the block timestamp
Who writes
only the keeper key; generation numbers must increase and stages pass in order, once each
Who edits
nobody, including us; the owner can only rotate the keeper key, and can give up even that

The plan is an entry about once an hour plus every generation that passes a stage. That keeps the record readable and the gas negligible on a chain with sub-second blocks.

The seats

Twenty-nine joints. Each belongs to whoever has burned the most $GAIT into it.

A claim burns the tokens: the seat contract sends them to the token's own burn function, or to the dead address if it has none. To take a seat you must burn strictly more than its current holder did, and they get nothing back. The holder sets the joint's torque budget between 0.70 and 1.00 of its force limit, in one more transaction. The floor keeps any single seat from breaking the run; the ceiling keeps anyone from buying a joint stronger than the real G1.

Seat numbers follow one fixed order published in the interface contract: waist yaw first, then the knees, hip pitch, roll and yaw, the ankles, waist pitch and roll, then shoulders, elbows and wrists, left before right. The trainer reads all 29 seats with one call before each training segment and writes the scales into that generation's config.json, which the manifest hash on chain covers. Anyone can later check which weakened joints a generation trained with.

Not built yet

The short list, so nobody has to guess.

  • The GPU trainer has not published a trained generation yet. The feed holds generation 0, the untrained baseline, until it does.
  • $GAIT has not launched, so there is no token address, no seat contract and nothing to claim or burn.
  • The ledger is not deployed. No number on this site is on a chain yet.
  • S5, getting up, has no environment in the pinned Playground and cannot be trained or evaluated until someone writes one.
  • Recorded episodes are kept for the newest fifty generations plus every stage-passing generation. Manifests, configs and policies are never pruned.

Built on

Open source, with licences. None of these projects endorse this one.

MuJoCo 3.13.0
physics; Google DeepMind, Apache 2.0
MuJoCo Menagerie, unitree_g1
robot description; Unitree Robotics, BSD 3-Clause
MuJoCo Playground
G1 joystick task; Google DeepMind, Apache 2.0
Brax and JAX
PPO and the accelerated training loop; Google, Apache 2.0
ONNX Runtime Web
policy inference in the browser; Microsoft, MIT
three.js
rendering and post-processing; MIT
Vite and TypeScript
build and language; MIT and Apache 2.0
GSAP and Animate.css
page motion; GreenSock standard licence and MIT
Foundry
contract tests; MIT and Apache 2.0
Geist and Phosphor
type and icons; SIL Open Font License and MIT