feat: Figurenauswahl, Autos, Debug-Panel und Namensnennung

Task 11: Figuren (Mannequin/Superhero Male/Female) mit auf ual.glb
retargeteten Animationen, Frisuren, vier SUVs auf angehefteten Chunks,
ein lil-gui-Debug-Panel (Figur/Frisur/Höhe/Hitbox/Chunk-Grenzen/
Kartenbild/Nebel/Wahrzeichen-Sprung) und die verpflichtende
Namensnennung fürs HUD (Kartenkacheln, Wahrzeichen, SUV, Texturen,
Palme, Figuren — jede Quelle mit ihrer eigenen Lizenz).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-13 03:04:49 +02:00
1 parent 02d0f36580
commit d30aae68a1
42 files changed
+13143 -4

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
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);
});
});