Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 907cfd4aa9b93d024c88d144bbfcc10e6f3860a2
parent 4de4d9514a17e357c35384783cae2bc14121f953
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Fri, 25 Sep 2026 23:11:55 -0400

common: brand tests pin the 4.5:1 bar as a literal, the sRGB curve at its boundary pair, and all 21 accent values (brand S3)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Mcommon/lib/accent.test.ts | 6++++--
Mcommon/lib/brand.test.ts | 36++++++++++++++++++++++++++----------
2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/common/lib/accent.test.ts b/common/lib/accent.test.ts @@ -65,6 +65,8 @@ const CUSTOMS = [ ]; test("resolveAccent: a custom hex is fitted to 4.5:1 on every ground and with its ink", () => { + // A literal bar, so an edit to MIN_ACCENT_CONTRAST cannot move fit and test together. + assert.equal(MIN_ACCENT_CONTRAST, 4.5); for (const hex of CUSTOMS) { const r = resolveAccent(hex); assert.equal(r.id, "custom"); @@ -73,8 +75,8 @@ test("resolveAccent: a custom hex is fitted to 4.5:1 on every ground and with it assert.match(v, /^#[0-9a-f]{6}$/); const ground = contrastRatio(v, BASE_GROUNDS[base]); const ink = contrastRatio(v, ACCENT_INK[base]); - assert.ok(ground >= MIN_ACCENT_CONTRAST, `${hex} on ${base} → ${v}: ${ground.toFixed(2)} vs ground`); - assert.ok(ink >= MIN_ACCENT_CONTRAST, `${hex} on ${base} → ${v}: ${ink.toFixed(2)} vs ink`); + assert.ok(ground >= 4.5, `${hex} on ${base} → ${v}: ${ground.toFixed(2)} vs ground`); + assert.ok(ink >= 4.5, `${hex} on ${base} → ${v}: ${ink.toFixed(2)} vs ink`); } } }); diff --git a/common/lib/brand.test.ts b/common/lib/brand.test.ts @@ -34,15 +34,17 @@ test("accents: the table is the plan's, keyed and ordered by ACCENT_IDS", () => } } assert.equal(DEFAULT_ACCENT, "signal"); - // Spot-check the table against plans/brand-and-themes.md "Accents". - assert.deepEqual(ACCENTS.signal, { - id: "signal", - name: "Signal", - onDark: "#5fa8a0", - onLight: "#2e7b73", - onSepia: "#2b756e", + // The whole table, literally, against plans/brand-and-themes.md "Accents": + // a typo that still clears 4.5:1 would pass the contrast test below. + assert.deepEqual(ACCENTS, { + signal: { id: "signal", name: "Signal", onDark: "#5fa8a0", onLight: "#2e7b73", onSepia: "#2b756e" }, + brass: { id: "brass", name: "Brass", onDark: "#e3b15c", onLight: "#95661a", onSepia: "#8e6119" }, + vermilion: { id: "vermilion", name: "Vermilion", onDark: "#ec7a52", onLight: "#b3431f", onSepia: "#b3431f" }, + violet: { id: "violet", name: "Violet", onDark: "#b49cf2", onLight: "#6a4bc4", onSepia: "#6a4bc4" }, + sakura: { id: "sakura", name: "Sakura", onDark: "#ee8fb5", onLight: "#a83a6a", onSepia: "#a83a6a" }, + blue: { id: "blue", name: "Blue", onDark: "#74a9f2", onLight: "#2d5fb8", onSepia: "#2d5fb8" }, + green: { id: "green", name: "Green", onDark: "#7cc46a", onLight: "#3f7a2c", onSepia: "#3d772b" }, }); - assert.equal(ACCENTS.green.onSepia, "#3d772b"); assert.equal(isAccentId("brass"), true); assert.equal(isAccentId("Brass"), false); assert.equal(isAccentId("#e3b15c"), false); @@ -52,14 +54,18 @@ test("accents: the table is the plan's, keyed and ordered by ACCENT_IDS", () => // that base's ground AND against the ink set on it (white on light/sepia, the // dark ground on dark). 7 accents × 3 bases × 2 = 42 checks. test("accents: every value reaches 4.5:1 on its ground and with its ink", () => { + // The bar itself is pinned as a literal: comparing only against the + // imported constant would let an edit to brand.ts lower rule and test + // together. + assert.equal(MIN_ACCENT_CONTRAST, 4.5); let checks = 0; for (const id of ACCENT_IDS) { for (const base of Object.keys(BASE_GROUNDS) as BaseGround[]) { const hex = ACCENTS[id][ON[base]]; const ground = contrastRatio(hex, BASE_GROUNDS[base]); const ink = contrastRatio(hex, ACCENT_INK[base]); - assert.ok(ground >= MIN_ACCENT_CONTRAST, `${id} on ${base}: ${ground.toFixed(2)} vs ground`); - assert.ok(ink >= MIN_ACCENT_CONTRAST, `${id} on ${base}: ${ink.toFixed(2)} vs ink`); + assert.ok(ground >= 4.5, `${id} on ${base}: ${ground.toFixed(2)} vs ground`); + assert.ok(ink >= 4.5, `${id} on ${base}: ${ink.toFixed(2)} vs ink`); checks += 2; } } @@ -75,6 +81,16 @@ test("contrastRatio: the WCAG endpoints", () => { assert.equal(contrastRatio("#ffffff", "#000000"), contrastRatio("#000000", "#ffffff")); }); +// The endpoints hold for any monotone curve, a naive gamma 2.2 included. The +// sRGB boundary pair pins the real one: #767676 is the lightest grey that +// passes 4.5:1 on white, and #777777 the first that does not. +test("contrastRatio: the sRGB curve, at the 4.5:1 boundary on white", () => { + assert.equal(contrastRatio("#767676", "#ffffff").toFixed(2), "4.54"); + assert.equal(contrastRatio("#777777", "#ffffff").toFixed(2), "4.48"); + assert.ok(contrastRatio("#767676", "#ffffff") >= 4.5); + assert.ok(contrastRatio("#777777", "#ffffff") < 4.5); +}); + test("bases and icon palettes are the plan's", () => { assert.deepEqual(BASE_GROUNDS, { light: "#f3f6f7", sepia: "#f4ecd8", dark: "#0c0a08" }); assert.deepEqual(ICON_PALETTES.archilyzer, { ground: "#151b20", dim: "#3f4c56", lit: "#e7edf1" });