"""UE integration: teaching orbit, two-clip starter and complete animation catalogs.""" import json import math import runpy from ue_workshop import Renderer from ue_workshop.paths import PROJECT from ue_workshop.characters import FIGHTER_MODEL, CREATURE_MODEL, _clips fighter_clips, creature_clips = _clips(FIGHTER_MODEL), _clips(CREATURE_MODEL) basics = runpy.run_path(str(PROJECT / "exercises/basics.py")) shot = basics["shot"] assert shot.frames == 192 channels = shot._transforms[basics["cam"].get_path_name()] x = [key.get_value() for key in channels[0].get_keys()] y = [key.get_value() for key in channels[1].get_keys()] yaw = [key.get_value() for key in channels[5].get_keys()] assert len(x) == shot.frames == len(yaw) assert abs(yaw[-1] - yaw[0] - 360) < 0.001 assert all(b > a for a, b in zip(yaw, yaw[1:])), "Camera reverses direction" assert abs(x[0] - x[-1]) < 0.001 and abs(y[0] - y[-1]) < 0.001 assert all(abs(math.hypot(px, py) - basics["radius"]) < 0.01 for px, py in zip(x, y)) starter = runpy.run_path(str(PROJECT / "exercises/animation_starter.py")) assert starter["shot"].frames == 360 models = starter["scene"]._skeletal_models assert len(models) == 1 assert set(next(iter(models.values()))[1].animations) == {"mutant_idle", "mutant_swiping"} example = runpy.run_path(str(PROJECT / "examples/mixamo_characters.py")) for actor_name, clips in (("fighter", fighter_clips), ("creature", creature_clips)): actor = example[actor_name] child, imported = example["scene"]._skeletal_models[actor.get_path_name()] assert set(imported.animations) == set(clips) assert all(clip.get_editor_property("sequence_length") > 0 for clip in imported.animations.values()) summary = {"fighter_clips": len(fighter_clips), "creature_clips": len(creature_clips), "orbit_frames": basics["shot"].frames, "starter_frames": starter["shot"].frames} (PROJECT / "Saved/Workshop/workshop_files_smoke.json").write_text(json.dumps(summary), encoding="utf-8") shot = example["shot"] renderer = Renderer(width=640, height=360, samples=1, warmup=0, mp4=False)