atproto.<cc> — community websites #
One codebase, several country websites for the AT Protocol community in Europe. Each country is
its own standalone site built from this same repo, selected at build time with SITE_SCOPE:
SITE_SCOPE |
Site | Accent | Languages |
|---|---|---|---|
nl (default) |
atproto.nl | orange | English, Dutch |
be |
atproto.be | yellow | English, Dutch, French |
no |
atproto.no | purple | English (Norwegian pending) |
eu |
atproto.eu | blue | English (the aggregate/directory) |
There are no redirects between the sites and each is complete on its own. .eu is the
aggregate: all-Europe stats plus a directory of country and city communities.
Run your country's site locally #
Prereqs: Node ≥ 22.12 and npm.
git clone tangled.org:did:plc:aqrkn66k2alnwxfrhstp3unq/website atproto-website
cd atproto-website
npm install
SITE_SCOPE=be npm run dev # runs the Belgian site at http://localhost:4321
# SITE_SCOPE=no npm run dev # the Norwegian site
# npm run dev # no SITE_SCOPE = the Dutch site (the default)
Build a single country's static site into dist/:
SITE_SCOPE=no npm run build
How a country is configured #
Everything specific to a country lives in src/config/scopes.ts — one entry per site:
be: {
site: 'https://atproto.be',
countries: ['be'], // whose members/events/tools/builders this site shows
locales: ['en', 'nl', 'fr'],// first is the default; only add a locale once its strings exist
cc: 'be', // wordmark //atproto.be, favicon, map highlight
accent: 'yellow', // one of the Gruvbox packs in src/styles/country-packs.css
cities: { Brussel: [4.35, 50.85], /* ... */ }, // dots on the map (lon, lat)
maintainer: null, // a handle, or null -> the "caretaker, get in touch" note
endonyms: { en: 'English', fr: 'Français', nl: 'Nederlands' }, // header language switcher
relatedLangs: ['nl', 'fr'], // /builders affinity section
},
To stand up or customize a country you typically touch:
src/config/scopes.ts— the entry above.- Copy —
src/i18n/ui.ts. Shared strings use{siteName}/{inCountry}tokens and work everywhere. Genuinely per-country strings (the hero welcome, the about intro) go in theuiByScopeoverride map. A language must have complete strings before it goes inlocales— shipping a locale with missing strings puts English text on that language's URLs. - Assets —
public/brand/favicon-<cc>.svgandavatar-<cc>.svg, plus an accent pack insrc/styles/country-packs.css(Gruvbox hues only, one per country).
Rules that matter #
- Language is not nationality. The "(Belgian or otherwise)" welcome means nationals and the many foreigners who build here — never a language. Don't write "Flemish"/"Walloon"; the languages are Dutch and French.
- One accent per view. A pack re-points the accent role and nothing else.
- Every page carries the disclaimer: "atproto.<cc> is an independent community project. It is not affiliated with, sponsored or endorsed by Bluesky Social PBC."
- Spelling: "the AT Protocol", "atproto". Never "AtProto"/"at-proto". No Bluesky/AT Protocol logos.
Tests #
npm test # unit tests (vitest)
npm run test:a11y # build + Playwright accessibility checks
Contributing & home base #
Home base is Tangled at tangled.org/atcommons.eu/website — open to pull requests. Push there
(a Codeberg mirror handles delivery; maintainers rarely deploy themselves). See AGENTS.md for the
coding conventions.