"""Verify a MIRPAMO output GLB: armature present, meshes skinned, animations present with real motion. Prints a JSON report; exit 1 on failure. Usage: blender -b --python bpy/verify_glb.py -- --in out/final.glb \ [--expect-anim] [--min-frames 10] """ import argparse import json import os import sys import bpy sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from common import (clean_scene, count_fcurves, die, find_armature, find_meshes, import_any, stage_args) def main(): ap = argparse.ArgumentParser() ap.add_argument("--in", dest="inp", required=True) ap.add_argument("--expect-anim", action="store_true") ap.add_argument("--min-frames", type=int, default=10) args = ap.parse_args(stage_args()) clean_scene() objs = import_any(args.inp) arm = find_armature(objs) meshes = find_meshes(objs) report = { "file": args.inp, "armature": arm.name if arm else None, "bones": len(arm.data.bones) if arm else 0, "meshes": [m.name for m in meshes], "skinned": [], "actions": {}, } if not arm: print(json.dumps(report, indent=2)) die("no armature in output") if not meshes: print(json.dumps(report, indent=2)) die("no meshes in output") for m in meshes: has_arm_mod = any(mod.type == "ARMATURE" for mod in m.modifiers) has_groups = len(m.vertex_groups) > 0 report["skinned"].append( {"mesh": m.name, "armature_mod": has_arm_mod, "vertex_groups": len(m.vertex_groups)}) if not (has_arm_mod and has_groups): print(json.dumps(report, indent=2)) die(f"mesh {m.name} is not skinned") for act in bpy.data.actions: fr = act.frame_range n_frames = int(fr[1] - fr[0]) + 1 report["actions"][act.name] = { "frames": n_frames, "fcurves": count_fcurves(act)} if args.expect_anim: good = [a for a, v in report["actions"].items() if v["frames"] >= args.min_frames and v["fcurves"] > 0] if not good: print(json.dumps(report, indent=2)) die(f"no action with >= {args.min_frames} frames found") print(json.dumps(report, indent=2)) print("[mirpamo] verify OK") main()