- ),
- },
{
// Every part recomposed into a live command palette — sectioned,
// shortcut-hinted, and typing filters it in place.
@@ -1292,13 +822,10 @@ const steps: Step[] = [
const compactSteps = steps.filter((s) => s.compact)
const maxCodeLines = Math.max(...steps.map((s) => s.code.split("\n").length))
-// Pagination lists only the headline steps; mid steps play during auto-advance
-// but aren't clickable stops. Each entry keeps its index into its list so the
-// rail/dots can jump straight to it.
+// Each entry keeps its index into its list so the rail/dots can jump straight
+// to it.
const paginate = (list: Step[]) =>
- list
- .map((s, index) => ({ title: s.title, index, mid: s.mid }))
- .filter((s) => !s.mid)
+ list.map((s, index) => ({ title: s.title, index }))
const paginatedSteps = paginate(steps)
const compactPaginatedSteps = paginate(compactSteps)
@@ -1309,18 +836,9 @@ export type CompositionPlayer = ReturnType
// (1 + delayEnter)×duration + the stagger tail — not at `duration`. Every dwell
// above has to clear that, or the next step cuts the animation off mid-flight.
const CODE_ENTER_DELAY = 0.7
-const CODE_SPAN = 1 + CODE_ENTER_DELAY
const CODE_DURATION_MS = 700
const CODE_STAGGER_MS = 2
-// A manual walk plays the exact same code transition as auto-play, only with a
-// smaller stagger — so each beat must clear the full span plus the stagger tail
-// of the longest (~120-token) snippet.
-const WALK_CODE_STAGGER_MS = 0.5
-const MANUAL_BEAT_MS = Math.ceil(
- CODE_SPAN * CODE_DURATION_MS + 120 * WALK_CODE_STAGGER_MS,
-)
-
// Shared player: auto-advance while visible, with a CSS animation as the step
// clock (see StepTimer) so the visible progress and the advance tick can never
// drift. Hovering or focusing the showcase pauses; the play/pause button is a
@@ -1429,61 +947,14 @@ export function useCompositionPlayer({ compactBelowLg = false } = {}) {
})
}, [])
- // Manual navigation (rail/dots): when the target is the next headline, play
- // the mid beats between here and there on a fast cadence instead of
- // hard-jumping, so the code still arrives in small blocks. Backward jumps
- // and far jumps (crossing another headline) stay direct.
- const walkTimerRef = useRef | null>(null)
- const cancelWalk = useCallback(() => {
- if (walkTimerRef.current) {
- clearTimeout(walkTimerRef.current)
- walkTimerRef.current = null
- }
- }, [])
- useEffect(() => cancelWalk, [cancelWalk])
-
// Restart from the top when the step list swaps (breakpoint cross) — the
// current index points into the other list.
useEffect(() => {
- cancelWalk()
stepRef.current = 0
setStep(0)
- }, [compact, cancelWalk])
+ }, [compact])
- const [walking, setWalking] = useState(false)
- const goToStep = useCallback(
- (next: number) => {
- cancelWalk()
- const from = stepRef.current
- const between = activeSteps.slice(from + 1, next)
- const reduce = window.matchMedia(
- "(prefers-reduced-motion: reduce)",
- ).matches
- if (
- reduce ||
- next <= from ||
- between.length === 0 ||
- !between.every((s) => s.mid)
- ) {
- setWalking(false)
- applyStep(next)
- return
- }
- setWalking(true)
- const walk = () => {
- applyStep(stepRef.current + 1)
- if (stepRef.current < next) {
- walkTimerRef.current = setTimeout(walk, MANUAL_BEAT_MS)
- } else {
- // Clears in the same commit as the final step, so the arrival plays at
- // full duration — nothing follows it to cut it off.
- setWalking(false)
- }
- }
- walk()
- },
- [applyStep, cancelWalk, activeSteps],
- )
+ const goToStep = applyStep
const advance = useCallback(
() => applyStep((stepRef.current + 1) % activeSteps.length),
@@ -1505,13 +976,8 @@ export function useCompositionPlayer({ compactBelowLg = false } = {}) {
// The index may briefly outlive a list swap — the reset effect above hasn't
// run yet on that render.
const current =
- activeSteps[Math.min(step, activeSteps.length - 1)] ?? firstStep
- // A mid step maps to the headline step it's building toward (the next
- // paginated entry), so that entry stays lit while the beats play.
- const activePaginated = Math.max(
- 0,
- paginated.findIndex((p) => p.index >= step),
- )
+ activeSteps[Math.min(step, activeSteps.length - 1)] ?? activeSteps[0]!
+ const activePaginated = Math.min(step, paginated.length - 1)
const stepDurationMs = current.durationMs
const reducedMotion =
mounted && window.matchMedia("(prefers-reduced-motion: reduce)").matches
@@ -1540,7 +1006,6 @@ export function useCompositionPlayer({ compactBelowLg = false } = {}) {
reducedMotion,
paginated,
activePaginated,
- codeStaggerMs: walking ? WALK_CODE_STAGGER_MS : CODE_STAGGER_MS,
}
}
@@ -1916,7 +1381,6 @@ export function CompositionCode({
options={{
duration: reducedMotion ? 0 : duration,
stagger,
- // Pinned: CODE_SPAN is only correct if this is what the renderer uses.
delayEnter: CODE_ENTER_DELAY,
containerStyle: false,
}}
@@ -1926,14 +1390,8 @@ export function CompositionCode({
export function CompositionAnimation({ className }: { className?: string }) {
const player = useCompositionPlayer()
- const {
- mounted,
- containerRef,
- current,
- reducedMotion,
- setHoverPaused,
- codeStaggerMs,
- } = player
+ const { mounted, containerRef, current, reducedMotion, setHoverPaused } =
+ player
return (
) : (