Website of the Open Source Firmware Conference, built with Astro and deployed as a static site on Netlify.
npm install
npm run dev
Requires Node.js 22.22 or newer.
| Command | Action |
|---|---|
npm run dev |
Dev server at localhost:4321 |
npm run build |
Production build to ./dist/ |
npm run preview |
Preview the production build |
npm run pretalx:sync |
Refresh the Pretalx snapshots of all years |
npm run pretalx:sync -- 2026 |
Refresh one (or more) years |
npm run compare:urls -- <old dist> [new] |
Compare the pages of two builds, respecting _redirects |
public/ Static files served as-is (beams, icons, video, _redirects, robots.txt)
scripts/ Node scripts (Pretalx sync, URL comparison)
src/
├── assets/ Images and SVGs processed by Astro
├── components/ One folder per component, CSS next to it
├── content/ Markdown content collections (pages, projects, organizers, sponsors, team)
├── data/
│ ├── pretalx/ Committed Pretalx snapshots, one JSON file per year
│ └── site.ts Site name, navigation, newsletter URL
├── layouts/ BaseLayout (head, SEO, header, footer) and PlainLayout (text pages)
├── pages/ Routes
├── styles/ Global CSS: reset, layout, utilities, blocks, page CSS
└── utils/ Pretalx fetching, slugs, Markdown, SEO helpers
tokens/ Design tokens that generate CSS variables and utility classes
Setting up a new conference year or archiving the last one? Follow the step-by-step guide in docs/new-conference-year.md.
Talks, speakers, schedules and video links come from Pretalx.
- Every year is saved as
src/data/pretalx/{year}.jsonand committed, so builds don't depend on Pretalx being reachable. src/utils/pretalx/years.jsdefines each year's Pretalx event, quirks and optional venue. Add a new year there first, then runnpm run pretalx:sync -- <year>.- Set
live: trueon a year to fetch it during every build instead of reading the snapshot. A failed fetch fails the build. - Pages read the data through the
conferenceYearscontent collection.
The sync needs API tokens. Copy .env.example to .env and fill in:
PRETALX_TOKEN= # pretalx.com (2018–2025)
TALKS_OSFC_TOKEN= # talks.osfc.io (2026 and later)
Authenticated Pretalx responses contain private data (emails, reviews, internal notes). src/utils/pretalx/sanitize.js keeps an allowlist of public fields, so only those end up in the snapshots and pages.
Talk and speaker URLs are built with src/utils/slugify.js, which matches the slugs of the previous 11ty site.
Speaker avatars stay on Pretalx and are optimized at build time with astro:assets (allowed domains in astro.config.mjs).
Markdown collections live in src/content/ and are defined in src/content.config.ts:
| Collection | Used on | Notes |
|---|---|---|
pages |
/imprint/, /info/, … |
One route per file via src/pages/[page].astro |
projects |
Homepage | Order in src/data/order.ts, others A–Z |
organizers |
Homepage | Sorted A–Z by name |
sponsors |
Homepage, /sponsors/<name>/ |
Sorted A–Z by name; sponsor is the tier (gold, silver, bronze) |
team |
/team/ |
Order in src/data/order.ts, others A–Z |
Logos and photos are referenced relative to the Markdown file and optimized by Astro.
-
Design tokens in
tokens/generatesrc/styles/generated/_variables.cssand_utilities.csson every dev start and build. SeeCLAUDE.mdfor the naming. -
CSS is organized in cascade layers:
fonts, reset, layout, utils, blocks. Component CSS is imported into theblockslayer, for example:<style is:global> @import "./SiteHead.css" layer(blocks); </style> -
src/styles/_root.cssis unlayered on purpose and wins over utilities, like on the previous site. -
Roboto is self-hosted as a variable font through Fontsource (
@fontsource-variable/roboto). The latin file is preloaded; other subsets only load when a page needs those characters.
BaseLayoutrenders meta tags with astro-seo and JSON-LD with astro-seo-schema.- Pages pass
title,metaTitle,description,socialImage,ogTypeandjsonLd(schema.org nodes, combined with the siteOrganizationinto one@graph). - Year pages describe the conference as an
Event, talk pages as a sub-event with performers, speaker pages as aPerson. @astrojs/sitemapgenerates the sitemap,public/robots.txtpoints to it.
public/_redirects (Netlify) keeps URLs of the previous site working, for example renamed or canceled talks and former sponsors. Run npm run compare:urls against an old build to check that every old page still exists or redirects.
Netlify builds the site with the settings in netlify.toml: npm run build, publish dist, Node 22. It also sets long-lived caching for the hashed files in /_astro/ and a few security headers.
Set PRETALX_TOKEN and TALKS_OSFC_TOKEN in the Netlify environment variables once a year in src/utils/pretalx/years.js has live: true. Snapshot-only builds don't need them.