# Homepage Changelog ## [Unreleased] - **The *Running an archive* doc says how to run one from a shell or an agent.** A new section, *From a shell or an agent*, names the three surfaces — `pnpm ops` (the running editor's actions over HTTP, with `ARCHILYZER_EDITOR_URL` and `WORKER_TOKEN`), `pnpm archilyzer` (the core's command line) and the MCP server — with three example commands, and links the source's OPERATING.md (recipes) and COMMANDS.md (every command and action). - **The homepage builds and deploys from the Docker image too.** It is a publish stage like a site's: `archilyzer publish homepage [--deploy]` (or its row on /sites → Publish) builds it — the `/source` mirror included, from the repository `docker-compose.source.yml` mounts read-only — into `homepage/out`, stamps it, and deploys that build to its Pages project, or with `--to local` into the volume the container's `homepage` service serves. The image has the pinned git-filter-repo; it has no gitleaks or stagit, so a container build skips the secret scan with a warning and ships no history pages. - **A site that publishes only its reports is not on the homepage.** A site with `publish: "cited"` has no Official Instances card, chart series, `/stats` entry or recent item, is not in `channel-sites.json`, and the channels only it carries count in no total — as an unlisted site, whatever its listing setting says. A site with reports that publishes its full corpus is listed as before. - **The AI and MCP doc has a Ten-minute setup.** Right after the MCP server's introduction, one block runs Claude Code against a published archive, the Jeralyzer as the example: clone the source (or unpack the tarball on Downloads), `pnpm install`, `claude mcp add archilyzer`, start `claude` and try `/ask`; then what it needs, why the server must be registered as `archilyzer` (the shipped `/ask` and `/sweep` call `mcp__archilyzer__…`), the two optional editor lines for `fetch_clip`, `TRANSCRIPT_HUB_URL`, where the `mcp.json` form for other clients is, and WSL2 on Windows. "What it can do" is a heading of its own after it. Every archive's **Use with AI** link now lands on this page. - **The Ten-minute setup starts the server with the source's own command, `pnpm --silent -C "$PWD" archilyzer mcp`**, as the README and the MCP server's README do. `--silent` keeps pnpm's own lines off the output the client reads the server's replies on, and a note says so. The note on other clients gives the `mcp.json` entry's arguments in the same form. - **`/source/` links the source's history.** A History block — how many commits (past 10,000, "the latest 10,000 of N"), the newest one (linking to its page), and links to the Log, the Refs and the Atom feed — shows when the build published the history pages (`/source/git/`, rendered by stagit); without them there is no History block. The history pages open on the homepage's ground (the reader's stored choice, else Dark; without JavaScript, the system's), start with one line back to `/source/`, and their Files page is an index into the raw tree. The e2e shows the page with and without a history from a fixture publish (`E2E_SOURCE_PUBLIC_DIR`, never read by a production build), and walks the real pages when the checkout has published them. - **The growth chart draws its smallest instances together as Other.** Two or more instances that each hold under 5% of the chart's total are one band, **Other**, on top of the stack, in a near-neutral grey of its own (`--chart-other`: 7.36:1 on the Light ground, 3.22:1 on the Dark one, and apart from every instance colour for colour-blind readers); an instance at exactly 5% keeps its band, and a single one under 5% is not grouped. The other instances keep their bands and their colours. The legend lists them and Other; the caption says what Other is and the chart's description names the instances in it; every month's hover title and the Numbers by year table still name every instance. At this release's numbers Hasanalyzer, Rekietalyzer and Jasolyzer are Other. The instance cards and `/stats` are unchanged. The e2e fixture's fifth site transcribes 4 a day rather than 5, so two of its six sites are grouped. - **An unlisted site is not on the homepage.** A site whose settings turn off **List on the Archilyzer homepage and hub** (`listed: false`) has no Official Instances card, chart series, `/stats` entry or recent item, is not in `channel-sites.json` or `stats/`, and the channels only it carries count in none of the numbers, the headline totals included. The summary's version is 6. The e2e fixture has a seventh, unlisted site that no page names. - **`/#instances` goes straight to Official Instances.** The section carries `id="instances"`, clear of the sticky header, and every archive's header now links there (`INSTANCES_URL` in `common/lib/project.ts`). With no sites the link lands on the top of the page. - **The social links are in the header beside the theme toggle, and on a small screen the header keeps the name.** The operator's social icons (`homepage.json`'s, else `settings.json`'s) sit in the header's bar as well as in the footer's Elsewhere column, followed by the theme toggle, all spaced alike. From 768 px wide the bar is wordmark, nav, icons, toggle; below 768 px it is wordmark, icons, toggle, and the nav has the rule below to itself, where its four links fit. From 520 px wide the header shows every link, up to four (with more, the ones marked **Keep in header on small screens** first, then the last of the rest); below 520 px it shows only the marked ones (none marked → none; the switch is 32.5rem, so at a larger text size it comes later), and the wordmark keeps its full name: "Archilyzer" shows from 292 px wide on a touch screen with one marked link. The footer always shows every link. Only as last resorts, on a screen narrower still or at a much larger text size, does the wordmark's text drop (its mark stays) and do the icons scroll sideways in their own box, the last one in view first. Each is an icon named by its label, with no text beside it. - **One theme toggle in place of the two theme buttons.** The header's theme menu (Base and Accent) and its base toggle are one toggle, the last of the header's icons, that cycles the ground (System, Light, Dark) and is named for the next one. There is no accent to pick: the homepage's is its own, Signal, and an accent stored by an earlier build is ignored here, with no flash. - **Two grounds, Light and Dark.** The third ground, the warm paper one, is gone: the toggle cycles System, Light and Dark. A reader who had chosen it gets Light, before the page first paints and with no other ground on the way, and the stored choice becomes Light. - **Changelog is in the footer only.** The header's nav is Docs, Source, Downloads and Stats; the footer's Sections list and the 404 page keep Changelog. - **Each Official Instances card names its site with the site's wordmark.** The first part of the name is set heavy in the site's own accent and the rest light, as the site's own header sets it (Jer·alyzer, Hasan·alyzer, …), at the card title's size; the accent is fitted to the ground in force and reads above 4:1 on the card on Light and Dark. A site with no configured lead, or a summary built before this, shows its title plain as before. `homepage-summary.json` gains an optional `wordmarkLead` per site (still version 5). - **The growth chart's bands are separated by a 2 px gap in the ground's colour, where both bands can spare it.** The gap runs along a band's upper edge where another band sits on it, the same 2 px at every width (it was a 1.25 px line in the page colour). It is drawn only where both bands keep at least a pixel of their own colour, measured at right angles to the edge at the narrowest width the chart is drawn at: on a steep month, and beside the thinnest instances, the bands touch instead, so no band is ever covered, and the gap shows in stretches rather than all along. In high-contrast mode the gap is the system's background colour. The gridlines are unchanged. The `/stats` charts' stacked bars get the same 2 px gap in the chart panel's colour; their stacked areas keep their coloured top lines. - **Larger social links, with a focus ring.** Each icon, in the header and the footer, is a 36 px target around its 20 px glyph (44 px on a touch screen), in the muted text colour and the text colour on hover; the footer's were 20 px, in the faint colour, with no ring. Keyboard focus draws a 2 px ring in the accent, and in high-contrast mode the browser's own focus outline. An icon of two or more colours keeps its colours, and every icon paints inside its own box. A stored icon that fails the check a save runs is shown as its label (at most 10rem, with an ellipsis) instead. - **Tab no longer stops on the header's scrolling boxes in Firefox.** When the social icons' box or the nav's rule under the header overflows (a screen under about 300 px, or a large text size), Firefox made it a tab stop with no name of its own; the icons and links inside are the stops now, and each scrolls into view as it takes focus. - **The e2e no longer reads the checkout's `settings.json` or `homepage.json`.** Its dev server reads `e2e/.e2e-settings.json` (`SETTINGS_FILE`), written by `e2e/fixture-social.ts`: three synthetic icons (a gradient with an outline, one colour, and a two-colour disc pasted with only its size), put through the same check a save runs; and `SITES_DIR` points at an empty directory. `e2e/social.spec.ts` covers the header and footer rows (at every width, with 1, 3 and 4 links, both pointers; the scroll fallback; hostile stored icons that must neither run nor fetch), `e2e/toggle.spec.ts` the theme toggle and that a stored accent is ignored, `e2e/svg-vectors.spec.ts` that every accepted icon stays inside its `` in a real parse, `e2e/growth-chart.spec.ts` the chart's gaps and that it paints its true peak and every band, and `e2e/instance-wordmark.spec.ts` the cards' names; specs change the ground through one helper, `chooseTheme` (`e2e/helpers.ts`). - **A site's card counts every transcript, and never shows 0 channels while it serves recordings.** A transcript that arrived after its video was first indexed, or a video with YouTube captions alone, could be left out of the family's numbers: one site served 1,889 recordings and its card said 0 transcripts, 0 channels and 0 hours. Such transcripts are counted now — in the card, the family totals and the archive-growth chart — and one with no transcription date is left off only what is placed by that date: the charts by transcription date, "this month" and the recent list. The official-instance figures on the hub move with them. - **The source is on the site, with its history: `/source/`.** A new **Source** page (and nav entry) gives `git clone https://archilyzer.pages.dev/source/archilyzer.git`, a read-only mirror of the main branch regenerated with every deploy, with its head, the private commit it reflects, a link to browse every file raw at `/source/tree/`, and the tarball with its size and sha256. Commit ids differ from the private repository's, because machine paths are scrubbed on the way out, and the page says so. A build without a published source says "No source published in this build." instead of offering a clone. The Downloads tarball is now regenerated by every build (its commit is the mirror's), and the page points at the mirror for history. The docs that said there is no public repository (*Install*, the FAQ, *What is Archilyzer*) now say how to clone. Below `md` the header's nav drops to its own row, as it did below `sm`, because five labels no longer fit beside the wordmark. `_headers` serves the raw tree as plain text. - **The docs' *Building several sites at once* page says what Build all does.** It called the container pipeline opt-in, turned on in the settings. Build all sites builds every site in parallel in containers whenever a container engine is available, and one after another when none is; there is nothing to switch on. - **A single-colour social icon shows on every ground.** The footer's social icons are the operator's (`homepage.json`'s, else `settings.socialLinks`), normalized when they are saved (`normalizeSocialSvg`, release 11 slice O1). An icon drawn in one colour now takes the footer's colour throughout; before, a part that carried its own colour kept it, so X's official logo, which is white, was invisible on the Light ground. An icon of two or more colours, such as YouTube's red mark with its white triangle, keeps its colours as pasted. "No fill", gradients, masks, clip paths and animation timing are never changed, and a clip path's own colour does not count, so a one-colour icon exported from Figma follows the footer too. It applies when the settings are next saved, then needs a rebuild and deploy of the homepage. - **In high-contrast mode the header mark's tile keeps its edge.** In Windows' high-contrast mode (forced colours) the reader's own background replaces the page on every ground and can be as dark as the slate tile, whose ring is only drawn on Dark. In that mode the tile gets a 1-pixel outline in the reader's text colour, on every ground, following its rounded corners. Nothing changes outside that mode. - **A sixth official instance has a chart colour of its own.** The growth chart, its legend and `/stats` had five validated colours, so a sixth site fell to a pink within a degree of the fifth's magenta. There is now a sixth, a rust (`--chart-6`: `#823c10` on Light, `#a54a08` on Dark), which is Vermilion's hue family, so Jasolyzer's card and its layer will share a hue once it is published. It clears every pair with the other five on each ground for colour-blind readers (the dataviz validator, all pairs; worst CVD ΔE 9.1, normal 16.3). Any six sites now wear the six validated colours; `/stats`' sixth channel gets the rust too. - **A custom-hex accent reads on every ground.** An Official Instances card whose site sets its own hex painted it exactly as set, so a pale one was all but invisible on Light. It is now fitted to each ground the way the site's own pages fit it (4.5:1, `resolveAccent`). No live site uses one. - **The e2e no longer needs the operator's data.** It reads a synthetic summary built by the real summary builder (`e2e/fixture-summary.ts`, six sites, deterministic) instead of `public/homepage-summary.json`, so a fresh clone runs every spec instead of skipping eight. `e2e/fixture-accents.ts` is gone. - **On the Dark ground the header mark's tile has a thin outline.** Its slate tile now has a 1-pixel ring just outside it, following its rounded corners, in the colour of the mark's unlit lines, so the tile's edge shows against the dark page. Light is unchanged, and so are the icons. - **The lines inside the Archilyzer mark are easier to see.** The header mark's and the icons' three unlit lines now read at 3:1 against the slate tile instead of 2:1. - **The homepage opens on the Dark ground in Signal, even with JavaScript off, and a reader can pick another ground.** The header's toggle cycles System → Light → Dark; the accent is the homepage's own, Signal. The old Archilyzer theme family is gone, and so are the other four: the dark ground is now the warm ink the archives used. Type is Archivo, IBM Plex Sans and IBM Plex Mono. The chart's third colour is a violet, well clear of the "gone" red, and the chart stacks its instances in palette order, so no two touching layers are hard to tell apart for a colour-blind reader. A stored theme from before carries over once. The docs' *Operate* page describes the accent. - **The Found-line mark.** The header's CSS triangle is now the family's parent mark (bone on slate) and "ARCHILYZER" is the split wordmark "Archi|lyzer" — heavy lead, light suffix, no longer tracked uppercase; the link is still named "Archilyzer home". The icons and `/favicon.ico` are no longer committed: `app/icons/[file]/route.ts` and `app/favicon.ico/route.ts` render them from `common/lib/brand.ts` at build, and `` gains `icon-32.png`. The OG image is still `/icons/icon-512.png`. - **The footer no longer links to Ko-fi.** The "Elsewhere" column is the operator's social icons again, and a homepage with none shows no column. - **The Official Instances cards wear each site's accent, and the chart wears its hue.** A card's left stripe is its site's accent at that accent's value for the reader's ground; a custom hex is shown as is, and a site with no accent keeps its chart colour. The growth chart, its legend and `/stats` draw each site in the validated chart colour of its accent's hue family (`siteChartColors`, `common/lib/siteColor.ts`: Brass → amber, Blue → blue, Violet → violet, Green → green, Sakura → magenta), since the accents themselves fail as a chart palette. No two sites share a colour. The `/stats` By-site leaderboard keeps each site's colour instead of colouring by rank. The e2e reads a copy of the summary with fixture accents (`HOMEPAGE_SUMMARY_FILE`, `e2e/fixture-accents.ts`). ## 2026-08-12 - **This package is the project's site now.** It was a shelf of one operator's archives dressed in the same warm-brass costume as the archives themselves. It is now the place that explains, documents and distributes **Archilyzer** — because three live public archives existed and *nothing said what built them*, while the root README was still titled "yt-dlp transcript browser" and claimed three packages when there are five. - **`/` is the marketing home.** What the software is, what it produces, and a download. - **`/stats/` is the dashboard**, moved verbatim — restoring the name it had before `33ed2fe` deleted it. Nothing about the charts changed. - **`/docs/`** renders hand-written Markdown from `content/docs/`, ordered and grouped by a typed manifest (`content/docs.ts`) rather than frontmatter, so a typo is a `tsc` error and the nav order is one reviewable list. - **`/downloads/`** publishes the source snapshot; **`/changelog/`** renders the viewer's. - **The site builds without a corpus — which is the point.** `prebuild` chained a multi-GB LMDB index and a whole-pool compose onto every `next build`, so the project's own marketing site could not be built by someone who had merely unpacked the source. `build` and **`build:nodata`** now run the *identical* command; the only difference is that pnpm's lifecycle hook matches on the script **name**, so `prebuild` fires for one and not the other. Routes that want numbers **degrade honestly**: `loadSummary()` returns `null` rather than a zero-filled summary, `/` drops its numeric bands entirely, and `/stats/` still exists (so the nav never 404s) and explains why it is empty. *"0 transcripts · 0 sites"* would have read as a broken product rather than an unconfigured build. - **A visual identity of its own — the instrument face.** New `archilyzer` theme family: graphite and bone, `2px` radius, hairline geometry, Archivo at 125% width for display, IBM Plex Sans for documentation body and IBM Plex Mono for every number. The warm radial glow and film grain are **cut**. The argument it makes is that the tool should stop dressing as its own output: **chrome is achromatic**, and colour appears in exactly two places, both carrying information — a recording's state at its source (`--state-gone`, the one hot hue, worn only by recordings found gone) and the archives themselves, each card wearing its own accent. The tool has no colour; the recordings do. The family declares the **complete** token set in **both** modes, since the theme toggle ships and a half-declared palette silently inherits the base family's values in whichever mode nobody checked — a spec now asserts all fifty tokens resolve in light and dark. - **The rail: real acquisitions, never invented ones.** The home page's signature object is a log of genuinely recent recordings — date, channel, title, and state at source. It revives `RecentAdditions`, which had been built and left unrendered. The hard rule is that **nothing on this page may be fabricated**: absent data renders an empty state, and a recording whose state is unknown gets no chip at all rather than a cheerful default. Inventing transcript rows on the marketing site for an archiving tool would undercut the entire product. For the same reason every figure is computed at build time and none is hardcoded — the public-archive count went from three to four *during* this work. - **The proof point is stated carefully.** 471 recordings in the reference corpus no longer exist where they came from, and that is the argument for the software. But `available` is a **floor, not a fact**: a recording counts as available until something re-checks it and finds otherwise, and nothing re-checks 60,000 videos continuously. The copy says *"simply not known to be gone"* and never *"everything else is safe"*. - **Two pre-existing e2e bugs fixed.** The Playwright config read `process.env.PORT` — the **editor's** port variable — instead of `HOMEPAGE_E2E_PORT`, which `scripts/worktree.mjs` had been allocating for it all along and nothing read; and the `e2e` script never took the machine-global queue lock, so it could race a running export suite for ports. ## 2026-06-29 - **Charts rebuilt around presets + a power-user explorer.** The single five-control chart is replaced by named **preset chips** that each set a full, data-tuned view, with an inline **"Customize"** disclosure exposing the raw matrix (Metric / Breakdown / Chart type / Bucket / Range / Scale / Values + an exclude-outlier toggle). Selecting a preset sets the controls; touching any control reconciles the state (chart type is authoritative — Symlog is greyed on a stacked chart, Share on a non-stacked one) and lights the **Custom** chip. The presets are deliberately simple — **always per-site, always one combined line chart** — and lean on a recent window so the May megaspike (15.8k in a day, Jeralyzer's backfill) doesn't dominate. The three: - **Recent** (default) — one line per site over the last six weeks, weekly, linear. In that window the three sites are *comparable* (recent totals ~290/420/440 vs all-time 27.5k/710/500), so a plain combined line chart reads clearly with no site slammed and the spike excluded. - **Cumulative** — running totals over the same recent window. The running sum is **window-relative** (starts at 0 at the window edge), so it isn't dominated by a site's historical total the way an absolute cumulative is. - **All-time** — every week since launch on a **symlog** y-axis: the one tamed historical view, where symlog keeps the dominant site from slamming the small ones. - **Skew-handling tools for the one-dominant-site data.** The full toolbox stays in Customize: by-channel, ranked leaderboard, small multiples, the linear⇄symlog toggle, 100% **Share**, **Indexed** (every series rebased to 100 at its window start), and **Exclude ** (drops the leader and rescales). Clicking a line isolates it. (Fixed a recharts quirk where a conditionally-`undefined` y-axis `scale` collapsed linear line charts to two points — the scale is now always explicit.) - **"Instrument panel" chart styling.** The plot sits on an opaque, slightly-lifted surface (`.panel-instrument`) that occludes the page glow/grain for data contrast, with crisp themed gridlines/axes and a hairline brass top edge; the in-panel brass glow is gone. Brass identity stays in the preset chips, the active control state, and the series palette. - New shared, framework-free pipeline (`common/lib/homepageChartData.ts`) feeds every chart (`common/components/charts/{ChartPanel,MomentumChart,SmallMultiples, LeaderboardChart,CrossSiteChart}.tsx`); symlog uses d3 `scaleSymlog` (added `d3-scale` to `common`). New homepage Playwright suite (`e2e/landing.spec.ts`) covers every preset, the symlog small-site visibility, the guard rails, exclude-outlier, indexed, and mobile. No summary-schema change — everything derives client-side. - **Header simplified.** The shrink-on-scroll homepage masthead is removed: the header is now one compact brass-mark + wordmark bar, the same size on every page. The client `SiteHeader` and the homepage headroom spacer are gone; `Header` is a plain server component again. ## 2026-06-28 - **The home page is now the cross-site landing.** The thin branding hero and the separate `/stats` dashboard are replaced by a single, mobile-first landing built from a small summary pre-computed at build (`compose-homepage` writes `public/homepage-summary.json`, embedded into the static HTML — no multi-MB client fetch). It leads with headline KPIs (transcripts, downloads, sites, channels, hours archived), then one activity chart driven by five small segmented controls: **Metric** (Transcribed / Downloaded), **Breakdown** (By site / By channel), **Bucket** (Day / Week / Month / Cumulative), **Range** (2w / 90d / 12mo / All), and **Display** (Counts / Share). Day/Week/Month are stacked bars, Cumulative a stacked area, so per-series composition *and* the combined total read at once. The default is **Day · 2-week · Counts** — a short recent window where the per-site magnitudes are comparable, so real counts read clearly (the data is bursty, which bars represent honestly); **Share** (100% stacked) stays as the fallback for the long ranges where the historical backlog skews one site huge. By-channel groups to the top-8 channels + an "Other" band. A responsive **site grid** links every *public* content site (cards follow the active metric — total, "+N this month", inline-SVG sparkline — sorted by this-month, with a **"#1 this month"** badge); in By-site the cards double as the chart legend with Show/Hide toggles. The data universe is public sites only (URL-less sites hidden), each video attributed to one primary site so combined totals stay honest. (A recent-additions feed is still built into the summary but not rendered — kept for easy re-enable.) The `/stats` route and the trailing "Stats" header link are gone. - **Distinctive, minimal "archive" visual identity.** The landing commits to a warm-ink dark theme (class-based `dark`, not OS-driven) with an atmospheric background (overhead brass glow + film grain), the **Adobe Source superfamily** — Source Serif 4 for the wordmark + headline numerals, Source Sans 3 for body, Source Code Pro for the tracked uppercase micro-labels — a single brass/gold signature accent (active controls, the "#1 this month" badge), glass panels with hairline borders, enriched card sparklines (area fill + endpoint dot), and one orchestrated staggered page-load reveal. Deliberately sparse "less is more" chrome: the masthead is just the wordmark (no eyebrow/subtitle) and the chart and site-grid zones carry no section labels — separation is by space alone. Chart entry animation is disabled so bars/areas paint immediately. - **Wordmark masthead = the header.** The big "Archilyzer" wordmark and the small sticky header logo are one element (`app/components/SiteHeader.tsx`): large as a masthead at the top of the home page, it shrinks to the compact sticky bar the moment you scroll. Other routes always show the compact bar. The shrink no longer reflows the page: the header's layout box stays pinned to the compact height and the enlarged wordmark overflows it (only its font-size and the bar chrome animate), so `
` and the document height never change on scroll. `page.tsx` reserves a fixed headroom spacer so the landing clears the overflowing masthead. - **Hub Markdown pages dropped.** The `[slug]` doc routes, the `index`-page home body, the `PageBody` renderer, and the doc nav are removed — the hub is now a single page (re-addable later if needed). See `app/page.tsx`, the new hub components under `app/components/`, `common/lib/{homepageSummary,homepageChart}.ts`, and `common/components/charts/CrossSiteChart.tsx`. ## 2026-06-22 - New `homepage` package: the Archilyzer hub — a standalone Next.js static (`output: "export"`) marketing/docs site, separate from the per-content export sites. - Markdown info/docs pages, authored in the editor and rendered with markdown-to-jsx at build (`app/[slug]`, home renders the `index` page). - Cross-site stats dashboard (`/stats`) charting downloads/transcriptions across every content site in the instance, with a per-site breakdown (`groupBy: "site"`) plus combined totals.