import { describe, expect, it } from "vitest"; import { AnimationClip, Quaternion, QuaternionKeyframeTrack, VectorKeyframeTrack } from "three"; import { retargetClips, teleportTargets } from "../src/characters/index.js"; const rest = (q) => new Map([["arm", { position: { x: 0, y: 1, z: 0 }, quaternion: q }]]); describe("retargetClips", () => { it("wirft konstante Positionsspuren weg", () => { const clip = new AnimationClip("a", 1, [ new VectorKeyframeTrack("arm.position", [0, 1], [0, 1, 0, 0, 1, 0]), new QuaternionKeyframeTrack("arm.quaternion", [0], [0, 0, 0, 1]), ]); const out = retargetClips([clip], rest(new Quaternion()), rest(new Quaternion())); expect(out[0].tracks.map((t) => t.name)).toEqual(["arm.quaternion"]); }); it("überträgt Rotationen relativ zur Ruhepose", () => { const src = new Quaternion().setFromAxisAngle({ x: 0, y: 1, z: 0 }, 0.3); const dst = new Quaternion().setFromAxisAngle({ x: 0, y: 1, z: 0 }, 0.9); const clip = new AnimationClip("a", 1, [ new QuaternionKeyframeTrack("arm.quaternion", [0], [src.x, src.y, src.z, src.w]), ]); const out = retargetClips([clip], rest(src), rest(dst)); const v = out[0].tracks[0].values; expect(new Quaternion(v[0], v[1], v[2], v[3]).angleTo(dst)).toBeLessThan(1e-6); }); }); describe("teleportTargets", () => { it("sortiert Wahrzeichen nach Höhe", () => { const targets = teleportTargets([ { name: "klein", xyz: [0, 0, 0], height: 30 }, { name: "groß", xyz: [10, 20, 0], height: 200 }, ]); expect(targets[0].name).toBe("groß"); expect(targets[0].z).toBe(-20); }); });