Skip to content

Sticky blocks: an entrance after the roll, a release that ends nothing, an exit that finishes — and the Calendar Display taken out - #25

Merged
ZombieHDGaming merged 3 commits into
masterfrom
claude/sticky-ending-block-options-qw39rf
Sep 7, 2026
Merged

Sticky blocks: an entrance after the roll, a release that ends nothing, an exit that finishes — and the Calendar Display taken out#25
ZombieHDGaming merged 3 commits into
masterfrom
claude/sticky-ending-block-options-qw39rf

Conversation

@ZombieHDGaming

Copy link
Copy Markdown
Contributor

Four things: three on the Sticky Ending Block, and the Calendar Display removed.

An entrance that waits for the roll

stickyEntrance is either WithRoll — travel up with the credits and stop at the pin, which is
what a block has always done and what every existing document loads as — or AfterRoll: not on
screen at all while the credits go past, then fading up in place over stickyFadeIn seconds once
the last of them has left the top. A beat of empty frame and then a card.

"The rest of the roll" is the strip's last drawn pixel (stripHeight less leadOut — lead-out
is blank and nobody watching counts it as the roll), and it is the other blocks too: a block that
waits also waits for any block still on the frame, since back-to-back cards are what the entrance is
for and one fading up through another on its way out is not that.

The layout does not move for any of it. The block still takes its slot, so turning the entrance
around changes nothing above or below it.

The one new shader. A fade needs an opacity, and the base effect has no parameter for one, so
the blocks are now drawn through a pass of their own with libobs' textured quad and the sampled
alpha scaled. A device that will not compile it falls back to the base effect and draws every block
solid — the fade is lost, the blocks are not. The shader is a string in CreditsSource.cpp rather
than a .effect file, since a data file is one more thing to find at runtime on three platforms.

A release that ends nothing

StickyRelease::ResumeOnlyLeave The Screen And Do Nothing — climbs off the top and has no
say in when the roll is over. That is what lets one card follow another: a thank-you that holds and
moves off, and a second block whose entrance waits, fading up behind it. It still holds the roll
open while it is on screen, so nothing ends underneath it.

The playback loop is written against three predicates rather than the enum — resumes, ends at the
hold, ends at the exit — and the new mode answers all three, so nothing downstream had to learn a
fourth name.

"Off screen" now means the picture, not the slot

This is the reported bug. A block's picture is margin taller than its slot at each end, for
the backdrop's outset and whatever its children paint outside their own boxes — and the release that
waits for the block to leave was asking the slot. So the roll ended, and the ending action fired,
over a card still showing the last band of itself.

StickyBlockPlacement::clearedFrame and offFrame are now where that question is answered, so it
cannot be asked of the slot by accident, and every site that judged visibility by hand goes through
them. ResumeThenEnd now ends the roll at the moment the whole picture has gone, which is what its
name has always promised.

And a block on its way out keeps going out.advanceStickyBlocks took a bool for "is the roll
rolling", and a released block stopped dead the moment the roll was called finished — half off the
top, and staying there. It now takes a StickyClock: rolling, coasting, paused or scrubbed.
Coasting starts nothing new but carries a departure through to the end of itself.

The Calendar Display is gone

A schedule board is not a credit roll. It shipped here because it could reuse the model's typefaces,
panels and gradients, but everything above that — events, days, lanes, slots, categories, a
five-layer style cascade, a free layer of decoration, five clock features, three answers to
overflow, five presets, a column-mapped import and a designer window of its own — is a second
product carried inside the first.

Removed: the source and its registration, the board model and its presets, the board renderer, the
board's designer and import windows, the tag-glyph table (nothing else read it), the fourteen board
suites, and the 225 locale strings behind all of it.

Nothing shared was touched. CsvParser still backs the roll's own import; StyleLibrary,
Background, Gradient, FontBundle, FontResolution, RenderThread, SvgArt,
BackgroundPainter and ImageEffects all had the roll as a caller already. The reuse a future
calendar plugin would want is still there for it.

A note on what changed underneath an existing setting

ResumeThenEnd ("Fire Ending Action After Leaving Screen") used to hold the roll open until the
block had left and then let the roll end naturally; it now ends the roll at the moment the block
clears the frame. For a block at the end of a roll — which is every one of them in practice, since
the roll has finished travelling long before the block's hold does — this is the same instant.
It differs only for a block with credits still scrolling below it, where the old behaviour let
those credits finish. If that turns out to be a roll somebody built, say so and it goes back to
waiting for both.

