# Animation System Architecture

Mechanica needs physically believable looping animations while keeping the core player unaware of machine-specific mechanics. The architecture is based on small machine animation modules that implement a shared interface.

## Goals

- One player UI for all machines.
- Machine-specific kinematics live outside core viewer controls.
- Deterministic loop behavior.
- RPM and time-scale support.
- Step-through support.
- Guided-tour integration.
- Future GSAP timeline support for camera and annotation choreography.

## Implemented contract location

The TypeScript contracts are in:

```text
src/animations/types.ts
```

## Core concepts

### Animation module

A module is registered per machine ID and exports a factory:

```ts
export interface MachineAnimationModule {
  machineId: string;
  createController(): MachineAnimationController;
}
```

### Controller lifecycle

```text
initialize(context)
reset()
play()
pause()
step(stepSize)
update(deltaSeconds, controls)
dispose()
```

`initialize` receives Object3D references after the model adapter has loaded and mapped registry part IDs.

### Runtime context

The runtime context includes:

- Root `Object3D`
- Part map keyed by registry part ID
- Clock
- Optional telemetry sink

This lets animation modules find named parts without importing React or Zustand.

### Playback controls

The standard playback input includes:

- `isPlaying`
- `rpm`
- `timeScale`
- `cycleStepIndex`
- `reducedMotion`

The UI writes these values to `viewerStore`; a future animation runner will pass them to the active controller on each frame.

## Machine-specific examples

### Four-stroke petrol engine

The module would animate:

- Crankshaft: 720 degrees per complete cycle.
- Piston: sinusoidal slider-crank motion with connecting rod correction.
- Camshaft: half crank speed.
- Intake valve: open during intake stroke.
- Exhaust valve: open during exhaust stroke.
- Spark plug highlight: near top dead center before combustion.

The UI still only sees play/pause/RPM/time-scale.

### Planetary gearbox

The module would animate:

- Sun, planets, carrier, and ring according to selected input/output constraints.
- Gear tooth direction based on gear ratio.
- Optional torque-flow highlight.

### Geneva drive

The module would animate:

- Continuous driver rotation.
- Intermittent driven wheel indexing.
- Dwell periods with no driven motion.
- Pin engagement highlighting.

## Time model

Use normalized cycle time for loop correctness:

```text
normalizedTime = (elapsedCycleSeconds / cycleSeconds) % 1
```

RPM converts to angular velocity:

```text
revolutionsPerSecond = rpm / 60
angularVelocity = revolutionsPerSecond * 2π
```

Machines with multi-revolution thermodynamic cycles, such as four-stroke engines, define the relationship between crank revolutions and cycle completion in their own module metadata.

## Step-through mode

Step-through should pause playback and increment `cycleStepIndex`. Each machine registry entry declares named cycle steps with normalized timestamps. Controllers can seek to the nearest normalized timestamp.

## Guided tours

Guided tours combine:

- Camera preset or explicit camera move.
- Highlighted part IDs.
- Caption text.
- Optional playback state changes.
- Optional timeline easing.

The registry stores content and camera intent. Animation modules expose seek/highlight functions. A future tour runner should orchestrate them without embedding content in animation code.

## GSAP usage

GSAP is reserved for timeline orchestration where deterministic tweens are preferable:

- Guided-tour camera moves.
- Exploded view transitions beyond simple scalar separation.
- Annotation reveal sequences.
- Cutaway plane movement.

Machine kinematics should remain math-based in frame updates rather than long hand-authored timelines, unless the mechanism is inherently staged.
