web: hide native number spinners; slower, fully staggered rounds
Per Justin: the native number-input spinners rendered as light boxes on the dark theme, so they are gone app-wide (typing and arrow keys keep working). Playback pacing: rounds now take 1000 ms at 1x, appearance moments spread across 95% of the interval via a murmur3-style full-avalanche hash, and each dot fades over 30% of the interval, so a round reads as a continuous trickle instead of a flash.
This commit is contained in:
parent
d9b3812306
commit
3a4e21b701
4 changed files with 27 additions and 7 deletions
|
|
@ -72,6 +72,19 @@ button {
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The native number-input spinners render as light boxes that clash with
|
||||||
|
the dark theme and crowd the compact fields; arrow keys and typing keep
|
||||||
|
working without them. */
|
||||||
|
input[type='number'] {
|
||||||
|
appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='number']::-webkit-outer-spin-button,
|
||||||
|
input[type='number']::-webkit-inner-spin-button {
|
||||||
|
appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.visually-hidden {
|
.visually-hidden {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ function onNodeClick(nodeIndex: number, event: MouseEvent) {
|
||||||
// the panel stats), then fade in over the rest of the interval; playback
|
// the panel stats), then fade in over the rest of the interval; playback
|
||||||
// never shows a finished still frame between rounds.
|
// never shows a finished still frame between rounds.
|
||||||
const roundIntervalMs = computed(() => ROUND_MS / store.state.speed)
|
const roundIntervalMs = computed(() => ROUND_MS / store.state.speed)
|
||||||
const popDurationMs = computed(() => roundIntervalMs.value * (1 - APPEAR_WINDOW) + 120)
|
const popDurationMs = computed(() => roundIntervalMs.value * 0.3)
|
||||||
|
|
||||||
function popDelay(nodeIndex: number): string {
|
function popDelay(nodeIndex: number): string {
|
||||||
return `${appearanceJitter(nodeIndex) * APPEAR_WINDOW * roundIntervalMs.value}ms`
|
return `${appearanceJitter(nodeIndex) * APPEAR_WINDOW * roundIntervalMs.value}ms`
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import { useSimStore, type SimStore } from './useSimStore'
|
||||||
// one-time autoplay). Playback never loops; at the final round the play
|
// one-time autoplay). Playback never loops; at the final round the play
|
||||||
// button becomes a replay affordance.
|
// button becomes a replay affordance.
|
||||||
|
|
||||||
export const ROUND_MS = 700
|
export const ROUND_MS = 1000
|
||||||
export const REDUCED_MOTION_ROUND_MS = 1000
|
export const REDUCED_MOTION_ROUND_MS = 1200
|
||||||
|
|
||||||
const SPEED_CYCLE: Record<number, 0.5 | 1 | 2> = { 0.5: 1, 1: 2, 2: 0.5 }
|
const SPEED_CYCLE: Record<number, 0.5 | 1 | 2> = { 0.5: 1, 1: 2, 2: 0.5 }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { mulberry32 } from './mulberry32'
|
|
||||||
|
|
||||||
// Cumulative reach at a playback round, shared by the panel stats and the
|
// Cumulative reach at a playback round, shared by the panel stats and the
|
||||||
// reach chart so both always agree with the network picture.
|
// reach chart so both always agree with the network picture.
|
||||||
export function reachedCountAtRound(reachedAtRound: number[], round: number): number {
|
export function reachedCountAtRound(reachedAtRound: number[], round: number): number {
|
||||||
|
|
@ -12,10 +10,19 @@ export function reachedCountAtRound(reachedAtRound: number[], round: number): nu
|
||||||
// jitter drives the dot's animation-delay and the live counter, so the
|
// jitter drives the dot's animation-delay and the live counter, so the
|
||||||
// percentage ticks up exactly as dots start appearing.
|
// percentage ticks up exactly as dots start appearing.
|
||||||
|
|
||||||
export const APPEAR_WINDOW = 0.7
|
export const APPEAR_WINDOW = 0.95
|
||||||
|
|
||||||
|
// A full-avalanche integer hash (murmur3 finalizer): consecutive node
|
||||||
|
// indices land anywhere in [0, 1), so the appearance moments of a round's
|
||||||
|
// nodes are spread evenly instead of clustering into one flash.
|
||||||
export function appearanceJitter(nodeIndex: number): number {
|
export function appearanceJitter(nodeIndex: number): number {
|
||||||
return mulberry32(nodeIndex * 7919 + 17)()
|
let mixed = Math.imul(nodeIndex + 1, 0x9e3779b1)
|
||||||
|
mixed ^= mixed >>> 16
|
||||||
|
mixed = Math.imul(mixed, 0x85ebca6b)
|
||||||
|
mixed ^= mixed >>> 13
|
||||||
|
mixed = Math.imul(mixed, 0xc2b2ae35)
|
||||||
|
mixed ^= mixed >>> 16
|
||||||
|
return (mixed >>> 0) / 4294967296
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reach as displayed mid-transition: every earlier round fully, plus the
|
// Reach as displayed mid-transition: every earlier round fully, plus the
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue