Archilyzer · Source

archilyzer

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

commit 2907e08946920fb94b916d7d366a250c65208fc7
parent 14ce4c3d69204dcf226174318058a369df646157
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Fri, 25 Sep 2026 21:30:59 -0400

homepage: the header is the parent mark + Archi|lyzer, no longer tracked uppercase (brand S1)

The CSS triangle becomes the bone-on-slate mark and "Archilyzer" the split
wordmark. The link keeps aria-label "Archilyzer home". brand.spec pins the
header and the rendered icon set.

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

Diffstat:
Mhomepage/app/components/Header.tsx | 27+++++++++++++++++----------
Ahomepage/e2e/brand.spec.ts | 38++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/homepage/app/components/Header.tsx b/homepage/app/components/Header.tsx @@ -1,5 +1,11 @@ import Link from "next/link"; -import { PROJECT_NAME } from "yt-dlp-transcript-common/lib/project"; +import { + PROJECT_NAME, + PROJECT_WORDMARK_LEAD, +} from "yt-dlp-transcript-common/lib/project"; +import { ICON_PALETTES } from "yt-dlp-transcript-common/lib/brand"; +import { BrandMark } from "yt-dlp-transcript-common/components/BrandMark"; +import { Wordmark } from "yt-dlp-transcript-common/components/Wordmark"; import { ThemeToggle } from "yt-dlp-transcript-common/components/ThemeToggle"; import { ThemeMenu } from "yt-dlp-transcript-common/components/ThemeMenu"; import { NAV } from "../lib/nav"; @@ -30,24 +36,25 @@ function NavList({ className }: { className?: string }) { // is the same string on every install. The operator's own naming still governs // /stats/ and the social links in the footer. // -// The mark is a solid triangle — a play head, the thing every recording here -// began as. Bone, not brass: this family spends no colour on chrome. +// The mark is the family's Found-line mark in its parent colours — bone on +// slate, no accent: the project spends no colour on its own chrome. The +// wordmark splits on the subject ("Archi" + "lyzer"); the link keeps its +// explicit name, "Archilyzer home". export default function Header() { return ( <header className="sticky top-0 z-20 border-b border-[var(--border)] bg-[var(--background)]/85 backdrop-blur-md"> <div className="max-w-6xl mx-auto px-5 sm:px-6 flex h-14 items-center gap-6"> <Link href="/" - className="group flex items-center gap-2.5 shrink-0" + className="flex items-center gap-2.5 shrink-0" aria-label={`${PROJECT_NAME} home`} > - <span - aria-hidden="true" - className="h-0 w-0 border-y-[6px] border-y-transparent border-l-[9px] border-l-[var(--foreground)] transition-colors group-hover:border-l-[var(--brand)]" + <BrandMark palette={ICON_PALETTES.archilyzer} className="size-7 shrink-0" /> + <Wordmark + title={PROJECT_NAME} + lead={PROJECT_WORDMARK_LEAD} + className="text-[1.3rem] leading-none tracking-[-0.01em]" /> - <span className="font-display text-[1.05rem] font-semibold uppercase leading-none tracking-[0.11em] text-[var(--foreground)]"> - {PROJECT_NAME} - </span> </Link> <nav aria-label="Main" className="ml-auto hidden sm:block"> <NavList className="gap-6" /> diff --git a/homepage/e2e/brand.spec.ts b/homepage/e2e/brand.spec.ts @@ -0,0 +1,38 @@ +import { expect, test } from "@playwright/test"; +import { ICON_PALETTES, markSvg } from "../../common/lib/brand"; + +// The project site wears the PARENT mark (plans/brand-and-themes.md, slice +// S1): bone on slate in its icons and its header, and the wordmark split on the +// subject — "Archi" heavy, "lyzer" light — no longer tracked uppercase. + +test("the header is the parent mark + Archi|lyzer, still named 'Archilyzer home'", async ({ + page, +}) => { + await page.goto("/"); + const home = page.getByRole("link", { name: "Archilyzer home", exact: true }); + await expect(home).toBeVisible(); + await expect(home.locator("[data-wordmark-lead]")).toHaveText("Archi"); + await expect(home.locator("[data-wordmark-suffix]")).toHaveText("lyzer"); + await expect(home.locator("[data-wordmark]")).not.toHaveCSS("text-transform", "uppercase"); + const mark = home.locator("svg[data-brand-mark]"); + await expect(mark).toHaveAttribute("aria-hidden", "true"); + const fills = await mark.evaluate((svg) => + ["ground", "dim", "lit"].map( + (t) => getComputedStyle(svg.querySelector(`[data-tone="${t}"]`) as Element).fill, + ), + ); + expect(fills).toEqual(["rgb(21, 27, 32)", "rgb(63, 76, 86)", "rgb(231, 237, 241)"]); +}); + +test("the icon set is rendered from the parent mark", async ({ request }) => { + const svg = await request.get("/icons/icon.svg"); + expect(svg.headers()["content-type"]).toBe("image/svg+xml"); + expect(await svg.text()).toBe(markSvg(ICON_PALETTES.archilyzer)); + // The OG image names this one. + const png = await request.get("/icons/icon-512.png"); + expect(png.headers()["content-type"]).toBe("image/png"); + const b = await png.body(); + expect([b.readUInt32BE(16), b.readUInt32BE(20)]).toEqual([512, 512]); + const ico = await request.get("/favicon.ico"); + expect([...(await ico.body()).subarray(0, 4)]).toEqual([0, 0, 1, 0]); +});