feat(engine): focus ring breathes at 1.4 s — gentle pulse instead of flat

The keyboard focus ring rendered as a static yellow outline. A new
pulse_focus_overlay system modulates the overlay's BorderColor alpha
with a sin curve over MOTION_FOCUS_PULSE_SECS (1.4 s), breathing the
visible alpha between 0.65× and 1.0× of FOCUS_RING's native value.
The motion is slow enough to read as a calm heartbeat in peripheral
vision rather than a competing animation, and a focus change still
draws the eye because the ring re-attaches at full brightness on
the next pulse cycle.

The pulse honours AnimSpeed::Instant by reading SettingsResource
and skipping the modulation entirely (static FOCUS_RING colour) for
reduced-motion users — matches the convention used elsewhere for
animation gating.

A pure focus_ring_pulse_factor(elapsed_secs) helper is unit-tested
for the curve shape: 0.825 at t=0 (mid-point), 1.0 at the
quarter-period peak, 0.65 at the three-quarter-period trough, and a
sweep across two full periods stays within the [0.65, 1.0] range.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-02 02:40:40 +00:00
parent 525fe0fe76
commit 9887343d8b
2 changed files with 97 additions and 1 deletions
+13
View File
@@ -399,6 +399,19 @@ pub const FOUNDATION_FLOURISH_PEAK_SCALE: f32 = 1.15;
/// 400 ms.
pub const MOTION_LOADING_TICK_SECS: f32 = 0.40;
/// Period of the focus-ring breathing pulse, in seconds.
///
/// The keyboard focus ring's alpha is modulated by a sin-curve over this
/// interval so the indicator gently "breathes" instead of presenting as
/// a flat outline. 1.4 s reads as a calm heartbeat — slow enough that
/// the motion is in the player's peripheral vision rather than competing
/// for attention, fast enough that a focus change still draws the eye.
/// Not run through [`scaled_duration`]: the pulse is an accessibility
/// affordance, not gameplay motion. `AnimSpeed::Instant` is honoured at
/// the system level by skipping the pulse entirely (see
/// `pulse_focus_overlay` in `ui_focus`).
pub const MOTION_FOCUS_PULSE_SECS: f32 = 1.4;
/// Hover delay before a tooltip appears, in seconds. Long enough that
/// players gliding the cursor across the HUD don't see flicker; short
/// enough that "stop and read" feels responsive. Not run through