# Machine authoring guide

Mechanica’s machine catalogue is data-driven. New systems should be added by registering metadata, parts, animation logic, guided tours, and optional GLB assets without changing the core catalogue or viewer code.

## Machine package anatomy

A complete machine entry contains:

```text
src/modules/machines/<machine-slug>/
├── index.ts
├── metadata.ts
├── parts.ts
├── facts.ts
├── tour.ts
├── animation.ts
└── proceduralModel.tsx or asset.glb reference
```

The exact file split can vary, but the exported registry entry should remain stable.

## Registry entry shape

Recommended registry shape:

```ts
type MachineCategory = 'engines' | 'gearboxes' | 'pumps' | 'mechanisms' | 'structural';

type Difficulty = 'beginner' | 'intermediate' | 'advanced';

type MachineRegistryEntry = {
  slug: string;
  title: string;
  category: MachineCategory;
  difficulty: Difficulty;
  complexity: number;
  createdAt: string;
  keywords: string[];
  thumbnail: string;
  description: string;
  facts: EngineeringFact[];
  parts: MachinePartDefinition[];
  related: string[];
  scene: MachineSceneDefinition;
  animation: MachineAnimationDefinition;
  tour: GuidedTourStep[];
};
```

Required constraints:

- `slug` is lowercase kebab-case and stable forever.
- `related` contains only existing slugs.
- `parts[].id` is unique within the machine.
- Every guided tour highlight references a valid part ID.
- Every animation channel references a valid part ID or object key.
- `createdAt` uses ISO date format.

## Part metadata

Each selectable part needs enough information for list controls, tooltips, annotations, and the detail drawer.

```ts
type MachinePartDefinition = {
  id: string;
  name: string;
  description: string;
  materialHint?: string;
  defaultVisible: boolean;
  defaultOpacity: number;
  color?: string;
  tags: string[];
  specs?: Record<string, string | number>;
  annotation?: {
    label: string;
    localPosition: [number, number, number];
  };
  explodedOffset?: [number, number, number];
};
```

Authoring rules:

- Keep `defaultOpacity` between `0` and `1`.
- Use human-readable `name` values; do not expose internal mesh names in UI.
- Put engineering claims in `specs` or `facts`, not only in descriptions.
- Use `explodedOffset` directions that separate components without hiding critical relationships.

## Engineering facts

Facts should be concise and comparable across machines.

```ts
type EngineeringFact = {
  label: string;
  value: string;
  unit?: string;
  note?: string;
};
```

Common facts:

- Typical RPM range
- Efficiency range
- Invention date or era
- Common applications
- Primary materials
- Pressure ratio, torque ratio, or reduction ratio
- Lubrication/cooling requirement

## Scene source

A machine can be rendered from either a procedural React Three Fiber component or a GLB asset.

```ts
type MachineSceneDefinition =
  | {
      kind: 'procedural';
      component: React.LazyExoticComponent<React.ComponentType<MachineSceneProps>>;
    }
  | {
      kind: 'asset';
      url: string;
      scale?: number;
      rotation?: [number, number, number];
      position?: [number, number, number];
      partMeshMap: Record<string, string[]>;
    };
```

For asset-based machines, `partMeshMap` maps part IDs to mesh node names inside the GLB. Mesh names should be stable and descriptive in the DCC tool before export.

## Animation module interface

Every machine animation module should implement the same control interface so the player does not contain machine-specific logic.

```ts
type MachineAnimationContext = {
  elapsedSeconds: number;
  deltaSeconds: number;
  cyclePhase: number;
  rpm: number;
  timeScale: number;
  playback: 'playing' | 'paused' | 'stopped';
  partObjects: Map<string, THREE.Object3D>;
};

type MachineAnimationDefinition = {
  cycleDurationSeconds: number;
  minRpm: number;
  maxRpm: number;
  defaultRpm: number;
  stepCount: number;
  labels: string[];
  update(context: MachineAnimationContext): void;
  reset?(partObjects: Map<string, THREE.Object3D>): void;
};
```

Rules:

- Animation loops must be continuous at phase `0` and phase `1`.
- Use radians for rotation values.
- Use physically plausible relationships: piston/crank/cam ratios, gear ratios, valve timing, and phase offsets.
- Do not update React state every frame.
- Keep allocations out of per-frame update paths.

## Guided tour steps

```ts
type GuidedTourStep = {
  id: string;
  title: string;
  body: string;
  durationSeconds: number;
  cameraPreset?: 'front' | 'back' | 'left' | 'right' | 'top' | 'isometric';
  cameraPosition?: [number, number, number];
  target?: [number, number, number];
  highlightPartIds: string[];
  animationState?: {
    playback?: 'playing' | 'paused';
    rpm?: number;
    timeScale?: number;
  };
};
```

A strong tour:

1. Starts with the complete system.
2. Introduces energy or motion input.
3. Walks through key conversion stages.
4. Highlights timing or control elements.
5. Ends with practical applications and limitations.

## Adding a new machine

1. Choose a stable slug.
2. Create the machine folder.
3. Add metadata, facts, and part definitions.
4. Build the procedural scene or export and optimize a GLB.
5. Implement the animation module.
6. Add guided tour steps.
7. Add a thumbnail and social image if needed.
8. Register the machine in the central registry.
9. Add related machine slugs.
10. Run:
   ```bash
   npm run typecheck
   npm run test
   npm run build
   ```
11. Manually inspect:
   - catalogue card
   - search/filter results
   - part list
   - viewer interactions
   - animation loop
   - exploded view
   - share URL
   - mobile layout

## Quality checklist for new machines

- The title and one-paragraph description are clear to a beginner.
- Difficulty matches the amount of prerequisite knowledge.
- Every selectable mesh has metadata.
- Hover and selection outlines are easy to see against the material.
- Exploded view reveals internal layout without scattering parts excessively.
- Wireframe and cross-section modes remain intelligible.
- Animation can run at minimum and maximum RPM without visual discontinuities.
- The guided tour can be completed with reduced motion enabled.
- Related machines create a meaningful learning path.
- Asset size stays within the budgets in the asset pipeline document.
