4.9 KiB
OpenSpec Change: enterprise-gaming-animation-events
- Change ID: enterprise-gaming-animation-events
- Package:
@suaveplan/animation-events - Category: gaming/rigs
- Target path:
gaming/rigs/animation-events - Status: PROPOSED
- Date: 2026-04-24
- Reference spec:
/mnt/s/web/suaveplan/enterprise/animation-events.md
Summary
Deliver @suaveplan/animation-events on the genesis branch from scratch at enterprise quality. The package provides animation event dispatching, foot contact detection, and procedural animation modifiers. An AnimationEventTrack associates named events with normalized animation times (0–1); an AnimationEventDispatcher fires @suaveplan/events messages when playback crosses event timestamps. FootContactDetector analyses Y-velocity of ankle bones to determine ground contact frames. Procedural modifiers (head bob, breathing sway, aim offset) compose additively. Genesis adds Zod schemas, structured errors, OTel event-count counter, 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:^) |
AnimationEventsError; ANIM_EVENT.* codes |
@suaveplan/types (workspace:^) |
Clock |
@suaveplan/events (workspace:^) |
Event bus for dispatching animation triggers |
@suaveplan/ik-solver (workspace:^) |
solveLookAt for aim-offset modifier |
zod (catalog:forms) |
Track and modifier schemas |
@opentelemetry/api (catalog:observability) |
Event dispatch counter |
Public API surface
// Event track
interface AnimationEvent {
name: string
normalizedTime: number // 0–1
data?: unknown
}
function createEventTrack(events: AnimationEvent[]): AnimationEventTrack
interface AnimationEventTrack {
getEvents(fromNorm: number, toNorm: number): AnimationEvent[]
readonly events: readonly AnimationEvent[]
}
// Dispatcher
function createAnimationEventDispatcher(options: DispatcherOptions): AnimationEventDispatcher
interface DispatcherOptions {
eventBus: EventBusLike
namespace?: string // event name prefix, default 'anim'
}
interface AnimationEventDispatcher {
update(clipName: string, track: AnimationEventTrack, normalizedTime: number, prevNormalizedTime: number): void
}
// Foot contact detection
function createFootContactDetector(options: FootContactOptions): FootContactDetector
interface FootContactOptions {
ankleThresholdY?: number // velocity below which foot is considered planted, default 0.05
sampleWindow?: number // frames to average, default 3
}
interface FootContactDetector {
update(leftAnkleY: number, rightAnkleY: number, dt: number): FootContactState
}
interface FootContactState {
leftGrounded: boolean
rightGrounded: boolean
leftPlantedAt?: Vec3
rightPlantedAt?: Vec3
}
// Procedural modifiers
interface ProceduralModifier {
update(dt: number, input: ModifierInput): BonePose[]
}
function createHeadBobModifier(options: HeadBobOptions): ProceduralModifier
function createBreathingModifier(options: BreathingOptions): ProceduralModifier
function createAimOffsetModifier(options: AimOffsetOptions): ProceduralModifier
Error codes
type AnimEventErrorCode =
| 'ANIM_EVENT_TRACK_EMPTY'
| 'ANIM_EVENT_INVALID_TIME'
| 'ANIM_EVENT_DISPATCH_FAILED'
New additions for genesis
- Looping event detection — dispatcher handles wrap-around (prevNorm > normTime) correctly, firing events in the wrapped range.
- Foot IK plant correction —
FootContactDetectoroutputs planted world positions; caller feeds into@suaveplan/ik-solverfor foot placement. - Aim offset modifier — uses
solveLookAtto rotate spine/neck toward aim target additively.
File layout
gaming/rigs/animation-events/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
constants/index.ts
types/common.ts
types/common.md
core/
event-track/
event-track.ts
event-track.md
event-track.types.ts
event-track.test.ts
index.ts
dispatcher/
dispatcher.ts
dispatcher.md
dispatcher.types.ts
dispatcher.test.ts
index.ts
foot-contact/
foot-contact.ts
foot-contact.md
foot-contact.types.ts
foot-contact.test.ts
index.ts
modifiers/
head-bob/
head-bob.ts
head-bob.md
head-bob.test.ts
index.ts
breathing/
breathing.ts
breathing.md
breathing.test.ts
index.ts
aim-offset/
aim-offset.ts
aim-offset.md
aim-offset.test.ts
index.ts
tests/
integration.test.ts
Impact
Downstream: @suaveplan/r3f-animation hooks these modifiers into Three.js AnimationMixer. Prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/ik-solver.