Skip to content

feat(scene)!: overlays restart on air - #66

Merged
kixelated merged 9 commits into
mainfrom
quest/m1/overlay-restart
Nov 6, 2026
Merged

kixelated merged 9 commits into
mainfrom
quest/m1/overlay-restart

Conversation

@kixelated

@kixelated kixelated commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Finishes quest/m1/overlay-restart.md.

Problem

An overlay's CSS timeline started when the overlay opened and never again, so a lower third played its entrance once, at launch or edit, and sat settled on every later cut.

Approach

  • Scene file (collection.rs): Source::Overlay gets restart: bool, true by default and written only when false, as the quest decided (like OBS's "refresh when the scene becomes active").
  • Overlay thread (overlay.rs): Overlay::restart(start) lays the document out afresh from its HTML on the overlay thread, keeping its textures, and repaints it as of start. Overlay::start reports where its timeline starts.
  • Compositor (compositor.rs): each render, before painting, a restarting overlay whose timeline started before the moment showing it went on starts over at that moment: the program scene's program_start if program shows it, else the preview scene's preview_start unless the top layer or a scene a transition leaves shows it on air, the same instants keyframes run from. shown is split into drawn (what given scenes draw on any canvas, through clones and masks) and on_air_sources (what program draws: its scene, the scene a transition leaves, the top layer, and a stinger's clip under way with its masks), so the restart and the paint filter agree on what "shows" and "on air" mean.
  • Studio (ui.rs): the Overlay add form gets Restart on program, on by default.
  • README documents the behavior, the key, and the add-form checkbox. The quest file and its link are deleted.

Impact

  • Scene file: overlays take restart = false to keep running across cuts. Existing overlays restart by default, a behavior change: one that should keep running (a clock) needs restart = false.
  • moq-scene public API: Source::Overlay gains a restart field (breaking for anyone constructing it by struct literal; add restart: true for the new default). No wire impact.

Choices made without asking

  • One timeline per overlay, preview and program share it. An overlay is one document and texture per source. If program shows it, program's moment wins, so putting a scene with the same lower third into preview does not replay its entrance there (it would replay on program too). The quest Plan says preview restarts its overlays "as keyframes do"; that holds whenever program does not show the overlay. Fully separate preview timelines would need a document and texture per moment, threaded through every draw (and through the nested-scene moments of moq-dev/studio#58), doubling paint and memory for the common case where preview and program show the same scene after a cut. Rejected as not worth its weight for a preview-only difference.
  • A transition between two scenes that both show a restarting overlay restarts it at the transition's start, so the outgoing copy replays too (it is the same texture). Keyframes keep the outgoing scene's own moment; the overlay cannot without a second document, for the same reason as above.
  • An edit still starts an overlay at the edit, not at its scene's moment: an overlay only restarts when the moment showing it is newer than its own start. Restarting to an older moment would jump an edited lower third past its entrance.
  • Hiding and showing an overlay's item within one moment does not restart it, as keyframes do not.
  • The flag is in the add form only, as Media's restart is; there is no per-source editor yet.

Alternatives

  • Per-moment documents (above).
  • Rewinding the existing document's resolve time instead of laying it out again: Stylo keeps its own record of which animations started and finished, which a rewind would leave stale, and Blitz exposes no restart. A fresh layout from the stored HTML, at cut time only, is the documented path (it is how the overlay opens).
  • Driving the restart from the studio's set_on_program, as media files do: that fires only when a source joins the on-program set, so a cut between two scenes both showing the lower third would not replay it, and it knows nothing of preview.

Validation

  • just ci passes (236 tests).
  • GPU tests on Metal: all 36 ignored compositor::tests::, including the new an_overlay_restarts_going_on (restarts going into preview while program does not show it, restarts on the cut, a preview under program does not restart it, a restart = false overlay runs on). It fails with the restart call removed (preview shows the settled overlay). an_overlay_animates_on_the_program_clock now sets restart: false, which is what it tests.
  • The new test also covers a preview not restarting an overlay the top layer shows on program.
  • New GPU test a_stinger_mask_runs_on_under_a_preview: during a stinger whose clip is masked by a restarting overlay no scene on air shows, putting a scene with that overlay into preview leaves its timeline alone. It fails with the old on-air set (the overlay restarts 100 ms later).
  • On f32fe19: just ci passes (236 tests), and all 37 ignored compositor::tests:: pass on Metal.
  • collection::tests::round_trips covers both values, the default written by omission.
  • Merged origin/main for moq-dev/studio#62 (overlay assets): a restart now lays the overlay out through feat(scene): overlays load their own images and fonts #62's open from the same checked Assets, so its preloaded images and served fonts survive it. overlay::tests::assets_load_before_the_first_paint now lays the document out a second time, as a restart does, and checks the fonts and both background images again. The README now says a restart reuses the assets read when the overlay opened.
  • On ddebcb7 (after the merge): quest gate just ci passes (240 tests), and all 37 ignored compositor::tests:: pass on Metal, including feat(scene): overlays load their own images and fonts #62's an_overlay_draws_its_image_on_its_first_frame, an_overlay_restarts_going_on, and a_stinger_mask_runs_on_under_a_preview.

Review

  • Reviewer: Codex, gpt-6.1-sol, medium effort (quest review --base origin/main), reviewed head ddebcb7.
  • Earlier rounds on the pre-merge branch: round 1 on 3ec7ce9 found that a preview restarted an overlay the top layer or a leaving scene showed on air (fixed in b50a9cf); round 2 on b50a9cf, no findings; the online review on b50a9cf found that the on-air set omitted a stinger's masks (fixed in f32fe19); round 3 on f32fe19, no findings.
  • The hand-resolved merge of origin/main changed the diff, so ddebcb7 got a new review session. Round 1 on ddebcb7: no findings.

Follow-ups

  • If moq-dev/studio#58 lands first, drawn must reach through nested scenes as its shown does, so an overlay in a nested scene restarts when the scene drawing it goes on; resolved at merge either way.

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

@pullfrog

pullfrog Bot commented Nov 6, 2026

Copy link
Copy Markdown

Pullfrog  | Review this ➔

An overlay's CSS timeline starts over each time a scene showing it goes on
program, or into preview while program does not show it, as keyframes do.
A new per-overlay `restart` flag, true by default, turns it off for a clock
or ticker that should run on across cuts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Overlays restart on air feat(scene)!: overlays restart on air Nov 6, 2026
…aving scene shows

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review November 6, 2026 08:36
@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You'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 3 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e51384a9-abef-4467-9fe9-d80bf070c2dc
Commits

Reviewing files that changed from the base of the PR and between e37e95f and a09849a.

Files selected for processing: 8

  • README.md
  • quest/m1/README.md
  • quest/m1/overlay-restart.md
  • rs/moq-scene/src/collection.rs
  • rs/moq-scene/src/compositor.rs
  • rs/moq-scene/src/overlay.rs
  • rs/moq-scene/src/source.rs
  • rs/moq-studio/src/ui.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

@kixelated kixelated left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed head: b50a9cf3db096e5a16bd134847b54c039cd0fa25.

[P2] Protect overlays used by an active stinger from preview restarts — rs/moq-scene/src/compositor.rs:575–583

on_air includes the outgoing scene and top layer, but not the active stinger's source-filter masks. An overlay is a valid mask source, and Draw::stinger applies those filters to the live program. While such a stinger is playing, selecting a preview scene containing the same restarting overlay (absent from both transition scenes and the top layer) therefore passes this guard and resets its shared texture, visibly replaying the mask on air. shown() already accounts for these stinger masks, so painting and restart protection disagree.

Include active-stinger mask dependencies in the on-air set and add a regression test that changes preview during the stinger, asserting its program mask continues uninterrupted.

Limits: GitHub-only static review of all eight changed files and relevant call paths; no local or GPU tests run. The exact-head GitHub Check runs currently show skipped/cancelled, so this is not a verified CI pass.

The on-air set that guards overlays from preview restarts now comes from
the same helper as the paint set, so it includes an active stinger's clip
and the sources its filters mask with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Contributor Author

Re the P2 on b50a9cf (stinger masks missing from the on-air set): agreed and fixed in f32fe19. restart and shown now share one on_air_sources set (program scene, leaving scene, top layer, and an active stinger's clip with its mask sources), so painting and restart protection cannot disagree again. The new GPU test a_stinger_mask_runs_on_under_a_preview puts a scene with the masking overlay into preview mid-stinger and asserts its timeline is untouched; it fails on the old set. Local Codex review of f32fe19 reports no findings.

(Written by Claude Opus 5.5)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed head: f32fe198999763a45e3b25b37159109b95f93252.

The prior P2 stinger-mask finding is addressed by inspection: restart() and shown() now share on_air_sources(), including the active stinger's mask dependencies. The new a_stinger_mask_runs_on_under_a_preview regression test checks that selecting a preview scene containing the mask leaves its timeline start unchanged while the stinger remains active.

No new actionable findings in the change since b50a9cf3db096e5a16bd134847b54c039cd0fa25. No further code change requested from this review; wait for the current CI result.

Limits: GitHub-only static review of the fix, regression test, and relevant call paths. No local or GPU tests run; the exact-head GitHub Check is still in progress.

kixelated and others added 3 commits November 6, 2026 07:46
A restart lays the overlay out again through #62's open, so its preloaded
images and served fonts survive it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@kixelated kixelated left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed head: ddebcb709b6f6637afc56e08872a53fb3165b22f.

No new actionable findings in the update since f32fe198999763a45e3b25b37159109b95f93252, accounting for the merged base changes. The restart now rebuilds the document through open(&document.assets, ...), preserving the preloaded images and fonts without rereading disk. The expanded assets_load_before_the_first_paint test checks fonts, images, and an animated background across two layouts using the same assets. The prior stinger-mask fix remains intact.

No further code change requested from this review; wait for the current CI result.

Limits: GitHub-only static review of the merge integration, changed regression coverage, and relevant restart/paint paths. No local or GPU tests run. The exact-head GitHub Check is still in progress; Quest passed.

@kixelated
kixelated merged commit c16bef4 into main Nov 6, 2026
3 checks passed
@kixelated
kixelated deleted the quest/m1/overlay-restart branch November 6, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant