From 3c3f3753027700249ce4456a73dfe0b5bc00026c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 15:23:28 +0000 Subject: [PATCH] Add up/down key time navigation to temporal time spinner Make the 3D temporal stack's time reel focusable and step one slice at a time with ArrowUp/ArrowDown when it has focus (up = later, down = earlier), matching the drag and scroll metaphors. Adds slider ARIA roles and a focus-visible style. https://claude.ai/code/session_01Ko2yruDbXdBsZ8ZzgL4Y8L --- src/ui/temporal/TemporalView.tsx | 29 +++++++++++++++++++++++++++-- src/ui/temporal/temporal.css | 5 +++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/ui/temporal/TemporalView.tsx b/src/ui/temporal/TemporalView.tsx index 05dacdc..3ecab26 100644 --- a/src/ui/temporal/TemporalView.tsx +++ b/src/ui/temporal/TemporalView.tsx @@ -21,7 +21,11 @@ * glow and sweep as the storm passes when the weather is switched on. */ import { useEffect, useMemo, useRef, useState } from 'react'; -import type { PointerEvent as ReactPointerEvent, RefObject } from 'react'; +import type { + KeyboardEvent as ReactKeyboardEvent, + PointerEvent as ReactPointerEvent, + RefObject, +} from 'react'; import * as THREE from 'three'; import { Canvas, useFrame, useThree } from '@react-three/fiber'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; @@ -849,6 +853,19 @@ function TimeWheel({ }; inertiaRaf.current = requestAnimationFrame(step); }; + // Arrow keys step one slice at a time when the reel is focused, matching the + // drag metaphor: up = later time, down = earlier. + const onKeyDown = (e: ReactKeyboardEvent) => { + if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return; + e.preventDefault(); + stopInertia(); + const dir = e.key === 'ArrowUp' ? 1 : -1; + const { interval, max } = cfgRef.current; + const slice = Math.round(curRef.current / interval); + const next = clampN((slice + dir) * interval, 0, max); + curRef.current = next; + setCurrentMin(next); + }; // Wheel over the controller scrubs time a slice at a time; Ctrl+wheel zooms the // time step instead, staying on the current time. Native + non-passive so it can // preventDefault — which also stops page zoom and the native