Checks

  • cmake --build build — the plugin and the harness, clean from scratch, no warnings.
  • ./build/tests/closing-time-tests97 suites, 6025 checks, 0 failures. The board's own
    fourteen suites are the only ones missing from the count.
  • Three new suites: sticky_release_modes (the three predicates and the id round trips for both
    new enums), sticky_entrance_carried (the entrance reaches the compositor and moves no layout),
    sticky_leaving_screen (a block whose slot has just gone has not left the screen — this one
    fails against the old slot-based test, which is the point of it).
  • Round-trip and legacy-default coverage for stickyEntrance and stickyFadeIn added to the
    persistence suite.
  • clang-format and gersemi clean on everything touched.

What is not covered by the harness: the playback state machine and the fade shader both live in
CreditsSource.cpp, which needs a real OBS and a graphics device. The state machine's inputs are
all pure functions the suites do reach; the shader is behind a fallback that costs the fade and
nothing else if it will not compile. Worth an eye on a real roll before merging.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Vx4e1ndwDfczcjrpib7uQj


Generated by Claude Code

…g, and an exit that finishes
A sticky ending block could only ever arrive one way -- travelling up with the credits and
stopping at the pin -- and could only ever be the end of the roll. Three changes, and a fix.
**An entrance that waits.** `stickyEntrance` is either `WithRoll`, which is what a block has
always done, or `AfterRoll`: not on screen at all while the credits go past, then fading up in
place over `stickyFadeIn` seconds once the last of them has left the top. A beat of empty frame
and then a card. "The rest of the roll" is the strip's last drawn pixel -- lead-out is blank and
nobody watching counts it -- and it is the other blocks too, so a card that waits waits for the
one ahead of it as well.
The fade needed an opacity the base effect has no parameter for, so the blocks are now drawn
through a pass of their own with the one shader in the plugin: libobs' own textured quad with the
sampled alpha scaled. A device that will not compile it falls back to the base effect and draws
every block solid, which loses the fade and nothing else.
**A release that ends nothing.** `StickyRelease::ResumeOnly` leaves the screen and has no say in
when the roll is over, which is what lets one card follow another: a thank-you that holds and
moves off, and a second block that fades up behind it. The three predicates the playback loop is
written against -- resumes, ends at the hold, ends at the exit -- answer for it, so nothing
downstream had to learn a fourth name.
**"Off screen" now means the picture, not the slot.** A block's picture is `margin` taller than
its slot at each end, for the backdrop's outset and whatever its children paint outside their own
boxes, and the release that waits for the block to leave was asking the slot. So the roll ended --
and the ending action fired -- over a card still showing the last band of itself.
`StickyBlockPlacement::clearedFrame` and `offFrame` are now where that question is answered, so it
cannot be asked of the slot by accident, and `ResumeThenEnd` ends the roll at the moment the whole
picture has gone rather than a tick or two before.
**And a block on its way out keeps going out.** `advanceStickyBlocks` took a bool for "is the roll
rolling", and a released block stopped dead the moment the roll was called finished -- half off
the top of the frame, and staying there. It now takes a `StickyClock`: rolling, coasting, paused
or scrubbed. Coasting starts nothing new but carries a departure through to the end of itself.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vx4e1ndwDfczcjrpib7uQj
A schedule board is not a credit roll. It shipped here because it could reuse the model's
typefaces, panels and gradients, but everything above that -- events, days, lanes, slots,
categories, a five-layer style cascade, a free layer of decoration, five clock features, three
answers to overflow, five presets, a column-mapped import and a designer window of its own -- is a
second product carried inside the first. It goes to its own plugin later; the reuse it wanted is
still there for it, because none of the shared pieces were ever written for the roll alone.
Gone: the source and its registration, the board model and its presets, the board renderer, the
board's designer and import windows, the tag-glyph table (nothing else read it), the fourteen
board suites, and the 225 locale strings behind all of it.
Nothing under the Credits Marquee changes. Nothing shared was touched: `CsvParser` still backs
the roll's own import, `StyleLibrary`, `Background`, `Gradient`, `FontBundle`, `FontResolution`,
`RenderThread`, `SvgArt`, `BackgroundPainter` and `ImageEffects` all had the roll as a caller
already, and the check is that the whole harness still passes -- 97 suites, 6025 checks -- with
the board's own suites the only ones missing from the count.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vx4e1ndwDfczcjrpib7uQj
…ere they are asked for
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vx4e1ndwDfczcjrpib7uQj
@ZombieHDGaming
ZombieHDGaming merged commit 77f1919 into masterSep 7, 2026
6 checks passed
@ZombieHDGaming
ZombieHDGaming deleted the claude/sticky-ending-block-options-qw39rf branch September 7, 2026 16:59
Sign up for freeto 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.

2 participants

@ZombieHDGaming@claude