Files
2026-05-27 23:29:53 +01:00

153 lines
3.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`.