Kucraft game assets and free examples
KUCRAFT · ANIMATION FIELD NOTE 01
The ankle stays put.
Why does the knee swing sideways?
A procedural leg can hit both target poses and still twist between them. In this two-bone example, the ankle barely moves sideways, while the knee drifts 5.24 mm out of its intended plane. The cause is the way each bone’s orientation was constructed.
This small reproduction came from fixing an original character rig. It isolates the mechanism using two 30 cm bones, two keyframes and no character model. You can inspect every input and rerun the measurements.
Scroll the chart horizontally on narrow screens. 101 samples per version, including both keys. Each sample interpolates local translations, rotations and scales, then composes the parent and child transforms. Values come from the included CSV.
Reproduce it in two steps
Download the complete example — ZIP, 101 kB. Includes the guide, editable source, recorded measurements and native Godot project. Free under the MIT licence.
You have the complete example: this guide, source, input transforms, measured output and the Godot extension. See README.txt to choose the mathematical or native engine route. No sign-up or external assets are needed.
blender --background --factory-startup --threads 2 --python reproduce.py
python3 measure.py
The first command uses Blender’s mathutils to write output/endpoints.json. The second uses only the Python standard library to evaluate the two-key animation and write report.json, samples.csv and the chart. Blender 4.5.14 LTS was used for the recorded run. The saved JSON lets you run the second step without Blender.
The missing information is roll
A head and tail specify a bone’s direction. They leave its rotation around that direction undetermined. This fixture points each local Y axis along its bone and asks to_track_quat('Y', 'Z') to choose the remaining orientation. The leg moves from one degree either side of vertical to the other. Near the chosen up direction, the resulting thigh frames differ by almost 180 degrees.
The child shin compensates at the endpoints, so the joint positions look right there. Between those endpoints, interpolating the local rotations sends the knee sideways. A check that watches only the ankle would miss this example.
The measurement script uses shortest-path quaternion interpolation and treats opposite quaternion signs as the same rotation. That still leaves a real, almost half-turn change in the authored thigh frame. glTF’s animation sampler guidance calls for spherical interpolation when a LINEAR sampler targets a rotation. The discontinuity here is already present in the supplied transforms.
Choose a stable transverse axis
For this planar leg, X is always transverse to the intended motion. Project that reference axis onto the plane perpendicular to the bone direction, then build an orthonormal frame. The generated orientation now changes by two degrees between the keys.
# head, tail and reference_x use the same coordinate frame.
# reference_x must be a unit vector.
direction = tail - head
if direction.length < 1e-8:
raise ValueError("Head and tail must differ")
y = direction.normalized()
x = reference_x - y * reference_x.dot(y)
if x.length < 0.1:
raise ValueError("Reference axis is too close to the bone direction")
x.normalize()
z = x.cross(y).normalized()
rotation = Matrix((x, y, z)).transposed()
pose = Matrix.Translation(head) @ rotation.to_4x4()
In a procedural rig, a bone’s rest X axis can supply the reference when it stays suitably transverse throughout the intended motion. This example uses Vector((1, 0, 0)). Keep the guard: a fixed reference axis also becomes ambiguous when the bone points along it. More general motion needs a deliberately continuous frame strategy; choosing a different fallback axis independently at each key can introduce another jump.
What changed in this example
These are results for this constructed fixture. The fixed version straightens the leg between the bent endpoints, so its ankle height changes slightly; the fix preserves the intended motion plane, rather than enforcing a planted-foot constraint.
The same path after a real glTF import
Version 1.1.0 adds two original GLB files and a small Godot project. Each GLB contains two rigid-weighted box segments, two joints and a two-key animation. Open native-example/godot/project.godot in Godot and run the scene to compare them. The slider and Play/Pause button control native animation; the knee readouts come from the imported skeleton.
Actual Linux Godot 4.7.2 midpoint render using Mesa llvmpipe on the CPU. The geometry is shown at true spatial scale, so the small bend is easier to quantify in the chart above. The animation is slowed 96 times for inspection.
The GLB animation lasts two seconds instead of 1/48 second, with the same endpoint transforms and LINEAR samplers. At 101 positions per version, Godot reproduced the 5.236 mm sideways knee excursion and the fixed version's planar motion. Every compared knee and ankle coordinate agreed with the separate Python evaluator within 0.001 mm. The largest observed component difference was 0.000234 mm.
The script uses GLTFDocument with a bake rate of 30 and immutable tracks retained, then updates AnimationPlayer explicitly while sampling. Skeleton bone poses are transformed into world coordinates before comparison. See the native example instructions for the exact commands and limits.
python3 native-example/build_glb.py
godot --headless --path native-example/godot --script measure_native.gd
python3 native-example/compare_native.py
This checks the included fixture's runtime import and playback. It does not test the original-speed clip through every editor import setting, other engines, or general character deformation. Actual renders at both endpoints and the midpoint were inspected. Programmatic scrub/play/pause paths passed; human pointer and keyboard use remains untested.
Scope and reuse
This package isolates one orientation-construction problem with a separate Python evaluator and a matching native Godot example. It is not a general rig repair tool, foot-plant constraint or performance benchmark. Engine import resampling and optimisation remain separate variables to check on your final asset. Linux Godot 4.7.2 is the only engine and platform combination tested here.
The guide, code, simple geometry and animation were generated with AI and checked with executable measurements and native renders. No third-party character, motion capture or paid asset is included. The source and example data are available under the included MIT licence.