t4as

Software & Sims · 2026

Inside the Walker: Legs, Weight and a Cockpit Made of Camera Feeds

A four-legged transport for the surface of the generated world: an 11 m machine with a procedural gait, a hull on a spring and three-segment legs. You board it through the belly and drive it from a cabin whose screens show what cameras on the hull see, so looking left means turning your head to the port screen, not turning the world.

  • Godot 4.7
  • GDScript
  • GLSL shaders
  • Python
  • NumPy
  • Procedural animation
  • Inverse kinematics
from the ground to the top of the hull when standing; it kneels 3.4 m lower to let the pilot in
11 m
camera feeds rendered for the cockpit: forward, port, starboard and belly
4
mean frame time on foot vs. in the cockpit (RTX 3060 Laptop, 1600×900, vsync off, 6 s each)
3.3 → 10.3 ms
animation clips: every step, sway and jolt is computed each frame
0
The walker standing on a sand plain in low sun: a cream wedge-shaped hull with blue stripes, arm-like front legs and heavier digitigrade hind legs, a cargo pack on its back and exhaust stacks smoking

Result

The generated world from Seeing Through Stone has a surface that is far bigger than anyone wants to cross on foot. The walker is the overworld’s fast travel: a slow, heavy four-legged transport that carries the player from ruin to ruin. Inside a ruin the game switches back to the lantern camera; the two never run at the same time. You walk up to it in third person, it kneels, the belly hatch opens, and you climb into a cabin where the outside reaches you only through camera feeds. The design takes its cue from the titan cockpit in Titanfall 2: screens instead of windows, thin seams between them, a feed that boots and glitches.

Driving the walker from the cockpit: the centre screen is the forward camera, the side screens show the flank cameras, the low screen looks down from the belly. At the end the pilot disembarks and the walker kneels in its own dust.

What works now:

  • A gait with weight. One leg moves at a time and three stay planted. Each step lifts fast, hangs, and lands hard. The hull sits on a spring, so every landing sinks it a little, and it leans over the planted feet.
  • Legs that look grown, not mirrored. Arm-like front legs, digitigrade hind legs, three segments each, and every leg with its own lengths, knee direction, toes and armour.
  • A cockpit you sit in. Five screens around the pilot’s head, each fed by a camera mounted where a small lens pod sits on the hull. Turning the head looks into a side screen; the outside view never turns with the mouse.
  • Motion you feel through the seat. The pilot’s head is a mass on a spring, pushed by the hull’s measured acceleration. A front-left footfall rolls you left and pitches you forward; walking into a ruin throws you forward and tears the feeds.

Weight without animation clips

The walker has no animation data. Every frame, the code decides where each foot should be, solves the legs to reach it, and moves the hull over the result.

The gait is a phase that advances with distance travelled: each leg owns a quarter of the cycle in the air (left hind, left fore, right hind, right fore), so three feet always carry the hull. When the walker stops, the phase keeps running at a slow shuffle until every foot is within 0.7 m of its rest position, then halts. Turning in place falls out of the same rule.

Where a foot lands is predicted, not reacted to: when a leg lifts, its target is the rest position the hull will have by the middle of that foot’s next stance, from the current speed and yaw rate. The shape of the step carries most of the sense of mass (walker.gd):

var t := p / DUTY
var w := maxf(omega, 1e-3)
var ahead := (1.0 - t) * DUTY / w + (1.0 - DUTY) * 0.5 / w
leg.target = _ground(_rest(leg.i, minf(ahead, 3.0)))
var s := smoothstep(0.08, 0.82, t)
var pos: Vector3 = leg.from.lerp(leg.target, s)
# heavy step: lifts quickly, hangs, slams down at the end
var lift := sin(PI * pow(t, 0.72))
pos.y += STEP_HEIGHT * lift * clampf(0.35 + dist / 3.0, 0.35, 1.0)

The horizontal move finishes before the drop does, and the exponent on t skews the arc so the foot comes down faster than it went up. Short corrective steps get a lower lift, so shuffling in place doesn’t look like marching.

Each landing kicks the hull’s vertical spring (k = 26, slightly underdamped), raises a ring of dust, sometimes vents steam from the hock, and emits a footfall signal that the cameras use. Body pitch and roll follow the front/back and left/right foot heights, with a small shift of weight away from whichever foot is in the air.

Three segments, one solved joint

The legs have three segments (thigh, shin, metatarsus), which a two-bone solver can’t handle on its own. Rather than writing a full three-joint solver, I set the metatarsus by hand: each leg has a lean direction for standing and another for kneeling, and it folds back while the foot is in the air. That fixes the hock, and the thigh and shin solve onto it with the usual two-bone construction:

var m_local: Vector3 = spec.meta.lerp(spec.meta_kneel, k)
m_local += Vector3(0, -0.1, 0.55) * leg.lift
var hock: Vector3 = ankle + (yb * m_local).normalized() * float(L[2])
var d := hock - hip
var dist := clampf(d.length(), absf(l1 - l2) + 0.1, l1 + l2 - 0.02)
var along := (l1 * l1 - l2 * l2 + dist * dist) / (2.0 * dist)
var h := sqrt(maxf(l1 * l1 - along * along, 0.0))
var knee := hip + dir * along + perp * h

