P0: Rust engine, wire daemon and audio-reactive descent surface
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# ZHILA wire protocol · v1
|
||||
|
||||
Loopback only, one daemon per session. Text frames are JSON; one binary frame type carries meters. The protocol is deliberately small in P0; the revision model and the command bus are the parts meant to survive into P1.
|
||||
|
||||
## Transport
|
||||
|
||||
- WebSocket at `ws://127.0.0.1:4317` by default.
|
||||
- The daemon binds `127.0.0.1` only.
|
||||
- The first client frame must be `hello` within 5 seconds.
|
||||
- If the client sends an `Origin`, it must be `http://localhost[:port]`, `http://127.0.0.1[:port]`, or `https://tauri.localhost`. Native clients may omit it.
|
||||
- The dev token is `dev`. Set `ZHILA_TOKEN` or `--token` to change it. Tokens are compared in the hello, never put in the URL.
|
||||
|
||||
## Client → daemon
|
||||
|
||||
```json
|
||||
{"type":"hello","protocol":1,"token":"dev","client":"zhila-ui"}
|
||||
{"type":"command","id":7,"command":{"type":"play"}}
|
||||
```
|
||||
|
||||
Commands:
|
||||
|
||||
| command | args | notes |
|
||||
|---|---|---|
|
||||
| `get_snapshot` | — | returns a snapshot, no revision change |
|
||||
| `play` | — | transport, idempotent |
|
||||
| `stop` | — | transport, idempotent |
|
||||
| `strike` | `vein` (bass/crack/voice/noise/silt), `velocity` 0..1 | performance; not journaled |
|
||||
| `set_tempo` | `bpm` 40..220 | journaled |
|
||||
| `set_vein_gain` | `vein`, `gain` 0..1.2 | journaled |
|
||||
|
||||
## Daemon → client
|
||||
|
||||
```json
|
||||
{"type":"hello","protocol":1,"session":"zhila-1a193dfd50c","engine":{"running":true,"device":"Default Audio Device","sample_rate":48000,"buffer_frames":256,"channels":2}}
|
||||
{"type":"snapshot","revision":0,"state":{...}}
|
||||
{"type":"result","id":7,"result":{"kind":"state","state":{...}}}
|
||||
{"type":"event","revision":1,"event":{"kind":"transport","playing":true}}
|
||||
{"type":"error","id":7,"code":"bad_request","message":"tempo must be between 40 and 220 bpm"}
|
||||
```
|
||||
|
||||
`state`:
|
||||
|
||||
```json
|
||||
{
|
||||
"revision": 1,
|
||||
"transport": {"playing": true, "bpm": 128.0, "bar": 1.0, "loop_bars": 2.0},
|
||||
"veins": [{"id":"bass","name":"bass","gain":0.82}, "..."],
|
||||
"pattern": {"steps":16,"steps_per_bar":8,"rows":[{"vein":"bass","velocities":[112,0,0,86,...]}]},
|
||||
"audio": {"running":true,"device":"Default Audio Device","sample_rate":48000,"buffer_frames":256,"channels":2},
|
||||
"journal_len": 0
|
||||
}
|
||||
```
|
||||
|
||||
`result.kind` is `snapshot` or `state`; both carry the full state.
|
||||
|
||||
Events:
|
||||
|
||||
- `{"kind":"transport","playing":bool}`
|
||||
- `{"kind":"tempo","bpm":number}`
|
||||
- `{"kind":"vein_gain","vein":VeinId,"gain":number}`
|
||||
- `{"kind":"struck","vein":VeinId,"velocity":number}`
|
||||
|
||||
Errors: `bad_request` (validation), `unauthorized`, `protocol` (version/hello), `internal`.
|
||||
|
||||
## Binary meter frame
|
||||
|
||||
Sent at ~30 Hz, 31 bytes, little-endian:
|
||||
|
||||
```
|
||||
offset size field
|
||||
0 1 kind = 1
|
||||
1 2 count = 5
|
||||
3 4 bar (f32)
|
||||
7 4 master level (f32)
|
||||
11 20 five vein levels (f32 each)
|
||||
```
|
||||
|
||||
The browser sets `binaryType = "arraybuffer"` and reads a `DataView`. The frame is deliberately separate from JSON; no meter ever goes through text frames.
|
||||
|
||||
## Semantics
|
||||
|
||||
- `revision` increments on every state-changing command: transport, tempo, gains. It is a state version, not the journal length.
|
||||
- `journal_len` counts project edits only: tempo and gains in P0. Play, stop and strike are performance.
|
||||
- The daemon broadcasts events to every client. A command's `result` goes only to the requester.
|
||||
- The server is authoritative. The surface holds a projection and updates it from snapshots, results and events.
|
||||
- P0 has no persistence; a daemon restart starts a fresh session at 128 bpm, not playing, journal empty.
|
||||
|
||||
## Not in v1 yet
|
||||
|
||||
- Binary snapshots / CRDTs.
|
||||
- Project/asset commands.
|
||||
- Agent tools and MCP.
|
||||
- Per-client cursors or collaboration.
|
||||
Reference in New Issue
Block a user