144 lines
3.8 KiB
Markdown
144 lines
3.8 KiB
Markdown
# 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<string, number>
|
|
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`.
|