Skip to content

Latest commit

 

History

History
93 lines (75 loc) · 5.53 KB

README.md

File metadata and controls

93 lines (75 loc) · 5.53 KB

polyweave site

The public site — a self-contained Vite + React 19 + TypeScript + Tailwind v4 workspace, and this repository's only code. It never writes into docs/, which is roadkeep's, and it reads from there rather than copying it.

Commands

npm install        # once
npm run dev        # dev server at /polyweave/
npm run build      # generate → tsc → client → SSR → og image + prerender
npm test           # the site's own claims, against what the build produced
npm run typecheck  # tsc -b, no emit
npm run preview    # serve the built dist/

npm run build is the gate, and it is one command on purpose: it regenerates the roadmap module from docs/ROADMAP.md, type-checks, builds the client, rasterises the social card, builds the SSR bundle and prerenders every route with its Markdown twin, its manifest.json, its sitemap.xml and its robots.txt. A drifted <head> template, a route with no page, or a feature record naming a block the roadmap has lost all fail it. npm test then asserts the built output, so it runs after the build rather than instead of it.

The chrome is the design system's site layer, @viglet/viglet-design-system pinned in package.json: the nav, the hero, the section heads, the buttons, the copy button, the sponsor block, the footer and the theme toggle come from ./site, the ground from ./tokens.css on data-tone="cool", their styles from ./site.css, and the prerender and the social card's rasteriser from ./vite. What src/index.css keeps is the product's own: the brand re-keyed to the hub's teal, the mark's violets for the lattice, and the sections.

GitHub Pages derives the base path from the repository name, so Vite's base is /polyweave/ and every asset path carries that prefix. It is written twice — in vite.config.ts and in src/routes.tsx — and nowhere else.

The two rules this site is held to

It sells polyweave as the roadmap leaves it, and never claims a result no run has measured.

The landing page is a pitch for the finished product — every block built — written for a person who has never heard of polyweave and has a few seconds to see what it is for. So:

  • It states no status. A count typed or derived into the pitch either goes stale or turns the page into a status report; what is still open lives in docs/ROADMAP.md, which the footer links. scripts/prerender.test.mjs refuses an open-line count on the landing and requires the install commands and every roadmap non-goal to reach it.
  • It is pictures first: tiles, a hub diagram, a review-page mock, one sentence each. Claude Code is the operator and the page is about what it gains, so there is no separate "Claude Code" item in the nav.
  • scripts/lint.test.mjs refuses copy that claims a measured result for polyweave ("faster than", "we measured", "benchmarked"). Describing what a feature does is the pitch; quoting a number nobody recorded is not.

Where things live

Path What
src/lib/site-content.ts All copy — sections only render it, so a claim is one array element a reviewer can check
src/lib/roadmap.generated.ts Generated from docs/ROADMAP.md through roadkeep: the blocks, the lines and the non-goals. Committed, because roadkeep is not
src/lib/roadmap.ts The typed read over it: block titles for the depth pages, and the non-goals
src/lib/features.ts One record per roadmap block — route, <head> and page, declared together
src/lib/diagrams.ts The depth pages' SVGs and the session transcript, kept verbatim as figures
src/components/ui/Icon.tsx The line icons the landing tiles use, drawn in the current text colour
src/components/Chrome.tsx The nav and the footer every route shares, drawn by the design system's site layer
src/components/Consent.tsx The analytics banner: Google Analytics loads only after the visitor allows it
vite.config.ts pre-paint script + THEME_KEY The theme follows the OS, a stored choice overrides it, applied before first paint
src/routes.tsx The route table and its metadata, asserted against each other at import time
src/components/sections/ One component per landing section; the composition lives here
src/pages/Landing.tsx The landing page — the section order is the pitch
scripts/ The generator, the prerender, the social card and the tests that read dist/

The generated module, and why it is committed

.roadkeep is in this repository's .gitignore, so a clean checkout has the roadmap but not the tool that reads it. npm run generate refreshes src/lib/roadmap.generated.ts where roadkeep is reachable and leaves the committed file alone where it is not, so the build works either way.

scripts/roadmap.test.mjs is what keeps that honest: with roadkeep present it regenerates into memory and asserts the committed file is byte-identical, so a line added, shipped, renumbered or reworded without a regenerate fails. Without roadkeep it checks the committed module against itself — unique ids, every dependency resolving, every block declared.

Set $ROADKEEP to a command if yours is not at .roadkeep/scripts/roadkeep.py or on PATH.

Deliberate non-goals here

No third-party fonts fetched at page load (the product claims nothing leaves your machine; the site adds no fetch of its own), and no analytics unless the visitor allows it: the tag is not in the HTML, and the banner the hub runs is what loads it. Inter and JetBrains Mono are named with system fallbacks rather than pulled from a CDN.