The build guide · /guide

Build one yourself.

Everything a technically capable person would need to reproduce a site like DAIODA — the stack, the architecture, the content model, the research and verification workflow, the deployment, and the running costs. No private credentials, keys, or tokens appear anywhere in here; those live in environment variables and never in the repository.

Technology stack

The guiding principle is ship as little JavaScript as possible: a content site should be fast, static, and legible to search engines by default, with interactivity added only where it earns its weight.

FrameworkAstro 5 — static output, content collections, view transitions, zero-JS by default
LanguageTypeScript for logic; Astro components for templating; vanilla TS islands for interactivity
StylingHand-written CSS with custom properties (design tokens); no CSS framework
ContentJSON records per project, validated at build with Zod via Astro's content collections
FontsFraunces (display), Instrument Sans (text), IBM Plex Mono (data) — all SIL OFL, self-hosted via Fontsource
GraphicsA hand-written WebGL fragment shader for the daybreak hero; no 3D library
SearchClient-side filtering over data attributes — no search service, no index to host
Feeds@astrojs/rss and @astrojs/sitemap generate the RSS feed and sitemap at build time
HostingNetlify static hosting with CDN, redirects, and headers via netlify.toml
AnalyticsGoatCounter — privacy-first, cookieless, no personal data

Architecture

DAIODA is a fully static site. At build time, Astro reads the project JSON records, validates each against the schema, and renders one HTML page per project plus the category, collection, discovery, and content pages. There is no server, no database, and no runtime API — the entire site is HTML, CSS, and a few small scripts served from a CDN.

Interactivity is confined to three small, dependency-free islands: the theme toggle, the discovery-page search and filters (which operate on data attributes already in the HTML, so the page works with JS disabled), and the WebGL hero (which degrades to a static gradient). Nothing blocks first paint.

Repository structure

daioda/
├─ src/
│  ├─ data/
│  │  ├─ projects/        # one JSON record per project (the catalog)
│  │  └─ taxonomy.json    # categories + collections
│  ├─ components/         # Header, Footer, ProjectCard, DaybreakHero, Wordmark
│  ├─ layouts/            # Base.astro (head, meta, theme, skip link)
│  ├─ lib/                # taxonomy helpers, verdict labels
│  ├─ pages/
│  │  ├─ index.astro
│  │  ├─ projects/index.astro      # discovery
│  │  ├─ projects/[id].astro       # detail (the Tally)
│  │  ├─ categories/[id].astro
│  │  ├─ collections/[id].astro
│  │  ├─ fine-print.astro
│  │  ├─ about / guide / methodology / credits
│  │  ├─ rss.xml.ts
│  │  └─ 404.astro
│  ├─ styles/global.css   # design tokens + primitives
│  └─ content.config.ts   # Zod schema for the projects collection
├─ public/                # favicon, og image, robots.txt
├─ astro.config.mjs
└─ netlify.toml           # headers, redirects, build config

Content model

Each project is a single JSON file, validated at build against a Zod schema so a malformed or incomplete record fails the build rather than shipping broken. The schema captures the editorial fields (tagline, description, why, use cases, takeaway), the setup profile, the related projects, and — the heart of it — the license and tally objects:

license: {
  code:    "MIT",            // the code license, read from the repo
  weights: null,             // model weights license, if different
  verdict: "open",           // open | partial | not-open | unclear
  notes:   "..."             // any caveats worth surfacing
},
tally: {
  stars:        "175k",
  lastActivity: "v0.31.1 June 2026",
  status:       "maintained",
  checked:      "2026-07-19" // when this tally was last verified
}

Categories and collections live in taxonomy.json, each with a name, a blurb, and (for categories) a hue that colors that category consistently everywhere it appears.

Research & open-source verification workflow

This is the editorial engine, and it's deliberately rigorous. For each candidate:

  1. Discover from primary sources — repositories, official docs and sites, papers, maintainer announcements — plus community signal.
  2. Verify the license from the source by reading the actual LICENSE file, never a third-party label. Record the code license and, separately, the weights license for models.
  3. Assign a verdict: open, open-code/restricted-weights (partial), or not-open — with added-condition licenses (fair-code, Apache-with-conditions, branding locks) flagged explicitly.
  4. Tally activity: stars, last meaningful update, and a status judgment (maintained / stable / experimental / static).
  5. Write original editorial context — description, why it matters, use cases, cautions, and a takeaway — in the site's own voice, never copied from the README.
  6. Review before publishing. No unverified claim ships as fact; when a license is unclear, the project is downgraded rather than given the benefit of the doubt.

The full public version of these rules lives on the methodology page.

Visual, animation & asset workflow

