Repository navigation
feat(scene): HTML and CSS overlays drawn by Blitz on the program clock - #34
Conversation
Quest-Claim: 734fe25480786f0d
An `overlay` source holds script-free HTML and CSS, laid out by Blitz and painted by Vello straight into a texture on the compositor's device, with its CSS animations on the program clock. HTML or CSS outside what overlays draw fails the source, naming it, and an overlay loads nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st drawn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 30 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: e2360ff
Overall direction: the inline source model and direct-to-texture rendering fit the studio-only scope. One recovery issue should be fixed: a failed overlay worker must invalidate all documents it owned, including off-air ones (inline finding).
Verification: static review of the diff, source integration, and relevant Blitz/Vello dependency paths via GitHub. No build, GPU tests, or performance measurements were run here; GitHub's Check workflow is still in progress.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This adds script-free HTML/CSS overlays rendered by Blitz on the program clock.
- Model and serialization: New
Source::Overlay { html, width, height }with validation (1..4096px, reusing browser bounds), serialized askind = "overlay", stored inline (undo/clipboard compatible). Overlays excluded from publishing and from Replay (like Browser). README and quest docs updated accordingly. - Rendering:
rs/moq-scene/src/overlay.rsadds a dedicated overlay thread (BlitzBaseDocumentis!Send) owning Vello pipelines, fonts (bundled Noto Sans as all generic families), and painting. Documents start at timeline 0 on open, animate on the program clock viaresolve(now - start), and only repaint while animating and while visible/previewed. Vello renders to anRgba8Unormstorage texture sampled directly by the compositor; no readback/upload per frame. - Safety/subset: Strict allowlists for elements/attributes/CSS rules/properties; CSS parsed by Stylo with error reporting (naming first violation). Blocks
url(,image-set(,@import,@font-face, scripts, resources, and unsupported properties (filter,backdrop-filter,mix-blend-mode,text-shadow,mask, etc.). Font synthesis disabled; bold uses the bundled bold face. Panic on overlay thread fails overlays gracefully ("the overlay thread stopped") without crashing the studio. - Integration: Compositor tracks overlays via
Overlays/Overlay, paints only those visible in preview/program/top/fade-out scenes (including through clones/masks), updates timeline on open, handles thread failure. Source driver validates HTML at startup (overlay::check) and surfaces failures in Sources panel. UI adds "Overlay" kind with multiline HTML editor and size controls; placement matches Browser (own size). Compositor GPU test added for program-clock animation.
All changes look consistent with existing patterns (threading model, error handling, validation flow). Tests added for subset enforcement, font weight, and animation timing.
big-pickle (free) | 𝕏
# Conflicts: # Cargo.lock
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head 5f65927 against base c9d4185.
The prior off-air overlay finding is addressed: a detected worker-wide paint failure now clears every overlay handle and cached picture, including layers outside the current paint. The new regression tests an off-air layer after worker failure and checks that cutting back cannot show its frozen paint. No new actionable finding in the follow-up.
Verification limits: GitHub-only static review of the compositor and worker paths; I did not run GPU tests, failure injection, or performance measurements.
(Written by review (OpenAI))
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Re-reviewed the commits since the prior pullfrog review at e2360ff, which fix overlay-thread failure recovery and merge origin/main.
- Failed every overlay when the thread stops:
Compositor::paintnow walks every overlay layer, off-air ones included, clearingoverlay/pictureand recording "overlay thread stopped" instead of only touching the layers in the current paint set, so an off-air overlay cannot show a frozen picture when cut to. Healthy paints still skip off-air layers. - Added a regression test:
a_stopped_overlay_thread_fails_every_overlaypaints an overlay, leaves it off air, stops the worker, asserts both overlays report the failure, and checks that cutting back renders no overlay. - Added a test-only worker panic hook:
Request::PanicandOverlays::panicstop the thread the way a Blitz panic would. - Merged
origin/main: picked up the moq pin bump (#35) and #31, touching onlyCargo.lockandquest/m0/README.md.
big-pickle (free) | 𝕏
Overlays (#34) follow the transition state: the scenes they paint for include the one a transition leaves, and a move glides an overlay item like any other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Problem
quest/m0/overlays.md: titles, lower thirds, and tickers should be written as script-free HTML and CSS and render through Blitz into the program, with CSS animations on the media clock. #30 scoped this to the studio: the layout track, browser DOM rendering, and the headless compositor wait for the m1 composition epic.
Approach
overlaysource kind,{ html, width, height }, besidebrowser. The HTML is inline, so the source is self-contained: no local path, nothing studio-only, and it travels through undo, the clipboard, and (in m1) the layout track as is.0.3.0-beta.4lays the document out,blitz_paint::paint_scenepaints it into avello::Scenethroughanyrender_vello::VelloScenePainter, andvello::Renderer::render_to_texturewrites it on the studio's own wgpu 30 device into anRgba8Unormstorage texture the compositor samples directly. Vello writes gamma-encoded straight alpha, which is what the compositor already reads.rendertime it first sees it, and resolves the document atnow - starteach frame, so a frame shows the animation where the program time says. A document repaints only while Blitz reports it animating, and only while preview or program draws it (through clones and masks); one off air waits and lands in the right place when shown again.BaseDocumentis!Send, and the compositor sits in the engine's shared state, so documents live on one thread per compositor, which owns the Vello pipelines too. The compositor asks it to paint and waits for the reply before submitting its frame. A panic in Blitz fails the overlays ("the overlay thread stopped"; edit to restart) instead of the studio.colr: redor an invalid value is named too); rules other than style, nested,@media, and@keyframesrefused (@import,@font-face, ...); properties checked against an allowlist by the names the block serializes under, soborder: 1px solidpasses asborderrather than tripping on theborder-imageit resets; anyurl(orimage-set(refused.filterandbackdrop-filter(blitz-paint computes them, butVelloScenePainter::push_layerdrops both),mix-blend-mode,text-shadow,mask,text-overflow, multi-column layout, or logical borders. A test checks every listed name is one Stylo parses.notosanscrate) registered as every generic family, with system fonts off. Blitz synthesizes no bold, so one face would drawfont-weight: boldlight.Verified the claims the brief carried over, from crate sources and a probe on this Mac:
blitz-paint 0.2.1takesanyrender ^0.6, whoseanyrender_vello 0.6is onvello ^0.6andwgpu ^26.0.3.0-beta.4resolves toanyrender 0.14,anyrender_vello 0.15,vello 0.11, andwgpu 30.0.1, one copy, the same as moq-video's.paint_scenetakes(painter, doc, scale, width, height, x_offset, y_offset).Measurements
Apple M4, Metal, 1920x1080 canvas at 30 fps, a solid background plus a 1920x1080 lower third (gradient, rounded box, shadow, two lines of text), 120 frames after a warm-up, release build:
render()CPUImpact
kind = "overlay", withhtml,width, andheight(each 1 to 4096).Public API:
moq_scene::Source::Overlay(a new variant; moq-studio is the only consumer) andmoq_scene::Error::Overlay. Wire: none; overlays publish no track and the catalog is unchanged.Alternatives
.htmlfile, likeimage: easier to edit in an editor, but a local file the m1 layout cannot serialize, which relative-path pastes break, and outside undo.BaseDocumentis!Send, and the compositor must beSend.Collection::validate, so an edit is refused outright: validation runs on every edit, drags included, and would re-parse every overlay each time. The driver's check matches how an unreadable image fails.Choices made without asking
htmlover a file path (above).onclickare refused rather than ignored, so a pasted snippet says what it expected.Decisions
=0.3.0-beta.4(blitz-dom,blitz-html,blitz-paint,blitz-traits), the first line whose Vello and wgpu match moq-video's, over stable 0.2 plus a readback or waiting for stable 0.3 (maintainer, 2026-11-04).Follow-ups
data:URLs or files beside the scene: aNetProviderthat serves only those, and the check widened to match.VelloScenePainter::push_layerignoresfilterandbackdrop-filter, and blitz-paint synthesizes no bold from parley'sSynthesis::embolden.Validation
just cipasses at the head, after mergingorigin/main(chore(moq): pin moq ffcb7cd for the presentation timeline #35's moq bump to ffcb7cd and feat(studio): microphones and system audio read stalled when they stop delivering #31).Cargo.lockis main's with Blitz's crates re-added by cargo; nothing in the moq bump broke the overlay code.just render-swruns them on Linux), on Metal:compositor::tests::an_overlay_animates_on_the_program_clock: the overlay opens off air, is cut to, and shows the midpoint at 500 ms, three quarters at 750 ms, and blue at 2 s.compositor::tests::a_stopped_overlay_thread_fails_every_overlay: with one overlay shown and one painted then off air, stopping the overlay thread fails both, and cutting to the off-air one shows no frozen paint.Review
Codex (
quest review), gpt-6.1-sol, medium effort, head8de1b23: no findings. The head after it only mergesorigin/main(#31) without conflicts.72e6644), medium: an overlay first drawn after it opened started its animations at the first draw, since Stylo starts an animation at the resolve that creates it. Fixed ine2360ff: the overlay thread resolves each document at timeline 0 when it opens. Reproduced first by the extended GPU test, which failed with500 ms: [255, 0, 0, 255].e2360ff): no findings.compositor.rs:392: when the overlay thread stopped, only the overlays in that paint lost their handle and picture, so an off-air one kept its last paint. Fixed in8de1b23: a worker-wide failure clears and fails every overlay. Reproduced first bya_stopped_overlay_thread_fails_every_overlay, which failed withaside fails.8de1b23): no findings.(Written by Claude Opus 5.5)