Skip to content

Smooth aurora + hero text state transitions#35

Merged
Soulhackzlol merged 5 commits into
mainfrom
ui/aurora-state-transitions
Jul 5, 2026
Merged

Smooth aurora + hero text state transitions#35
Soulhackzlol merged 5 commits into
mainfrom
ui/aurora-state-transitions

Conversation

@Soulhackzlol

@Soulhackzlol Soulhackzlol commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Stacked on #34 (which stacks on #33) - merge order: #33#34 → this → #36. GitHub retargets automatically as each base merges.

What

The hero now changes state as one coordinated sweep - aurora glow, big number, state pill, and subtext move together - and the per-second stutter in the text and the arming counter is gone.

Aurora: two bugs behind the jank

  1. Colors never actually transitioned. The blobs consume var(--aurora-a/b) inside a radial-gradient, and transition: background cannot interpolate gradient images, so the declared .6s transition silently never ran - every state change was a hard color cut. Fix: the colors are registered custom properties (@property with syntax: '<color>') and the variables themselves transition over ~1.1 s. Browsers without @property keep the old instant swap.

  2. The blobs teleported around the arming state. Arming overrode animation-duration (14 s → 4 s), and changing duration mid-flight remaps elapsed time to a different progress fraction - a visible jump on every enter/exit of buffering. The drift animation is now identical in every state; arming's energy comes from a dedicated .aurora-pulse layer (bottom glow, 0.9 s opacity fade-in, transform-only breathing so its restart never fights the fade).

Text: synchronized sweeps, no more per-second pulsing

  • The big number's color rides the same 1.1 s sweep as the aurora (it used to finish in .25 s, visibly ahead of the glow). The state pill's text/background/border sweep over .8 s instead of hard-cutting.
  • The subtext only animates when the message kind changes. The buffering, bitrate, and auto-cut countdown lines embed numbers that tick up to 4x/s (SSE pushes on every state change at a 250 ms check tick), and every tick replayed the fade - a constant pulse. Same kind now updates in place; a kind change gets a directional swap (old line drops out, new one drops in via a transition-suppressed pre-frame).
  • The arming counter counts continuously: each ~250 ms update animates linearly into the next instead of the old 80 ms ease-out that sprinted then froze ~170 ms between updates. Phase jumps (arm/activate/cut) get a longer 700 ms eased sweep, and the fill bar fills at constant speed. animateNumber also gained a generation guard so mid-flight retargets stop the previous rAF loop instead of stacking duplicate loops on the element.

Verification

  • Decompressed the embedded index.html.gz and confirmed the @property blocks, pulse rules, variable transition, and the new text-swap/counter code all survive build.rs minification.
  • cargo fmt --check clean, cargo test --release: 235 passed.

Two things made state changes feel abrupt:

1. Colors snapped. The blobs consume var(--aurora-a/b) inside a
   radial-gradient, and "transition: background" cannot interpolate
   gradient images, so the declared .6s transition never actually ran.
   The vars are now registered with @Property (syntax '<color>') and
   transitioned on the readout itself, so a state flip reads as one
   ~1.1s color sweep. Browsers without @Property fall back to the old
   instant swap.

2. The blobs teleported around buffering. The arming state overrode
   animation-duration (14s -> 4s), which remaps the animation's elapsed
   time to a different progress fraction - a visible jump on every
   enter/exit. The drift is now identical in every state; arming's
   energy comes from a new dedicated .aurora-pulse layer, a bottom glow
   that fades in via an opacity transition and breathes via a
   transform-only animation, so its keyframe restart never fights the
   fade.

Verified the @Property blocks, pulse rules, and var transition survive
build.rs minification in the embedded output. 235 tests green.
Bundles the text polish into the aurora work so the hero changes state
as one sweep instead of three unsynchronized snaps:

