joule-moq-web room: draw only what changed, and send a key at once #585

Merged
dcharlot merged 1 commit from room/draw-on-new-frame into main 2026-11-02 19:49:35 -05:00
Owner

The room's compositor redrew every tile on a fixed timer whether or not a frame had arrived, on a canvas asking for software rendering so a test hook could read it back. A still room spent draws at the full rate, and a frame waited up to a whole period for the next tick.

What changes

  • A tile is drawn when its video has a new frame, at the next display refresh, with whatever lies over it. The whole canvas is drawn only after a re-layout. Drawing the whole canvas on every new frame would be worse for a large grid, whose unsynchronised sources would repaint all of it at every refresh.
  • The canvas no longer asks for software rendering.
  • stats() reports what drawing spent. The counts are held by the test, because a busy host can't flake them (draws <= frames + relayouts + 1). The latency from a frame's arrival to its drawing is reported, not held.
  • The log and timeline no longer grow without bound in the DOM: 2,000 and 1,000 lines.
  • Remote control held every action for the next refresh. A key, a button or a wheel now goes at once, with the moves before it.
  • A bug this fixes: coalesced pointer moves kept the pointer's oldest place in a refresh, because the batch held a copy of the move that later ones updated in vain. They now keep the latest.

Evidence

  • Node tests: compose.test.mjs 9, remote_input.test.mjs 7, both run from e2e/run.sh.
  • Mutations: 11 of 11 in the compositor and 5 of 5 in the input path caught.
  • Real browser on the build host at load about 150: room 348 of 348 checks, conversations and calls 17 of 17.

Not measured: the frame latency this saves on a real display. The host above is shared and headless, so the figure would not mean much; the counts are what the test holds.

🤖 Generated with Claude Code

The room's compositor redrew every tile on a fixed timer whether or not a frame had arrived, on a canvas asking for software rendering so a test hook could read it back. A still room spent draws at the full rate, and a frame waited up to a whole period for the next tick. **What changes** - A tile is drawn when its video has a new frame, at the next display refresh, with whatever lies over it. The whole canvas is drawn only after a re-layout. Drawing the whole canvas on every new frame would be worse for a large grid, whose unsynchronised sources would repaint all of it at every refresh. - The canvas no longer asks for software rendering. - `stats()` reports what drawing spent. The counts are held by the test, because a busy host can't flake them (`draws <= frames + relayouts + 1`). The latency from a frame's arrival to its drawing is reported, not held. - The log and timeline no longer grow without bound in the DOM: 2,000 and 1,000 lines. - Remote control held every action for the next refresh. A key, a button or a wheel now goes at once, with the moves before it. - **A bug this fixes:** coalesced pointer moves kept the pointer's oldest place in a refresh, because the batch held a copy of the move that later ones updated in vain. They now keep the latest. **Evidence** - Node tests: `compose.test.mjs` 9, `remote_input.test.mjs` 7, both run from `e2e/run.sh`. - Mutations: 11 of 11 in the compositor and 5 of 5 in the input path caught. - Real browser on the build host at load about 150: room 348 of 348 checks, conversations and calls 17 of 17. **Not measured:** the frame latency this saves on a real display. The host above is shared and headless, so the figure would not mean much; the counts are what the test holds. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
joule-moq-web room: draw only what changed, and send a key at once
All checks were successful
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 3m35s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 8s
WAI conformance / does this change touch it (pull_request) Successful in 8s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 9s
WAI Studio / does this change touch it (pull_request) Successful in 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 36s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m2s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 3m19s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 29s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 59s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 3m9s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m35s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 5m43s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m16s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 6m1s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 10m16s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 11m30s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 11m58s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 16m38s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 12m38s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 14m53s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 7m24s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 24s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 11m47s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 18m5s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 11s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 33s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 1m51s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 5m27s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h5m58s
d3507ca658
The room's compositor redrew every tile on a fixed timer, whether or not a new
frame had arrived, on a canvas asking for software rendering so that a test hook
could read it back. A still room spent draws at the full rate, and a frame waited
up to a whole period for the next tick.

A tile is now drawn when its video has a new frame, at the next display refresh,
with whatever lies over it; the whole canvas only after a re-layout. Simply drawing
the canvas on every new frame would be worse for a large grid, whose unsynchronised
sources would repaint all of it at every refresh. `stats()` reports what drawing
spent: counts a test can hold, since a busy host can't flake them, and the latency
from a frame's arrival to its drawing, which is reported and not held.

The room's log and timeline no longer grow without bound in the DOM.

Remote control held every action for the next refresh. A pointer moving is many
actions a refresh, and that suits it; a key, a button or a wheel is one thing that
happened, and now goes at once with the moves before it. Coalesced moves also kept
the pointer's oldest place in a refresh, because the batch held a copy of the move
that later ones updated in vain. They now keep the latest.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!585
No description provided.