feat(a11y): wire flash-clamp into autoScrub; document 3-flash/sec audit
Clamp each per-altitude step to the WCAG 2.3.1 floor (no-op at 1200ms, guards a future lowering). Audit: #black fade + audio crossfade can't exceed 3/sec, no clamp needed. boot() now seeds the gate-dismissed flag (returning visitor) so the run-sim test isn't blocked by the new interstitial. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -705,7 +705,14 @@ function autoScrub(targetPos, perAltMs = PER_ALTITUDE_MS) {
|
||||
if (autoRaf) cancelAnimationFrame(autoRaf);
|
||||
const fromPos = pos, dist = targetPos - fromPos;
|
||||
if (!dist) { setPos(targetPos); return; }
|
||||
const ms = perAltMs * Math.abs(dist); // constant per-altitude speed → N steps take N× as long
|
||||
// Photosensitivity floor (WCAG 2.3.1): each altitude step is one luminance
|
||||
// transition (a blended crossfade), so a single step must take >= 1/3 s to stay
|
||||
// <= 3 flashes/sec. The clamp is a no-op at today's 1200ms but guards the floor
|
||||
// if PER_ALTITUDE_MS is ever lowered. (Audit: the only other luminance sources —
|
||||
// the #black cover fade (200ms, single, >=1.2s apart) and the audio-coupled
|
||||
// crossfade — cannot repeat faster than 3/sec, so they need no clamp.)
|
||||
const safeAltMs = HEFFlash.clampDurationMs(perAltMs, 1);
|
||||
const ms = safeAltMs * Math.abs(dist); // constant per-altitude speed → N steps take N× as long
|
||||
let startTs = null;
|
||||
const tick = (ts) => {
|
||||
if (startTs === null) startTs = ts;
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
<script src="config.js"></script>
|
||||
<script src="scrub.js"></script>
|
||||
<script src="alteration.js"></script>
|
||||
<script src="flash.js"></script>
|
||||
<script src="i18n.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user