- The big number's color transition now matches the aurora's 1.1s sweep
  (it used to finish in .25s, visibly ahead of the glow), and the state
  pill's text/background/border sweep over .8s instead of hard-cutting.
  The consuming properties interpolate when --sc changes, so no extra
  @Property registration is needed there.

- setSubText now takes a message-kind key and only animates when the
  KIND changes. The buffering, bitrate, and auto-cut countdown lines
  embed numbers that tick up to 4x/s (SSE pushes on every state change,
  checked at 250ms), and every tick replayed the fade - a constant
  pulse. Same kind now updates text in place; a kind change gets a
  directional swap (old line drops out, new one drops in via a
  transition-suppressed pre-frame).

- The arming counter counts continuously: each ~250ms update animates
  linearly into the next instead of the old 80ms ease-out that sprinted
  and then froze ~170ms between updates. Phase jumps (arm/activate/cut)
  get a longer 700ms eased sweep. The fill bar switches to linear width
  for the same reason. animateNumber also gained a generation guard so
  mid-flight retargets stop the previous rAF loop instead of stacking
  duplicate loops on the element.

235 tests green; verified the new code survives build.rs minification.
@Soulhackzlol Soulhackzlol changed the title Smooth aurora transitions between delay states Smooth aurora + hero text state transitions Jul 5, 2026
Two fixes from live use:

1. "Adjusting -> rewinding to 15s (currently 0s)..." described motion
   the engine doesn't do. The delay never rewinds gradually - the cut
   machinery holds position until the ring has enough history, then
   makes ONE IDR-aligned jump (compute_delay_cut's build-buffer-first
   branch). The copy now tracks the server's buffer_building flag:
   "Building history - jumps to 15s once Xs buffered reaches it" while
   waiting, and "Jumping back/forward to 15s of delay..." in the brief
   pre-jump window. The adjusting detector is also gated on
   egress_alive: current_delay_ms derives from the slowest LIVE
   destination and reads 0 with none connected, which made the old line
   show a fake permanent "rewinding (currently 0s)" state. Fixed the
   same "smoothly rewind" wording in arm_delay's doc comment.

2. Disarm / cancel now rolls the big number down to 0.0 over 1.1s, the
   same duration as the aurora + number color sweep, so the count-down
   and the fade-to-idle land as one motion instead of the number
   vanishing ahead of the glow.
Four issues from live use:

1. Disarm 15s -> 0s didn't animate. animateNumber is re-called with the
   same target on every state tick (~4x/s), and the no-change branch
   hard-set textContent to the end value, killing any in-flight roll.
   The idle state repeats after disarm, so ~250ms into the 1.1s
   count-down it snapped to 0. Now the no-change branch only writes text
   when the animation has actually settled (cur.last === target),
   letting an in-flight roll finish.

2. Arming count-up stuttered. It animated over 300ms but the poll
   fallback updates every 500ms, so it finished early and froze. Bumped
   the arming duration to 600ms (linear + the generation guard) so it's
   always still moving when the next value lands, whether the driver is
   SSE (~4x/s) or the 500ms poll.

3. Profile chips (hero) and the Profiles pane flickered - both wiped and
   rebuilt their DOM every state tick. Added a content signature guard
   so they only rebuild when the rendered result actually changes.

4. The "delay too big for your buffer" gate flickered and could
   momentarily unlock an unfillable delay (e.g. 5min at ~7Mbps): it
   planned from the raw instantaneous bitrate, so a dip inflated the
   computed capacity and made the chip clickable for a frame. Planning
   now uses a slow-decaying peak-hold (worst-case bitrate), so the gate
   is stable and can't transiently unlock a delay that can't fill.

235 tests green; verified all four in the embedded minified output.
Base automatically changed from feat/local-test-sink-destination to main July 5, 2026 12:42
@Soulhackzlol
Soulhackzlol merged commit 6c0fbdb into main Jul 5, 2026
4 checks passed
@Soulhackzlol
Soulhackzlol deleted the ui/aurora-state-transitions branch July 5, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant