How It Works
An architecture tour for developers who read the homepage and asked, prove it. Here's what's actually under the hood — the zero-JS philosophy, the AI development system, the design pipeline, and the toolchain that ships.
The page you're reading is itself a demonstration: zero hydrated JavaScript, scroll-driven animations powered by CSS, and a section-tracking sidebar that uses one Intersection Observer.
Pillar 1 — Performance-First Architecture
Zero-JS by default
Every component in this template compiles to static HTML and CSS.
JavaScript ships only when a feature genuinely needs it — and
even then, it's an Astro Island, lazy-hydrated only when in
view. ADR-001 codifies the rule: no client:load without explicit justification.
What the web platform gives us for free
The browser has caught up to the framework era. Most of what React, Vue, or Angular libraries used to do in user-space JavaScript is now a CSS rule, a media query, or a one-line HTML attribute. Pick a tab to see the swap.
Replaces: AOS · ScrollMagic · GSAP ScrollTrigger
// Typical IntersectionObserver setupimport { useEffect, useRef } from "react";
export function FadeIn({ children }) { const ref = useRef(null); useEffect(() => { const io = new IntersectionObserver(([entry]) => { if (entry.isIntersecting) ref.current.classList.add("visible"); }, { threshold: 0.3 }); io.observe(ref.current); return () => io.disconnect(); }, []); return <div ref={ref} className="fade-in">{children}</div>;}/* Native scroll-driven animation — zero JS */.fade-in { animation: fade-up linear both; animation-timeline: view(); animation-range: entry 0% entry 30%;}
@keyframes fade-up { from { opacity: 0; transform: translateY(2rem); } to { opacity: 1; transform: translateY(0); }}Replaces: Radix Dialog · HeadlessUI · React Modal
// React modal with focus trapimport * as Dialog from "@radix-ui/react-dialog";
export function ConfirmModal() { const [open, setOpen] = useState(false); return ( <Dialog.Root open={open} onOpenChange={setOpen}> <Dialog.Portal> <Dialog.Overlay className="overlay" /> <Dialog.Content className="content"> {/* focus trap, backdrop, escape handling, body scroll lock */} </Dialog.Content> </Dialog.Portal> </Dialog.Root> );}<!-- Native <dialog> — focus trap, backdrop, escape: free --><dialog id="confirm"> <h2>Confirm action</h2> <button onclick="confirm.close()">Close</button></dialog>
<button onclick="confirm.showModal()">Open</button>Replaces: tippy.js · Floating UI · Popper.js
// Floating UI tooltip with positioningimport { useFloating, autoUpdate, offset, flip } from "@floating-ui/react";
export function Tooltip({ children, text }) { const [open, setOpen] = useState(false); const { refs, floatingStyles } = useFloating({ open, onOpenChange: setOpen, middleware: [offset(8), flip()], whileElementsMounted: autoUpdate, }); // ... handlers, render, escape, dismiss}<!-- Popover API: hint type = auto-dismiss, escape, no JS --><button popovertarget="hint" popovertargetaction="show"> Hover me</button><div id="hint" popover="hint"> Helpful information</div>Replaces: GSAP · CountUp.js · react-countup
// GSAP number counterimport { gsap } from "gsap";
export function Counter({ value }) { const ref = useRef(null); useEffect(() => { const obj = { n: 0 }; gsap.to(obj, { n: value, duration: 1.5, ease: "power2.out", onUpdate: () => { ref.current.textContent = Math.round(obj.n); }, }); }, [value]); return <span ref={ref}>0</span>;}/* CSS @property + counter() — pure CSS interpolation */@property --num { syntax: "<integer>"; initial-value: 0; inherits: false;}
.counter { counter-reset: num var(--num); animation: count 1.5s forwards;}.counter::before { content: counter(num); }@keyframes count { to { --num: 95; } }Preact islands for genuine state
Some interactions actually need client-side reactive state —
optimistic UI, complex form validation, signal-driven counters.
For those, Astro Islands give us a Preact component that
hydrates only when it scrolls into view via client:visible.
Everything else stays static.
---import SignalsCounter from "@/components/islands/SignalsCounter.tsx";---<!-- Lazy-hydrated. Zero JS until visible. --><SignalsCounter client:visible />Pillar 2 — Agentic Discipline
Point your agent at the docs and ship
The headline differentiator. Most templates assume a human reads the README and figures out the conventions. This one assumes an AI coding agent will be sitting at the keyboard, and front-loads the context, constraints, and decision history that agent needs to make good calls without supervision.
What an agent sees on day one
When Claude Code (or any AI assistant) opens this repo, the
very first thing it loads is CLAUDE.md at the project root —
rules of engagement, scope boundaries, and a pointer to every
ADR that constrains architectural decisions.
# Astro Performance Starter — Claude Code Context
## Rules of Engagement
1. Check `docs/adr/` before suggesting architectural changes.2. No `client:load` without ADR justification (ADR-001).3. Use design tokens from `tokens/` — never hardcode colors.4. TypeScript strict mode is non-negotiable.5. Use Biome, not ESLint/Prettier.6. Use pnpm, not npm or yarn.7. Prefer CSS solutions over JavaScript.8. Use Astro Image for all images — no raw <img> tags.9. Verify with `pnpm run quality` before claiming done.The AI-context system
CLAUDE.md
Project-root entry point. Conventions, scope boundaries, and rules of engagement an agent must follow.
35+ ADRs in docs/adr/
Every accepted ADR is a constraint. The agent reads them before proposing architectural changes — no rediscovery of past decisions.
docs/ai-context/
Prompt libraries, context-update procedures, and guides for keeping the AI surface area in sync with the code.
Progressive implementation tiers
ADR-033 splits the work into three tiers — natural stopping points the agent can ship to. Each tier is "done enough" to deploy, then the next tier unlocks more capability.
Foundation
Working site skeleton with design system, content schemas, and build pipeline. Done = deployable site, no content yet.
Build
Components, pages, content, and quality assurance. Done = complete, tested site running locally and in CI.
Polish
Performance optimization, monitoring, deeper docs. Done = enterprise-grade deployment.
Pillar 3 — Enterprise-Grade Design System
Tokens flow from JSON to your components
One source of truth in tokens/,
automatically built into CSS custom properties and exposed
as Tailwind utilities. Change one token; the cascade
propagates everywhere — light mode, dark mode, every component.
Step 1
Token JSON
tokens/semantic.json
Step 2
CSS Variables
tokens/dist/tokens.css
Step 3
Tailwind Utilities
@theme inline
Step 4
Components
bg-primary-600
1. Token definition
{ "semantic": { "primary": { "600": { "value": "{color.moonstone.600}" } }, "background": { "primary": { "value": "{color.white.500}", "dark": "{color.spaceCadet.500}" } } }}2. Generated CSS variables
:root { --color-primary-600: 189 61% 32%; --color-background-primary: 0 0% 100%;}
.dark { --color-background-primary: 227 50% 16%;}3. Tailwind utility binding
@theme inline { --color-primary-600: hsl(var(--color-primary-600)); --color-background-primary: hsl(var(--color-background-primary));}4. Used in a component
<button class="bg-primary-600 text-white"> Save changes</button>
<!-- Dark mode just works. No dark: variants needed. -->Contrast validation in CI
Every semantic foreground/background pair is checked against WCAG-AA at build time. The build fails if any pair drops below 4.5:1.
pnpm design:validate# ✅ All semantic foreground/background pairs meet WCAG-AA contrast.Pillar 4 — Next-Gen Toolchain
One command verifies everything
The toolchain is opinionated and modern. Biome instead of
ESLint + Prettier. TypeScript strict by default. Performance
budgets enforced in CI. Tests at four layers — and a single
pnpm quality runs all of it.
Biome
Replaces ESLint + Prettier with one Rust-powered binary. Linting and formatting in a single config, single pass.
TypeScript
Astro's strict preset plus
strictNullChecks. Errors
surface during astro check,
not in production.
Performance budgets
160 KB JS, 50 KB CSS, 200 KB per image. The build fails if any budget is exceeded. Overrides expire automatically.
Test pyramid
Vitest for units, Playwright for e2e across Chromium / Firefox / WebKit, axe-core for a11y, Lighthouse for performance regressions.
Git hooks
Husky + lint-staged runs Biome on staged files; commitlint enforces conventional commits. No bad code reaches the remote.
pnpm engine-strict
Package manager and Node version are pinned in
package.json. New
contributors get the same toolchain on the first install.
The single quality gate
Format → lint → markdown lint → type check. One command, fast feedback, identical in CI and on your laptop.
pnpm quality# ✓ format biome format . --write# ✓ lint biome check .# ✓ lint:md markdownlint-cli2 **/*.md **/*.mdx# ✓ check astro check (TypeScript)Pillar 5 — Robust Page Templates
Real pages, not empty shells
Most starter templates ship a hero page and call it a day. This one ships a full set of reference implementations — each one a working example of how the components, content collections, and conventions fit together.
Home
Marketing pillar grid, Lighthouse metric showcase, tech stack with version display, expandable feature cards.
Components
Live demo of every component in src/components/,
with code snippets, a11y notes, and composition examples.
Blog
Content Collections + MDX with Zod schemas. Reading time, tags, scroll-driven progress bar, prefetched links.
Projects
Portfolio / case-study layout with filtering by technology, pagination, and structured outcome metadata.
About
Bio, skills, experience timeline, social links — pulled from content collections so non-engineers can edit it.
Contact
Progressive-enhancement form with native HTML validation first, JS enhancement second (ADR-021).
Want to see the components themselves? The Components page has every atom, molecule, and structural component with a live demo and code.
Browse the Components → Clone the repo →