SOURCE / PINNED RELEASE
Made of little things.
Napplet Machines V8
- Release
- f041ff5dc40c…
- Author-recorded commit
- 71c68951e1dd…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b5572362d4a
Archive hash verified: 996282af7a380b0d…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
# Machines multiplayer
Realtime multiplayer update, 2026-11-11. The existing napplet identity, backend
identity, tracks, cars and local gameplay are retained. Verification below
distinguishes isolated simulation from real-network testing.
## Transport and compatibility
This consumer targets proposed NAP-WEBRTC #145 at
`69b8f0b367e3e204ce522b5369d446974b11459a`, based on #59 at
`fb4dd6f0e6294e1837733d2af61931e3e114bd97`. #145 merged into the still-open #59 during implementation; the new
whole-session/late-join and guest-key requirements are included. The shell owns
signaling, consent, authenticated transport keys and capability negotiation.
Guest transport keys do not assert a durable profile identity.
`pocket-circuit-v7` rooms use a host-star topology. A reliable ordered `race`
session carries profiles, ready state, starts/resync, return-to-lobby and one-shot
resets. A separate `state` session requests unordered delivery without retries.
Every open result is checked; missing bindings, incompatible delivery or missing
peer support retain working JSON communication. Old v6 races are deliberately
separate because the application protocol changed.
The installed SDK predates `sendBytes`. A narrow optional adapter calls only the
injected `webrtc.sendBytes` method; all existing operations use the SDK. No raw
host port, native WebRTC, network request or app-owned signaling is introduced.
The new binding must be present before requesting transient delivery. State uses
JSON until the control-channel feature announcement and transient peer connection
are known. An explicit `unsupported` rejection permits JSON fallback; a timeout
has unknown delivery and **never resends that payload**. Future state can use JSON.
Only one in-flight application update and its newest replacement are retained.
Queue-full responses retry the newest state after a short pause. Reliable control
is independent of that coalescing. Success means the shell queued the data, not
that another player received it. Control errors remain visible instead of silently
claiming delivery.
The shell's additional `soy-rtc/realtime-1` signaling profile is a local host
implementation choice, not an accepted interoperable upstream contract. Other
shells need compatible signaling. CVM room membership is validated by this app;
it is not a transport admission credential. Incoming identities, authority, race,
roster, finite values, ranges, frame size, sequence and ticks are checked before
game state changes. The host remains authoritative; this is not anti-cheat.
## State and responsiveness
MC7/1 binary frames carry a version/type and race UUID, then either a world tick
and numeric body state, or sequenced compact input. Roster names/IDs/cars arrive
on the reliable start. World numbers use float32 (ACK/tick are unsigned integers);
steering/throttle use signed 16-bit quantization. Malformed, unknown, oversized,
wrong-race and stale frames are discarded. JSON follows the same state validation.
World snapshots are sent at 20 Hz, inputs at 30 Hz with the latest three commands.
The host samples the newest intent once per 60 Hz physics tick and acknowledges
its sequence. It holds that intent for at most 250 ms, then applies neutral input.
This replaces the old persistent queue of inputs replayed at normal speed; it
also prevents high-rate senders from advancing physics faster. Reset is a reliable,
deduplicated one-shot action, not a lossy transient input bit.
Local prediction and ACK-based reconciliation remain. Small visual corrections
decay over roughly 100 ms; respawns and large corrections snap. Remote interpolation
adapts between 50 and 150 ms based on snapshot arrival jitter (previously fixed at
100 ms). There is no extrapolation, rollback or host migration. A guest departure
leaves the healthy room running and its car becomes AI; host departure ends the
race. Membership refresh requests reliable resync so early joiners do not miss
the start while their CVM roster catches up.
## Reproduce the local checks
```sh
pnpm verify
pnpm test:conformance
soyli multiplayer tests/multiplayer.mjs --players 6 --latency 50 --jitter 15 --timeout 180 --turn-binary /path/to/turnserver
soyli multiplayer tests/network-fallback.mjs --players 2 --latency 50 --jitter 15 --timeout 120 --turn-binary /path/to/turnserver
soyli multiplayer tests/network-benchmark.mjs --players 2 --latency 50 --jitter 15 --timeout 120 --turn-binary /path/to/turnserver
soyli multiplayer tests/network-loss-benchmark.mjs --players 2 --timeout 120 --turn-binary /path/to/turnserver
```
Use the matching locally built soyLI for the new loss-model scenario. Each command
runs independent browser contexts with disposable local signaling/CVM and TURN.
Run scenarios in separate processes: a sequential same-process harness stalled
during service teardown. That harness limitation is not a gameplay acceptance.
Reports distinguish passed and skipped checks; conformance without manifest,
wire and lifecycle evidence does not prove those surfaces.
The benchmark logs application bytes, message sizes, pending input counts and
send-to-authoritative-ACK observation time. Queue measurements come from the
trusted test host. Simulated loss drops transient messages and delays reliable
messages to model retransmission; this is not packet-level SCTP emulation.
Measurements exclude DTLS/SCTP/TURN overhead. Real-network NAT, physical controllers,
prolonged Internet loss and independent-shell interoperability remain unverified.
## Local verification results
- `pnpm verify`: 6 guidance tests and 48 gameplay/network tests passed, followed
by type checking and the production build. The frozen artifact used in browser
tests is unchanged by final formatting: SHA-256
`49a9d499a8d22624717a5d4aa7ea5ec9e9b1930bb2abdd62511edfade1fca786`.
- Upstream conformance: 5 passed, 0 failed, 5 skipped (manifest/index/requires,
wire envelopes and lifecycle evidence not supplied). Those skips remain unverified.
- Six independent players: start, host-star communication, driving, guest
departure/reconnect and preserved room passed. Two-player missing-binding
reliable JSON fallback passed. Real runtime tests also cover isolated peer
failure, authenticated attribution, queue pressure and consent revocation.
- Two-player before/after, 50 → 200 → 50 ms delay, ±15 ms jitter, 15 seconds:
| Measure | Before | After |
| --- | ---: | ---: |
| Host payload bytes | 1,088,422 | 192,130 |
| Guest payload bytes | 1,198,912 | 16,296 |
| Guest median / p95 send-to-ACK | 702 / 886 ms | 468 / 761 ms |
| Guest peak simulated queue | 23,952 B | 240 B |
| Guest pending-input median after recovery | 43 | 27 |
With ±95 ms jitter and 25% loss, median/p95 ACK observation changed from
958/1,207 ms to 459/805 ms and peak guest queue from 69,642 B to 288 B. The loss
baseline uses the old frozen game on the new host so the loss model is identical.
Normal-delay baseline uses the old host and old game. The old artifact was
`434eecd409c2b38f5ecb4266db50ced44c1b42c493117ce043e98ac09e2ba722` from
commit `1d539a5`. These single-run measurements include scheduling variability;
ACK observation is not input-to-photon latency. No deployment/publication performed.
