From 1f98b7bd8c931c95eff4df8a51eb477643583544 Mon Sep 17 00:00:00 2001 From: BenStullsBets Date: Tue, 30 Jun 2026 09:16:02 -0700 Subject: [PATCH] feat(a11y): flash.js pure WCAG 2.3.1 flash-clamp helper + tests Co-Authored-By: Claude Opus 4.8 (1M context) --- simulator/static/flash.js | 20 ++++++++++++++++++++ simulator/static/flash.test.js | 16 ++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 simulator/static/flash.js create mode 100644 simulator/static/flash.test.js diff --git a/simulator/static/flash.js b/simulator/static/flash.js new file mode 100644 index 0000000..38ac605 --- /dev/null +++ b/simulator/static/flash.js @@ -0,0 +1,20 @@ +// Pure photosensitivity helper. WCAG 2.3.1: no more than 3 general flashes +// (luminance transitions) per second. Given a transition COUNT, returns the +// minimum total duration that keeps the rate at or below 3/sec, and a clamp +// that only ever slows a transition down. UMD: browser `HEFFlash` + require(). +(function (root, factory) { + const api = factory(); + if (typeof module !== "undefined" && module.exports) module.exports = api; + else root.HEFFlash = api; +})(typeof self !== "undefined" ? self : this, function () { + "use strict"; + const MAX_PER_SEC = 3; + function minSafeDurationMs(count) { + const n = Math.max(0, Number(count) || 0); + return (n / MAX_PER_SEC) * 1000; + } + function clampDurationMs(requestedMs, count) { + return Math.max(Number(requestedMs) || 0, minSafeDurationMs(count)); + } + return { MAX_PER_SEC, minSafeDurationMs, clampDurationMs }; +}); diff --git a/simulator/static/flash.test.js b/simulator/static/flash.test.js new file mode 100644 index 0000000..72f1188 --- /dev/null +++ b/simulator/static/flash.test.js @@ -0,0 +1,16 @@ +const test = require("node:test"); +const assert = require("node:assert"); +const F = require("./flash.js"); + +test("minSafeDurationMs: N transitions need N/3 seconds", () => { + assert.strictEqual(F.minSafeDurationMs(3), 1000); // 3 flashes in >=1s + assert.strictEqual(F.minSafeDurationMs(6), 2000); + assert.strictEqual(F.minSafeDurationMs(0), 0); + assert.strictEqual(F.minSafeDurationMs(1), 1000 / 3); +}); + +test("clampDurationMs: stretches only when too fast", () => { + assert.strictEqual(F.clampDurationMs(2000, 3), 2000); // already safe + assert.strictEqual(F.clampDurationMs(200, 3), 1000); // too fast -> clamped up + assert.strictEqual(F.clampDurationMs(500, 1), 500); // single transition, slow enough +});