Initial Commit
This commit is contained in:
143
openspec/changes/enterprise-gaming-mixamo/proposal.md
Normal file
143
openspec/changes/enterprise-gaming-mixamo/proposal.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 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`.
|
||||
41
openspec/changes/enterprise-gaming-mixamo/tasks.md
Normal file
41
openspec/changes/enterprise-gaming-mixamo/tasks.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Tasks: enterprise-gaming-mixamo
|
||||
|
||||
## 0. Pre-flight (non-negotiable)
|
||||
|
||||
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
|
||||
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
|
||||
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
|
||||
|
||||
## Phase 1 — Scaffold
|
||||
|
||||
- [ ] Create `gaming/rigs/mixamo/` (`@suaveplan/mixamo`, `0.1.0`, `sideEffects: false`)
|
||||
- [ ] `tsconfig.json`, `vitest.config.ts`
|
||||
|
||||
## Phase 2 — Error codes & constants
|
||||
|
||||
- [ ] `src/error-codes.ts` — `MixamoError`, `MIXAMO.*` codes
|
||||
- [ ] `src/constants/index.ts` — `MIXAMO_BONE_NAMES` (65 entries), `MIXAMO_ROOT_BONE`
|
||||
|
||||
## Phase 3 — Types
|
||||
|
||||
- [ ] `src/types/common.ts` + `common.md`
|
||||
|
||||
## Phase 4 — Skeleton normalisation
|
||||
|
||||
- [ ] `src/core/normalise/normalise.ts` — `normalizeMixamoSkeleton`, T-pose extraction, bone index map
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 5 — Root motion
|
||||
|
||||
- [ ] `src/core/root-motion/root-motion.ts` — strip horizontal translation + yaw from root track, return `RootMotionData`
|
||||
- [ ] Tests + docs
|
||||
|
||||
## Phase 6 — Integration tests
|
||||
|
||||
- [ ] `tests/integration.test.ts` — normalise → extract root motion → verify stripped clip has no root translation
|
||||
|
||||
## Phase 7 — Pre-publish gate
|
||||
|
||||
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/mixamo` green
|
||||
- [ ] 100% coverage
|
||||
- [ ] Publish: `bun scripts/publish.ts --package @suaveplan/mixamo`
|
||||
Reference in New Issue
Block a user