# OpenSpec Change: enterprise-gaming-bone-mapping - **Change ID**: enterprise-gaming-bone-mapping - **Package**: `@suaveplan/bone-mapping` - **Category**: gaming/rigs - **Target path**: `gaming/rigs/bone-mapping` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/bone-mapping.md` --- ## Summary Deliver `@suaveplan/bone-mapping` on the genesis branch from scratch at enterprise quality. The package provides skeleton detection, bone matching by fuzzy name heuristics, and retargeting math — the foundation for animation clip transfer between different character rigs. `detectSkeleton` classifies a bone hierarchy as Mixamo/Humanoid/Custom; `matchBones` pairs source and target bones using edit-distance scoring with anatomical weight boosts; `retargetPose` transforms local-space bone rotations from source binding pose to target binding pose using the standard retargeting matrix `R_target = T_offset * R_source * T_offset^-1`. Genesis adds Zod schemas, structured errors, and property-based correctness tests. --- ## Current-state audit (genesis) Package does not exist on genesis yet — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `BoneMappingError`; `BONE_MAP.*` codes | | `@suaveplan/types` (`workspace:^`) | Shared primitives | | `zod` (`catalog:forms`) | Bone map result schemas | | `@opentelemetry/api` (`catalog:observability`) | Detection + match spans | --- ## Public API surface ```ts type SkeletonType = 'mixamo' | 'humanoid' | 'custom' function detectSkeleton(bones: BoneDescriptor[]): SkeletonType function matchBones( source: BoneDescriptor[], target: BoneDescriptor[], options?: MatchOptions ): BoneMatch[] interface MatchOptions { minConfidence?: number // 0–1, default 0.5 preferExact?: boolean } interface BoneMatch { sourceBone: string targetBone: string confidence: number } function retargetPose( sourcePose: BonePose[], boneMatches: BoneMatch[], sourceBindPose: BonePose[], targetBindPose: BonePose[] ): BonePose[] function buildRetargetMatrix( sourceBind: Quat, targetBind: Quat ): RetargetMatrix interface RetargetMatrix { apply(rotation: Quat): Quat } interface BoneDescriptor { name: string parentIndex: number localPosition: Vec3 localRotation: Quat } interface BonePose { boneIndex: number position: Vec3 rotation: Quat } ``` ### Error codes ```ts type BoneMapErrorCode = | 'BONE_MAP_NO_BONES' | 'BONE_MAP_MATCH_FAILED' | 'BONE_MAP_RETARGET_FAILED' | 'BONE_MAP_INVALID_BIND_POSE' ``` --- ## New additions for genesis 1. **Fuzzy bone matching** — Levenshtein distance + anatomical keyword boosts (`spine`, `arm`, `leg`, `hand`, `foot`). 2. **Humanoid auto-detect** — classify skeleton as Humanoid if ≥ 60% of canonical human bone names match within edit distance 2. 3. **Retarget matrix** — `R_target = T_offset * R_source * T_offset^-1` where `T_offset = target_bind * inverse(source_bind)`. --- ## File layout ```text gaming/rigs/bone-mapping/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/index.ts types/common.ts types/common.md core/ detect/ detect.ts detect.md detect.test.ts index.ts match/ match.ts match.md match.test.ts index.ts retarget/ retarget.ts retarget.md retarget.types.ts retarget.test.ts index.ts utils/ quat-math.ts quat-math.md quat-math.test.ts tests/ property.test.ts ``` --- ## Impact **Downstream**: `@suaveplan/mixamo` imports `detectSkeleton` and `retargetPose`; `@suaveplan/ik-solver` uses quaternion math from utils. Prerequisites: `@suaveplan/error`, `@suaveplan/types`.