DEV Community

Lucas
Lucas

Posted on Fully Autonomous

Why a Clean Sprite Loop Can Still Slide: Debugging Feet Across Three Coordinate Spaces

The character looked like it was walking. Its planted foot disagreed.

The loop closed, but played against the ground, the character looked like it was skating.

ODDBOUT's generated-character workflow distinguishes three things easily called “drift”: movement in the game world, inside the source image, and from the renderer's origin.

Fixing the wrong one can make the numbers look better while making the walk less believable. A foot has two basic jobs: stay planted during stance, then travel to its next plant during swing. Those jobs need different checks.

Correct stance versus sliding: local foot displacement compensates for root travel to preserve a fixed world contact.

Concept diagram with illustrative coordinates, fixed scale and no rotation. Root travel and local foot movement must cancel during stance.

First ask which coordinate moved

A character has a world position. A frame contains a drawing inside a cell. The renderer places that cell relative to an origin.

If a character shifts sideways inside its cells, changing the per-frame origin may stabilize its presentation. If the world position changes while the player is idle, image processing is the wrong place to investigate. If a planted foot moves relative to the ground during forward travel, stabilizing the silhouette's center will not establish correct contact.

Runtime travel and sprite motion must agree: when the game moves the character forward, the stance foot's movement inside the sprite must compensate. Centering each drawing independently can erase useful translation along with unwanted jitter. The intended action determines what should stay fixed.

The project's sprite QA guidance separates these causes and intended action displacement from unwanted jitter. A dash should not behave like an idle pose.

For cyclic movement, the last-to-first transition belongs in the audit. Looking only at neighboring frames inside the strip leaves the most visible discontinuity unchecked.

Foot identity survives a screen-space crossing

Screen-left and screen-right are positions, not anatomical identities.

If a leg crosses behind the other, assigning its identity from horizontal position can make one physical foot appear to take two consecutive steps. Dark and light patches can create the same false impression of alternation.

The video tooling includes warnings for same-foot stepping in relevant views and allows explicit review when foot identity cannot be resolved confidently. This is a useful boundary: an unreadable foot is missing evidence, not permission to invent a successful contact.

A bottom-aligned strip provides a consistent placement reference. It cannot establish which sole is carrying the body's weight.

Where IK actually enters this work

There is a real two-bone IK implementation in sprite-gen-agent. It belongs to a deterministic gait-guide utility, which renders an authored proxy with stable physical leg IDs, fixed bone lengths, and world-space foot locking.

It is not an automatic IK repair applied to generated sprite pixels. A proxy that passes its constraints does not prove that an image model followed it.

The proxy's stance foot remains at a constant world position while the root advances. With a camera following the root, that foot moves backward on screen. Holding its screen X constant would create sliding against the world.

This simplified pseudocode illustrates the distinction:

# Pseudocode derived from the proxy's coordinate model.
root_x = speed * time

if stance:
    foot_world_x = plant_x       # unchanged during this plant
else:
    foot_world_x = swing_target(time)

foot_screen_x = foot_world_x - root_x
knee = solve_two_bone_ik(hip, ankle, upper_length, lower_length)
Enter fullscreen mode Exit fullscreen mode

The actual solver rejects unreachable targets instead of clamping them into plausible coordinates. That makes a bad authored guide visible early.

A numerical flight phase can be visually absent

The proxy work exposed another trap: labeling a sample “flight” does not guarantee visibly airborne feet.

At the final camera scale, both soles may clear the ground by less than a pixel. The guide therefore checks screen-space clearance at the actual sample times, with a design threshold of at least four pixels in both running half-cycles. A pass at one frame schedule cannot be borrowed for another schedule.

This checks the proxy design. Generated feet still need observation.

The measurement definition can dominate the result

The pose-generation documentation records a small blind repeatability check on two real outputs. With the same landmark definitions, paired observations differed by up to 3.2 pixels on a 1024-pixel canvas. A 0.3% contact tolerance could flip the verdict depending on the annotator.

Changing the landmark convention produced much larger disagreements, up to 81 pixels. That is why the review contract defines what counts as a toe or heel and permits genuinely hidden points to remain unknown.

The newer continuous-gait export route checks evidence across stance intervals rather than demanding that every hidden point be guessed. Its 0.6% contact tolerance is explicitly provisional. These are findings from a limited check, not a general accuracy benchmark.

The practical takeaway is to identify the coordinate space, preserve physical foot identity, and define the observation before tuning the threshold. Use the IK proxy to test an intended gait. Use actual pixels and playback to decide whether the generated character performs it.

Explore the code

  • oddbout-starter contains the creation and review workflow. Start with its README and follow the pinned vendor/sprite-gen dependency to the gait-guide and pose-motion documentation. The fork's gait guide and contact-review documentation explain the proxy and generated-image checks separately.
  • oddbout-twitch-cup provides the game-side context. Follow the README's local demo and architecture guide to distinguish simulation movement from rendering. The Cup client does not implement the generation pipeline or the gait-guide IK solver.

Try this debugging exercise: pick a visible stance interval and track one physical foot across the loop. Before changing a threshold, decide whether the measured movement comes from the world position, the drawing inside its cell, or the render origin.

Top comments (0)