# Viewer Asset Pipeline and Loading System

## Supported asset forms

Mechanica supports two production asset forms in the viewer framework:

1. **Procedural assets** — TypeScript factories that generate a Three.js `Group` and part metadata.
2. **GLB/GLTF assets** — externally authored CAD/DCC exports loaded with Drei `useGLTF`.

Both forms must produce the same runtime contract:

```ts
interface LoadedMachineAsset {
  root: THREE.Group;
  metadata: MachineMetadata;
  parts: ViewerPart[];
  source: { kind: 'procedural' | 'gltf' | 'hybrid'; url?: string };
}
```

The shared viewer never branches on machine-specific logic after this point.

## Part metadata requirements

Each selectable component needs a stable part ID. The recommended convention is kebab-case:

```txt
sun-gear
planet-carrier
ring-gear
hydraulic-piston
```

Each part should define:

- `id`
- `name`
- `description`
- optional `material`
- optional `specs`
- optional `explodeDirection`
- optional `annotationPosition`
- optional `nodeNames` for GLTF matching

## GLB authoring requirements

For best results, model authors should:

- name meshes or empty groups after part IDs or entries in `nodeNames`
- keep machine origin near the functional centre
- apply transforms before export
- use real-world-ish units where 1 unit ≈ 1 metre
- keep individual selectable components as separate nodes
- avoid baking all parts into one mesh unless selection is not required
- use PBR metallic/roughness materials
- keep texture dimensions power-of-two where possible

## Compression

The framework exposes hooks for:

- Draco mesh compression (`dracoPath`)
- KTX2/Basis texture compression (`ktx2TranscoderPath`)
- Meshopt geometry compression (`meshopt`)

Recommended public folder layout:

```txt
public/
├─ assets/
│  └─ machines/
│     └─ planetary-gearbox/
│        ├─ model.glb
│        └─ preview.webp
├─ draco/
│  ├─ draco_decoder.js
│  ├─ draco_decoder.wasm
│  └─ draco_wasm_wrapper.js
└─ basis/
   ├─ basis_transcoder.js
   └─ basis_transcoder.wasm
```

## CDN deployment

Set:

```env
VITE_MECHANICA_ASSET_BASE_URL=https://cdn.example.com/mechanica/machines
```

A GLB definition created with `createGltfMachineAssetDefinition(metadata)` will then load:

```txt
https://cdn.example.com/mechanica/machines/{machineId}/model.glb
```

## Loading behavior

The visible loading UI combines:

- Drei global loader progress from `useProgress()`
- explicit viewer-store loading phase
- model preparation state for procedural assets
- loader errors surfaced in the overlay

The overlay does not alter layout dimensions; it is absolutely positioned over the canvas to avoid layout shift.

## Replacing a procedural teaching model with GLB

1. Keep the same machine ID.
2. Keep the same part IDs where possible.
3. Register the GLB definition after the procedural definition, or remove the procedural registry entry.
4. Ensure node names map to existing part IDs.
5. Verify selection, opacity, annotations, exploded view, and clipping.

Because URLs encode part IDs, preserving IDs prevents old share links from breaking.
