PURPOSE

Stateless controlled-input component for the Weapon Workbench timeline. Renders a horizontal range slider plus a readout label and an “auto” resume button, letting the user scrub a normalized timeline parameter t in [0, 1] or hand control back to automatic playback.

OWNS

  • Pure presentational JSX: a flex container, a <input type="range">, a monospace readout <span>, and a conditional ▶ auto <button>.
  • Local derived state only: isAuto (whether the incoming currentT equals the string 'auto') and displayT (the numeric value to show — 0 when auto).
  • Inline styling for the container, slider, readout, and button.
  • Test ids timeline-scrubber, timeline-slider, and timeline-auto-resume.

READS FROM

  • Props.currentT — either a number in [0, 1] or the literal string 'auto', supplied by the parent screen.
  • The native range <input> change event value (e.target.value), parsed via parseFloat.

PUSHES TO

  • Props.onScrub(t: number) — invoked on every slider onChange with the parsed float.
  • Props.onAutoResume() — invoked when the user releases the slider (onMouseUp) while not already in auto mode, and when the explicit ▶ auto button is clicked.

DOES NOT

  • Hold any internal React state (no useState, useRef, useEffect).
  • Persist values to a store, localStorage, or telemetry sink.
  • Manage playback, timers, or animation — the parent owns the auto-advance loop.
  • Validate or clamp currentT; assumes the parent stays in the documented domain.
  • Render touch-specific handlers (onTouchEnd); only onMouseUp triggers auto-resume on release.
  • Apply styles from any stylesheet — all styling is inline.

Signals

  • Outbound scrub: onScrub(parseFloat(value)) on slider change.
  • Outbound auto-resume: onAutoResume() on slider mouseUp (only when not currently auto) and on ▶ auto button click.
  • Visual signal: readout shows 'auto' when in auto mode, otherwise "{t.toFixed(2)} / 1.00"; the ▶ auto button is mounted only when not in auto mode.

Entry points

  • Named export TimelineScrubber(props: Props).
  • Props interface: currentT: number | 'auto', onScrub: (t: number) => void, onAutoResume: () => void.

Pattern notes

  • Discriminated value pattern: a single prop (currentT) encodes both the auto-mode flag and the numeric scrub position via a number | 'auto' union, so the parent never has to send a separate boolean.
  • Fully controlled input: value={displayT} plus onChange={onScrub} means the slider reflects parent state immediately; there is no local debouncing.
  • Range bounds (min=0, max=1, step=0.01) are hard-coded — the timeline parameter is always normalized.
  • Auto-resume on onMouseUp only fires outside auto mode, preventing redundant callbacks when the user merely clicks the slider while auto playback is already active.
  • Inline styling and inline color literals (#1a1a26, #44ffcc, #aaa) — no theme token usage.
  • Accessibility: aria-label="timeline" on the slider; no label on the auto button beyond its text content.