# Asset pipeline and loading guide

Mechanica supports procedural React Three Fiber models and GLB/GLTF assets. Production assets should be optimized for fast streaming, stable part selection, and predictable rendering on mobile GPUs.

## Asset goals

| Asset type | Preferred budget |
| --- | ---: |
| Catalogue thumbnail | < 120 KB AVIF/WebP/SVG |
| Small machine GLB | < 1.5 MB compressed |
| Complex machine GLB | < 4 MB compressed |
| Environment HDR/EXR | < 1 MB compressed or use procedural environment |
| Texture set per machine | < 2 MB total KTX2 |
| Draw calls per machine | < 250 desktop, < 140 mobile |
| Triangles per machine | < 250k desktop, < 120k mobile |

Budgets are guidelines. A machine can exceed a single budget only if profiling confirms the interaction remains smooth.

## Recommended folder layout

```text
public/
├── basis/
│   ├── basis_transcoder.js
│   └── basis_transcoder.wasm
├── draco/
│   ├── draco_decoder.js
│   ├── draco_decoder.wasm
│   └── draco_wasm_wrapper.js
src/assets/
├── thumbnails/
└── machines/
    └── <machine-slug>/
        ├── source-notes.md
        ├── <machine-slug>.glb
        └── preview.webp
```

Large source files such as `.blend`, `.fbx`, or CAD exports should be stored outside the application bundle or tracked through Git LFS if the project policy allows it.

## Blender export checklist

Before exporting:

- Apply transforms where appropriate.
- Set origin points for rotating components such as shafts, gears, rotors, flywheels, and valves.
- Name meshes with stable semantic names.
- Keep part boundaries separate when users need visibility or opacity controls.
- Remove hidden construction geometry.
- Use real-world proportions, then scale uniformly for viewer framing.
- Assign material names that describe engineering purpose.
- Prefer a small number of shared PBR materials over many unique materials.
- Avoid unapplied modifiers that create excessive geometry on export.

Export as GLB unless an external `.bin` is required for a specific pipeline.

## Optimization workflow

Use glTF Transform through `npx` so the CLI version is resolved explicitly when run:

```bash
npx @gltf-transform/cli inspect input.glb
npx @gltf-transform/cli optimize input.glb output.optimized.glb --compress draco --texture-compress webp
```

For KTX2 texture compression:

```bash
npx @gltf-transform/cli etc1s input.glb output.ktx2.glb
```

For higher-quality normal maps or technical labels, use UASTC:

```bash
npx @gltf-transform/cli uastc input.glb output.uastc.glb
```

Inspect after every optimization pass:

```bash
npx @gltf-transform/cli inspect output.ktx2.glb
```

## Draco guidance

Draco is effective for high-poly static meshes. Use it for:

- housings
- cases
- brackets
- impellers
- turbine blades
- complex cast geometry

Avoid Draco when:

- the mesh is tiny and decoder overhead dominates
- geometry is frequently morphed
- mesh identity needs direct node manipulation that the optimization pass would merge away

If meshes are merged during optimization, preserve names or rebuild `partMeshMap` after the final optimized file is produced.

## KTX2 guidance

KTX2 reduces GPU memory and download size for texture-heavy assets. Use it for:

- baked ambient occlusion
- normal maps
- roughness/metalness maps
- technical labels baked into mesh surfaces

Prefer simple material colors for procedural educational models. Many Mechanica systems are diagrammatic and do not need heavy texture sets.

## Decoder files

The app configuration points loaders at:

```text
VITE_DRACO_DECODER_PATH=/draco/
VITE_KTX2_TRANSCODER_PATH=/basis/
```

Copy decoder files from the installed Three.js package that matches the application’s resolved version. Common source paths are under:

```text
node_modules/three/examples/jsm/libs/draco/
node_modules/three/examples/jsm/libs/basis/
```

Three.js package layout can change, so verify the exact source path after `npm install`.

## Loading strategy

Production machine loading should follow this sequence:

1. Load registry metadata immediately; it is small and powers the catalogue.
2. Lazy-load machine scene module only when the viewer route opens.
3. Show stable skeleton panels and a viewer progress bar.
4. Initialize GLTFLoader with DracoLoader and KTX2Loader when compressed assets are used.
5. Use `LoadingManager` progress events for visible progress.
6. Cache loaded assets by URL.
7. Dispose cloned runtime materials/geometries when leaving a machine.
8. Keep decoder/transcoder paths same-origin for CSP and caching simplicity.

## React Three Fiber recommendations

- Use `<Suspense>` around machine scene modules.
- Use Drei’s `useGLTF.preload(url)` for likely next machines.
- Use instancing for repeated parts such as bearing balls, roller elements, bolts, fan blades, and compressor stages.
- Set `frustumCulled=true` unless an animation moves bounding volumes unpredictably.
- Use shared materials and memoized geometry for procedural shapes.
- Prefer baked or environment lighting over many real-time lights.
- Clamp device pixel ratio on mobile.

## Material conventions

Recommended material categories:

| Category | Visual treatment |
| --- | --- |
| Housing/case | darker metal, lower opacity in x-ray/cutaway modes |
| Motion transfer | accent blue or graphite metal |
| Energy event | warm amber highlight |
| Fluid/air flow | translucent blue/cyan ribbons or particles |
| Seals/gaskets | dark rubber |
| Bearings/contact | polished metal with clear labels |

## Validation before commit

For every asset:

1. Open in a GLB viewer and confirm scale/orientation.
2. Run glTF Transform `inspect`.
3. Confirm mesh names match `partMeshMap`.
4. Test solid, wireframe, exploded, and cross-section modes.
5. Confirm selected-part highlight works.
6. Test on a mobile viewport with throttled CPU.
7. Compare final file size against the budget table.
8. Confirm no console warnings from GLTFLoader, DRACOLoader, or KTX2Loader.
