Adds the "carries whatever it can reconstruct, verifies whatever it
carries" surface on top of the existing neural/codec WAI. All builds
green against this base (wai-rs all-features tests + clippy, wai-web
wasm, wai-spz-gen, wai-relay).
Reconstruct half — each a spec + conformance corpus + in-tab browser
sink that re-derives the corpus hash, over one wai.det.fixed64 floor:
- interactive worlds replay-equivalence (3 sim registrants,
relay multiplayer, session receipts, glTF + real-SPZ assets)
- spatial audio mixdown-equivalence
- haptics sample-equivalence
- state-feeds replay-equivalence (non-physics sim)
- avatars / digital humans pose-equivalence (+ telepresence)
- volumetric / 4D splats frame-state-equivalence (WebGPU EWA render)
Verify half (lever 4):
- asset provenance — signed, energy-accounted lineage for opaque
captured content WAI does not reconstruct; tamper-evident in-tab.
Cross-cutting: per-class JWP receipt profiles; a native energy meter
(IOReport via macmon, no sudo) emitting receipts with real measured
joules. Codecs gated behind a `codecs` feature (default on) so the
world/wasm sinks build without the C codec chain.
Excludes the separately-evolving neural subsystem (semantic path, GLC
rANS, ONNX tooling) to avoid reverting newer origin work.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
100 lines
3.6 KiB
Markdown
100 lines
3.6 KiB
Markdown
# WAI Extension: Haptics (DRAFT)
|
||
|
||
> Status: **PROMOTED 2026-06-13** — canonical copy at
|
||
> `extensions/haptics.md` (site mirror). Edit the canonical copy.
|
||
> Reference impl: `wai-rs` `haptic`; corpus: `haptic-conformance/`;
|
||
> live sink: wai.transaction.science/haptics.
|
||
|
||
Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
|
||
|
||
## 1. Scope and model
|
||
|
||
A `wai.haptic.signal` object is a per-channel keyframed envelope of
|
||
**intensity** and **sharpness** (the Core-Haptics-shaped pair every
|
||
modern actuator API maps to) that the sink reconstructs to a per-sample
|
||
buffer and plays on whatever actuators it has. It is lever 3
|
||
(instructions-at-the-sink) for touch — an effect is a few hundred bytes,
|
||
not a recorded waveform.
|
||
|
||
In scope: the container, the deterministic reconstruct contract, the
|
||
**sample-equivalence** conformance criterion, the fallback floor, the
|
||
receipt profile.
|
||
|
||
Out of scope: a transport; actuator hardware specifics (the
|
||
channel→actuator binding is the sink's); carrier synthesis (the signal
|
||
is an amplitude/sharpness envelope, not a modulated waveform — the
|
||
deterministic floor stays trig-free).
|
||
|
||
Relationship to the core spec: mirrors interactive-worlds / spatial
|
||
audio. The reconstruct runs in the `wai.det.fixed64` floor; `media`
|
||
takes the informational value `"haptic"`; `wai.haptic.signal` is
|
||
authoritative.
|
||
|
||
## 2. Container (`WHAP`)
|
||
|
||
```
|
||
"WHAP" | u16 n_sections | section table (u8 kind, u32 off, u32 len) | sections
|
||
```
|
||
|
||
| kind | section | required |
|
||
|---|---|---|
|
||
| `0x01` | contract (canonical JSON) | REQUIRED |
|
||
| `0x02` | channel signals | REQUIRED |
|
||
|
||
### 2.1 Contract
|
||
|
||
```json
|
||
{ "sample_rate": 1000, "numeric": "wai.det.fixed64",
|
||
"channels": 1, "duration": 1500 }
|
||
```
|
||
|
||
Haptic rates are low (≈1 kHz); `duration` is in samples.
|
||
|
||
### 2.2 Channel signals
|
||
|
||
`n_channels u32`, then per channel: `n_keys u16`, then
|
||
`n × ( pos_sample u64 | intensity i64 Fx | sharpness i64 Fx )`.
|
||
Both fields are in `[0, 1]`. Between keyframes they linear-interpolate
|
||
in `Fx`; before the first / after the last key they hold.
|
||
|
||
## 3. Reconstruct contract
|
||
|
||
For each channel, for each sample `t ∈ [0, duration)`:
|
||
`intensity(t)`, `sharpness(t)` = the `Fx` linear interpolation of the
|
||
channel's keyframes at `t`, each clamped to `[0,1]` and quantized to a
|
||
`u8` (`round(v · 255)`, half away from zero, in integer space). The
|
||
canonical reconstruction is, per channel, the interleaved
|
||
`[intensity, sharpness]` `u8` pairs.
|
||
|
||
## 4. Conformance — sample-equivalence
|
||
|
||
> Given the same `wai.haptic.signal`, a conforming sink MUST reconstruct
|
||
> the identical canonical `u8` buffer, hence the identical BLAKE3 — on
|
||
> every machine, no tolerance parameter.
|
||
|
||
```
|
||
signal_hash = BLAKE3("wai:haptic-signal\x01" || per-channel u8 pairs)
|
||
```
|
||
|
||
## 5. Fallback floor
|
||
|
||
A sink with no actuators ignores the signal (haptics are
|
||
supplementary); there is no perceptual substitute to fall back *to*, so
|
||
`fallback` is typically `null`. A sink MAY surface the envelope visually
|
||
(a waveform) — presentation, not conformance.
|
||
|
||
## 6. Receipt (JWP profile)
|
||
|
||
`signal_hash` is the identity; the group's objects are per-channel
|
||
reconstruction blocks, Merkle-bound; one Ed25519 signature over
|
||
signal_hash + root + `work` (= duration × channels) + carried
|
||
`joules_micro`; `parent_receipt_hash` chains — the worlds/audio receipt
|
||
shape reused.
|
||
|
||
## Appendix
|
||
|
||
Sample-equivalence is replay/mixdown-equivalence with the tick replaced
|
||
by the haptic sample. The envelope is trig-free by construction
|
||
(amplitude + sharpness, not a modulated carrier), so the `Fx` floor
|
||
reconstructs it exactly with `+,−,×,÷` alone — the simplest cargo class
|
||
to make bit-exact, which is why it's the fast Phase-2 win.
|