feat: v0.9.1 — left-pane time controls refined: log-scale slider (t→round(60^t), 250 ms debounced commit with release flush + in-flight queue) replaces the scale select; game clock now shows seconds (HH:MM:SS UTC)
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
// Pure log-scale mapping helpers for the time-scale slider (v0.9.1) — no game logic,
|
||||
// unit-testable in node. Slider position t ∈ [0,1] ↔ scale = round(60^t), so equal
|
||||
// distances on the slider correspond to equal multiplicative steps: 1× at t=0, ~8×
|
||||
// mid-slider, 60× at t=1 (matching POST /api/sim's clamp range).
|
||||
|
||||
export const MIN_SCALE = 1;
|
||||
export const MAX_SCALE = 60;
|
||||
|
||||
const clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v));
|
||||
|
||||
// t → scale. Exact at the endpoints: sliderToScale(0) === 1, sliderToScale(1) === 60.
|
||||
export function sliderToScale(t: number): number {
|
||||
const tt = clamp(Number.isFinite(t) ? t : 0, 0, 1);
|
||||
return Math.round(clamp(Math.pow(MAX_SCALE, tt), MIN_SCALE, MAX_SCALE));
|
||||
}
|
||||
|
||||
// scale → t (inverse of the pre-rounding mapping). Exact at the endpoints:
|
||||
// scaleToSlider(1) === 0, scaleToSlider(60) === 1. Round-trips every integer 1..60.
|
||||
export function scaleToSlider(scale: number): number {
|
||||
const s = clamp(Number.isFinite(scale) ? scale : MIN_SCALE, MIN_SCALE, MAX_SCALE);
|
||||
return Math.log(s) / Math.log(MAX_SCALE);
|
||||
}
|
||||
Reference in New Issue
Block a user