# OpenSpec Change: enterprise-gaming-mixamo - **Change ID**: enterprise-gaming-mixamo - **Package**: `@suaveplan/mixamo` - **Category**: gaming/rigs - **Target path**: `gaming/rigs/mixamo` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/mixamo.md` --- ## Summary Deliver `@suaveplan/mixamo` on the genesis branch from scratch at enterprise quality. The package provides Mixamo character utilities: skeleton normalisation (canonical bone name mapping), T-pose extraction, animation clip retargeting from Mixamo rig to arbitrary target skeletons, and root-motion extraction. These are pure math utilities with no Three.js dependency — the R3F integration layer lives in `@suaveplan/r3f-animation`. Genesis adds Zod schemas for bone maps and clip descriptors, structured errors, and 100% coverage. --- ## Current-state audit (genesis) Package does not exist on genesis yet — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `MixamoError`; `MIXAMO.*` codes | | `@suaveplan/types` (`workspace:^`) | Shared primitives | | `@suaveplan/bone-mapping` (`workspace:^`) | Skeleton detection and retargeting math | | `zod` (`catalog:forms`) | Bone map + clip schemas | | `@opentelemetry/api` (`catalog:observability`) | Retarget duration span | --- ## Public API surface ```ts // Canonical Mixamo bone names → target bone names const MIXAMO_BONE_NAMES: readonly string[] function normalizeMixamoSkeleton(bones: BoneDescriptor[]): NormalizedSkeleton interface NormalizedSkeleton { bones: BoneDescriptor[] boneIndexByName: Map tPose: BonePose[] } interface BoneDescriptor { name: string parentIndex: number // -1 for root localPosition: Vec3 localRotation: Quat } interface BonePose { boneIndex: number position: Vec3 rotation: Quat } // Animation clip interface AnimationClip { name: string duration: number tracks: AnimationTrack[] } interface AnimationTrack { boneName: string times: Float32Array positions?: Float32Array // xyz per keyframe rotations?: Float32Array // xyzw per keyframe } function extractRootMotion(clip: AnimationClip, rootBoneName?: string): RootMotionData interface RootMotionData { positions: Float32Array // xyz per keyframe rotations: Float32Array // xyzw per keyframe strippedClip: AnimationClip // root motion removed from tracks } ``` ### Error codes ```ts type MixamoErrorCode = | 'MIXAMO_BONE_NOT_FOUND' | 'MIXAMO_INVALID_SKELETON' | 'MIXAMO_RETARGET_FAILED' | 'MIXAMO_CLIP_INVALID' ``` --- ## New additions for genesis 1. **Canonical bone map** — 65-entry `MIXAMO_BONE_NAMES` table matching Adobe Mixamo's naming convention. 2. **T-pose extraction** — derives rest pose from first frame of a T-pose clip or from bind pose. 3. **Root motion extraction** — strips horizontal XZ translation and yaw from root track; returns both stripped clip and motion data. 4. **OTel** — `mixamo.normalise_duration_ms` span; `mixamo.retarget_duration_ms` span. --- ## File layout ```text gaming/rigs/mixamo/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/ index.ts # MIXAMO_BONE_NAMES types/common.ts types/common.md core/ normalise/ normalise.ts normalise.md normalise.types.ts normalise.test.ts index.ts root-motion/ root-motion.ts root-motion.md root-motion.types.ts root-motion.test.ts index.ts tests/ integration.test.ts ``` --- ## Impact **Downstream**: `@suaveplan/r3f-animation` uses `normalizeMixamoSkeleton` and `extractRootMotion`. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/bone-mapping`.