# Share-Link Codec Contract

Mechanica share links must be safe to paste, stable across releases, and compact enough for classroom slides or documentation. The `src/utils/viewStateCodec.ts` module defines a pure v1 URL-state codec for viewer links and backs it with regression tests in `tests/viewStateCodec.test.ts`.

## Canonical v1 query keys

| Key | State field | Example | Notes |
| --- | --- | --- | --- |
| `v` | schema version | `v=1` | Always emitted so future migrations are explicit. |
| `m` | machine id | `m=inline-four-engine` | Safe registry identifier only. |
| `cam` | saved camera preset | `cam=front-cutaway` | Optional when raw camera vectors are present. |
| `pos` | camera position | `pos=6,3,8` | Three finite numbers. |
| `target` | camera target | `target=0,1,0` | Three finite numbers. |
| `zoom` | camera zoom/distance | `zoom=1.25` | Clamped to the codec budget. |
| `mode` | render mode | `mode=section` | Canonical values: `solid`, `wireframe`, `xray`, `section`. |
| `explode` | exploded-view amount | `explode=0.6` | Normalized to `0..1`. |
| `play` | animation playback | `play=1` | `1` = playing, `0` = paused. |
| `speed` | animation time scale | `speed=1.5` | Clamped to `0..4` by default. |
| `select` | selected component id | `select=piston-1` | Empty value clears selection when defaults are supplied. |
| `hide` | hidden component ids | `hide=cover,bolt` | Deduplicated and sorted for stable links. |
| `iso` | isolated component ids | `iso=rotor` | Deduplicated and sorted for stable links. |
| `opacity` | component opacity map | `opacity=cover:0.25;block:0.6` | Per-component values clamped to `0..1`. |
| `section` | cross-section plane | `section=x:-0.125` | Axis must be `x`, `y`, or `z`. |
| `labels` | label visibility | `labels=1` | Boolean aliases accepted on decode. |
| `dims` | dimensions visibility | `dims=0` | Boolean aliases accepted on decode. |

## Safety and edge-case behavior

- Identifiers must match `^[A-Za-z0-9][A-Za-z0-9_.:-]{0,95}$`; path traversal, whitespace, markup, and script-like values are ignored.
- Numeric fields must be finite. Values outside supported ranges are clamped and reported as decode warnings.
- Duplicate URL parameters use the last value and emit a warning so copied links remain deterministic.
- Legacy aliases such as `machine`, `view`, `display`, `exploded`, `hidden`, and `measurements` are accepted on decode but canonicalized back to v1 keys.
- Empty collection params (`hide=`, `opacity=`) intentionally clear default collections, which is required when sharing a state that differs from route-level defaults.

## Integration guidance

The codec is UI-agnostic and can be used by `useUrlViewState`, share buttons, QA fixtures, and machine documentation examples without importing React or Three.js. When wiring it into the viewer, pass `allowedMachineIds` and `allowedComponentIds` from the active registry/machine definition so stale links cannot select components that do not exist. If a decoded result contains warnings, the UI should still open the closest safe state but may surface a non-blocking “link was repaired” status message.