The knee direction (pole) is per leg too. The front legs push their elbows up and out, the hind legs push their knees forward, and the folding metatarsus gives the hind legs a backward hock. Pistons between hull and thigh, and between thigh and shin on three of the legs, are re-aimed every frame, which shows the joints working under load.

Side profile in low sun: the hull is a forward-leaning wedge, tall at the back where the hind legs hang from high shoulders and low at the cockpit prow; the cargo pack hangs off the back

A hind leg up close: the knee pad, the shin widening towards the hock with a back spur, the heavy lower column and a three-toed foot pad; a hose runs down the back

A cockpit made of camera feeds

The walker has no windows. The pilot sees the outside through cameras, and the cockpit should make that obvious: screens, seams between them, a feed that boots with static and tears when a foot slams down.

# cockpit_room.gd: who sees what
cam.cull_mask = 0xFFFFF & ~CABIN_LAYER                                       # feed cameras
views.center.cam.cull_mask = 0xFFFFF & ~CABIN_LAYER & ~walker.HULL_LAYER   # it sits inside the prow
# walker_demo.gd, while piloting: the pilot sees only the cabin
cam.cull_mask = CockpitRoom.CABIN_LAYER

The feed look (a cool grade, scanlines, colour fringes, grain, tearing bands) is one full-screen quad on a layer that only feed cameras render, so each feed carries the effect and the cabin stays clean. The HUD is drawn per screen into transparent viewports and composited in the screen’s shader, so the compass, the leg-contact diagram and the waypoint stay in perspective on their screens when the head turns. The belly screen looks straight down from under the hatch and marks where the pilot will step off.

The cockpit while walking: the centre screen shows the forward feed with compass, leg diagram and ground speed; the side screens wrap around the head; the low screen looks down at the ground and marks the exit spot

Head turned to the port screen: the flank camera shows the walker's own front leg and shoulder from outside; the hydraulic pressures are painted on that screen

When the link comes up after boarding, every feed starts as static. It isn’t a fixed noise image: each frame picks new bands of random height, each with its own grain size, sideways tear and brightness, in navy, cyan and white, with a few bright bars rolling at random speeds. The picture fades in through it while the boot text runs.

The feeds coming up after boarding: banded blue static on all five screens with the first lines of the boot text on the centre screen

Motion through the seat

Screen shake as a random offset tells the player that something happened, but not what. In the cabin, the head is a damped spring pushed by what the hull actually does. The demo differentiates the seat position twice, rotates the result into the cabin’s frame, and lets inertia do the rest (walker_demo.gd):

# head: lags the cabin (inertia), leans out of turns, nods with surges
var ks := 55.0
head_vel += (-ks * head_off - 2.0 * 0.45 * sqrt(ks) * head_vel - a_local * 0.012 * k) * delta
head_off += head_vel * delta
var push := Vector3(a_local.z * 0.012, 0.0, -a_local.x * 0.012 + walker.yaw_rate * walker.speed * 0.05) * k
head_rot_vel += (-kr * head_rot - 2.0 * 0.4 * sqrt(kr) * head_rot_vel + push * kr * 0.1) * delta

On top of that, each footfall adds an impulse that depends on which corner landed: roll towards its side, pitch towards its end, a short drop. The hull’s own spring and the head’s spring then ring against each other, so a stride reads as a rhythm, not as noise. A collision with a ruin throws the head forward and tears every feed; kneeling and standing up add a servo rumble.

Several things are switchable in the demo for testing: shake strength (×0.6 is the default after playtesting), and three steering modes. In look-led the hull turns slowly towards where the pilot looks and the head settles back forward as it turns. In WASD turn the mouse only looks, and direct mouse turns the hull with the mouse. Middle mouse toggles a free look that doesn’t steer.

Measurements

Frame times from the demo’s --bench mode (the same scripted sequence each run), RTX 3060 Laptop GPU, 1600×900 window, vsync off, 6 s per situation after 1 s to settle:

Situation Frames Mean 95th percentile
On foot, walker idle 1805 3.32 ms 5.34 ms
Cockpit, standing 583 10.30 ms 12.92 ms
Cockpit, walking 582 10.31 ms 12.99 ms
Third person, walking 1649 3.64 ms 5.57 ms

The cockpit costs about 7 ms because four cameras render the world (1600×940, two at 860×720 and 800×400), each with shadows and ambient occlusion. Walking itself (gait, IK, particles) adds about 0.3 ms over standing.

Where it goes next

The walker lives in its own scene next to the map viewer, so it could be developed while other work on the viewer went on. The next step is to bring it into the main project, and the plan is written down with the inventory of files:

  • The switch between modes. The walker and the lantern camera never run together: boarding turns the lantern’s line-of-sight cube and cutaway off, arriving at a ruin parks the walker and hands back. That switch is the real integration point. The rest is bookkeeping: the walker’s physics bits move off the viewer’s per-material collision bits.
  • Ground from the streamed world. The demo’s feet fall back to an analytic height function. In the real world they ray-cast streamed collision, which has to be kept ready around the walker, not only around the player.
  • Shading. The main world is unshaded and lit by the lantern and a daylight term; the walker uses a real sun. On the surface the directions already match; one side has to adopt the other.
  • The cockpit’s cost. Lower feed resolutions, no shadows or ambient occlusion on the flank and belly cameras, and side feeds every other frame should take most of the 7 ms back.

After that: real destinations from the overworld plan for the waypoint, sound for footfalls and servos, and the cargo pack as an inventory.