164 lines
4.0 KiB
Markdown
164 lines
4.0 KiB
Markdown
# OpenSpec Change: enterprise-gaming-ik-solver
|
|
|
|
- **Change ID**: enterprise-gaming-ik-solver
|
|
- **Package**: `@suaveplan/ik-solver`
|
|
- **Category**: gaming/rigs
|
|
- **Target path**: `gaming/rigs/ik-solver`
|
|
- **Status**: PROPOSED
|
|
- **Date**: 2026-04-24
|
|
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/ik-solver.md`
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Deliver `@suaveplan/ik-solver` on the genesis branch from scratch at enterprise quality. The package provides pure-math inverse kinematics solvers: two-bone analytic IK (arm/leg chains), look-at (head/eye), and multi-chain FABRIK for arbitrary-length chains. No Three.js dependency — callers pass `Vec3`/`Quat` structs and receive solved bone rotations. Genesis adds configurable iteration limits, convergence thresholds, Zod chain config schemas, structured errors, OTel solve-time histogram, and 100% coverage with property tests for geometric correctness.
|
|
|
|
---
|
|
|
|
## Current-state audit (genesis)
|
|
|
|
Package does not exist on genesis yet — fresh build.
|
|
|
|
---
|
|
|
|
## Available workspace deps on genesis
|
|
|
|
| Package | Role |
|
|
|---|---|
|
|
| `@suaveplan/error` (`workspace:^`) | `IkSolverError`; `IK.*` codes |
|
|
| `@suaveplan/types` (`workspace:^`) | Shared primitives |
|
|
| `zod` (`catalog:forms`) | Chain config schemas |
|
|
| `@opentelemetry/api` (`catalog:observability`) | Solve duration histogram, iteration count gauge |
|
|
|
|
---
|
|
|
|
## Public API surface
|
|
|
|
```ts
|
|
// Two-bone analytic IK (arm/leg)
|
|
function solveTwoBone(chain: TwoBoneChain, target: Vec3, hint?: Vec3): TwoBoneSolution
|
|
|
|
interface TwoBoneChain {
|
|
root: Vec3
|
|
mid: Vec3
|
|
tip: Vec3
|
|
upperLength: number
|
|
lowerLength: number
|
|
}
|
|
|
|
interface TwoBoneSolution {
|
|
upperRotation: Quat
|
|
lowerRotation: Quat
|
|
reached: boolean
|
|
}
|
|
|
|
// Look-at IK
|
|
function solveLookAt(
|
|
bonePosition: Vec3,
|
|
boneForward: Vec3,
|
|
boneUp: Vec3,
|
|
target: Vec3,
|
|
clampAngle?: number // max angle in radians
|
|
): Quat
|
|
|
|
// FABRIK multi-chain
|
|
function solveFabrik(chain: FabrikChain, options?: FabrikOptions): FabrikSolution
|
|
|
|
interface FabrikChain {
|
|
joints: Vec3[]
|
|
lengths: number[]
|
|
target: Vec3
|
|
root?: Vec3 // if set, root is constrained to original position
|
|
}
|
|
|
|
interface FabrikOptions {
|
|
maxIterations?: number // default 10
|
|
tolerance?: number // convergence threshold, default 0.001
|
|
constraints?: JointConstraint[]
|
|
}
|
|
|
|
interface JointConstraint {
|
|
jointIndex: number
|
|
minAngle: number
|
|
maxAngle: number
|
|
axis: Vec3
|
|
}
|
|
|
|
interface FabrikSolution {
|
|
joints: Vec3[]
|
|
rotations: Quat[]
|
|
iterations: number
|
|
converged: boolean
|
|
}
|
|
|
|
// Utility: build chain from bone descriptors
|
|
function chainFromBones(bones: BoneDescriptor[], indices: number[]): FabrikChain
|
|
```
|
|
|
|
### Error codes
|
|
|
|
```ts
|
|
type IkErrorCode =
|
|
| 'IK_CHAIN_TOO_SHORT'
|
|
| 'IK_DEGENERATE_CHAIN'
|
|
| 'IK_MAX_ITERATIONS_EXCEEDED'
|
|
| 'IK_INVALID_CONSTRAINT'
|
|
```
|
|
|
|
---
|
|
|
|
## New additions for genesis
|
|
|
|
1. **Hint vector for two-bone** — optional pole-vector hint controls elbow/knee direction.
|
|
2. **Joint constraints in FABRIK** — hinge and cone constraints applied per iteration.
|
|
3. **OTel** — `ik.solve_duration_ms` histogram; `ik.iterations` histogram.
|
|
4. **Property tests** — two-bone: tip distance from target ≤ tolerance after solve; look-at: resulting forward aligns with target direction.
|
|
|
|
---
|
|
|
|
## File layout
|
|
|
|
```text
|
|
gaming/rigs/ik-solver/
|
|
package.json
|
|
tsconfig.json
|
|
vitest.config.ts
|
|
src/
|
|
index.ts
|
|
error-codes.ts
|
|
constants/index.ts
|
|
types/common.ts
|
|
types/common.md
|
|
solvers/
|
|
two-bone/
|
|
two-bone.ts
|
|
two-bone.md
|
|
two-bone.types.ts
|
|
two-bone.test.ts
|
|
index.ts
|
|
look-at/
|
|
look-at.ts
|
|
look-at.md
|
|
look-at.test.ts
|
|
index.ts
|
|
fabrik/
|
|
fabrik.ts
|
|
fabrik.md
|
|
fabrik.types.ts
|
|
fabrik.test.ts
|
|
index.ts
|
|
utils/
|
|
vec3-math.ts
|
|
vec3-math.md
|
|
vec3-math.test.ts
|
|
tests/
|
|
property.test.ts
|
|
```
|
|
|
|
---
|
|
|
|
## Impact
|
|
|
|
**Downstream**: `@suaveplan/r3f-animation` uses these solvers for foot IK and hand IK; `@suaveplan/animation-events` uses look-at for gaze control. Prerequisites: `@suaveplan/error`, `@suaveplan/types`.
|