3.8 KiB
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
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
type BoneMapErrorCode =
| 'BONE_MAP_NO_BONES'
| 'BONE_MAP_MATCH_FAILED'
| 'BONE_MAP_RETARGET_FAILED'
| 'BONE_MAP_INVALID_BIND_POSE'
New additions for genesis
- Fuzzy bone matching — Levenshtein distance + anatomical keyword boosts (
spine,arm,leg,hand,foot). - Humanoid auto-detect — classify skeleton as Humanoid if ≥ 60% of canonical human bone names match within edit distance 2.
- Retarget matrix —
R_target = T_offset * R_source * T_offset^-1whereT_offset = target_bind * inverse(source_bind).
File layout
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.