The visual identity is a "night shift at daybreak" harbor: deep-indigo night warming to a dawn-gold horizon. All imagery is generated in code, so there are no third-party image assets to license or attribute. The hero is a single full-screen WebGL quad running a hand-written GLSL fragment shader that renders a slow generative dawn — value-noise aurora bands, a breathing horizon glow, and drifting "cargo lights" standing in for projects. It pauses when scrolled offscreen and is replaced by a static CSS gradient when a GPU context is unavailable or when the visitor prefers reduced motion.

The rest of the motion is CSS: scroll-reveal via IntersectionObserver, stepped count-ups on the home statistics (a nod to the tally song's counted bunches), and hover microinteractions. Every animation is gated behind prefers-reduced-motion. The favicon and OG image are hand-authored SVG. No living artist's style, copyrighted campaign, or proprietary layout is imitated; the one cultural reference — a dockworkers' tally song — is honored structurally through rhythm and daybreak language, never by reproducing lyrics, recordings, or protected artwork.

Deployment & Netlify configuration

Deployment is a static build connected to Netlify from the GitHub repository:

  1. Push the repository to GitHub (here, the OLDCARTS organization).
  2. Connect the repo to Netlify. Build command npm run build, publish directory dist.
  3. Configure headers, redirects, and caching in netlify.toml (security headers, long-cache for hashed assets, apex-to-www canonicalization).
  4. Connect the daioda.io domain, set the primary domain (www or apex) so the other redirects to it, and let Netlify provision the automatic HTTPS certificate.
  5. Confirm HTTPS, that the non-primary host 301-redirects to the canonical one, that canonical URLs and the sitemap resolve, and that the 404 renders.

No secrets live in the repo. Any keys (for example the analytics endpoint) are set as Netlify environment variables and referenced at build time.

Update & automation process

Content updates on a weekly Daybreak cadence. Adding a project is adding one JSON file and opening a pull request; the schema validates it, a preview deploy renders it, and merging publishes it — the RSS feed and sitemap regenerate automatically. Automation assists with discovery and with re-checking activity metrics, but the license verdict and the editorial writing stay under review. The firm rule: no automatically generated claim is published without source verification. Abandoned projects are re-tallied and flagged, or moved out of the featured catalog.

Analytics configuration

DAIODA uses GoatCounter, a privacy-first analytics service: no cookies, no cross-site tracking, no personal data, and a lightweight script. It's added once in the base layout (commented out until the production site key is set) and answers the only questions that matter here — how many people visit, which projects and categories draw attention, and which repository links get clicked. There is no advertising technology anywhere on the site, and nothing that would require a cookie banner. Netlify's server-side analytics is a drop-in alternative if you prefer no client script at all.

Accessibility & performance

Accessibility is built in, not bolted on: semantic landmarks, a skip link, visible focus rings, keyboard-operable search and filters, ARIA labels on icon controls, honored reduced-motion preferences, and color contrast checked against WCAG AA in both themes. The dark theme is primary; a daylight theme is one toggle away and persists via localStorage.

Performance follows from the architecture. The site is static HTML from a CDN; the JavaScript is a few small dependency-free islands; fonts are self-hosted and subset; the WebGL hero runs at a capped device-pixel-ratio, pauses offscreen, and never blocks paint; images are hand-authored SVG. The result targets strong Core Web Vitals — fast first paint, negligible layout shift, and quick interactivity — even on low-power devices and slow connections.

Local development

# prerequisites: Node 22+

npm install         # install dependencies
npm run dev         # local dev server with hot reload
npm run build       # produce the static site in dist/
npm run preview     # serve the built site locally

# add a project:
#   1. create src/data/projects/<slug>.json
#   2. fill every schema field (license + tally included)
#   3. npm run dev and confirm the card + detail page render
#   4. open a pull request

Publishing an update is merging a pull request; Netlify builds and deploys automatically, and the feed and sitemap update themselves.

Estimated costs & known limitations

Running costs are low by design, because a static site needs almost no infrastructure:

Domain~$15–40 / year, depending on the TLD registrar
Hosting$0 on Netlify's free tier for a site this size; a paid tier only becomes relevant at high traffic
Analytics$0 self-hosted GoatCounter, or a few dollars a month hosted
Fonts & assets$0 — all self-hosted, openly licensed, or code-generated
Research/curationThe real recurring cost is time (and, for automated discovery, some model/API usage) — not infrastructure

Known limitations: tally figures are point-in-time snapshots and drift; client-side search suits a curated catalog but wouldn't scale to tens of thousands of entries without a real index; and the WebGL hero, while it degrades gracefully, is the one place the site asks anything of the GPU. None of these are load-bearing, and each has a documented fallback.