bitcircus101 is a tech and creative space located in Bonn, Germany.
This repository contains the website for bitcircus101.
| Branch | Purpose |
|---|---|
feat/… |
Feature branches — all changes land here first, then merge to main via PR; delete after merge |
main |
Integration branch (no direct pushes for normal work; see CONTRIBUTING.md) |
live |
Production branch — served by GitHub Pages. CI actions commit generated files here |
index.html Main landing page
events.html Events page (loads events-data.json)
donations.html Donation / funding page (loads funding.json)
raum-nutzen.html Room usage info
impressum-datenschutz.html Legal / privacy
dankedankedanke.html Thank you page
ascii/index.html Internal ASCII playground (/ascii/) — noindex, not in nav; strict system monospace
includes/
site-header.html Shared <header> (nav); inlined into pages by build:layout
site-footer.html Shared <footer>; inlined into pages by build:layout
scripts/inject-layout.mjs Writes header/footer into the six layout HTML files
style.css Global styles (terminal theme, dark bg, green accent)
events.js Frontend: fetches events-data.json, renders event cards, tag filtering
calendars.json Calendar source definitions (ICS URLs, names, flags)
funding.json Current funding percentage (generated by CI)
scripts/
sync-events.mjs Fetches ICS from Nextcloud, generates events-data.json + feed.xml
tests/
site.spec.js Playwright end-to-end tests (~20 tests × 2 browsers)
sync-events.spec.mjs Unit tests for ICS parser and RRULE expansion (22 tests)
playwright.config.js Playwright config (Chromium, Mobile Chrome)
.github/workflows/
ci.yml PR checks: layout sync + unit tests (no Playwright)
deploy.yml Test on main → deploy to live
sync-events.yml Calendar sync (every 15 min)
update-funding.yml Funding level update (manual)
sitemap.yml Sitemap generation (on push to live)
These files are created by CI actions and committed to the live branch only:
| File | Generated by | Schedule |
|---|---|---|
events-data.json |
sync-events.yml |
Every 30 minutes |
feed.xml |
sync-events.yml |
Every 30 minutes |
sitemap.xml |
sitemap.yml |
On push to live |
funding.json |
update-funding.yml |
Manual trigger |
main (push) → Unit tests → Sync script → Playwright E2E → Deploy to live
Every push to main triggers:
- Layout sync check:
scripts/inject-layout.mjsmust not change any committed*.html - Unit tests: ICS parser, RRULE expansion, date parsing (node:test)
- Sync script: Generates
events-data.jsonfor E2E tests to use - E2E tests: Playwright across 2 browsers (~20 tests × Chromium + Mobile Chrome)
- Deploy (only if all tests pass): Syncs site files from
maintolive
PRs get lightweight CI via ci.yml: same layout check + unit tests (no Playwright). See CONTRIBUTING.md.
Nothing reaches production without passing all tests first.
- Trigger: Cron every 30 minutes + manual
- Branch: Checks out
live, pulls scripts/config frommain - What it does:
- Runs
scripts/sync-events.mjs(Node 22, zero dependencies) - Fetches ICS feeds from all calendars defined in
calendars.json - Parses VEVENT entries, expands RRULE recurrences (weekly, monthly with BYDAY/BYSETPOS)
- Filters out internal/blocker events and past events
- Generates
events-data.jsonwithlastSynctimestamp (max 40 cards, 120-day horizon) - Generates
feed.xml(RSS 2.0, primary calendar only, max 15 items) - Commits and pushes to
livewith retry logic
- Runs
- Trigger: Manual (
workflow_dispatch) withpercentinput (0-100) - Branch:
live - What it does: Writes
funding.jsonwith the given percentage, commits tolive
- Trigger: On push to
live+ manual - Branch:
live - What it does:
- Uses
cicirello/generate-sitemapto scan all HTML files - Strips Google verification files from the sitemap
- Commits
sitemap.xmltolive
- Uses
| ID | Name | Nextcloud instance | Primary | In RSS |
|---|---|---|---|---|
bitcircus |
bitcircus101 | nc.6bm.de | yes | yes |
datenburg |
Datenburg e.V. | cloud.datenb.org | no | no |
To add a new calendar, add an entry to calendars.json — no code changes needed.
Tags are resolved in priority order:
- Explicit
#hashtagsin the Nextcloud event description (e.g.#workshop #hardware) - ICS CATEGORIES field (set in Nextcloud calendar UI)
- Keyword auto-detection from title + description (fallback)
If no tags match, the event gets #community as default.
- Events with "blocker" or "interne veranstaltung" in the title are excluded
- Only future events are shown (up to 120 days ahead)
- Max 30 events per calendar, 40 total
- Loads
events-data.json, falls back to live ICS fetch if JSON unavailable - Renders event cards grouped by month
- Dynamic tag filter bar (OR logic: any matching tag shows event)
- Source badge for non-primary calendar events
- Permalink anchors with smooth scroll
Site chrome (nav + footer): Edit includes/site-header.html and includes/site-footer.html, then run npm run build:layout and commit the partials plus updated *.html. Documented in CONTRIBUTING.md and CLAUDE.md.
Static site — open HTML files directly or use any local server:
python3 -m http.server 8080Contributors only need the quick check — see CONTRIBUTING.md.
npm install
npm run test:quick # unit tests only (~100ms, no browser needed)
npm test # full suite (unit + E2E, used by CI)
npm run test:e2e # only Playwright E2E
npm run test:headed # E2E with browser window
npm run test:ui # Playwright UI modeUnit tests (tests/sync-events.spec.mjs — 22 tests, ~100ms):
| Area | What is tested |
|---|---|
parseDate |
All-day dates, datetime with timezone, UTC, null inputs |
nthWeekday |
Nth weekday calculation, month overflow |
expandRRule |
BYSETPOS + classic BYDAY, weekly, COUNT, EXDATE exclusions |
parseICS |
Single events, all-day, TZID params, line folding, recurring BYSETPOS |
clean |
ICS character unescaping (\n, \,, \;) |
E2E tests (tests/site.spec.js — ~20 tests × 2 browsers):
| Area | Tests | What is tested |
|---|---|---|
| Home page | 3 | Title + heading, CTAs, carousel + map interaction |
| SEO / Meta | 2 | All meta tags on home, subpage descriptions + keywords |
| Privacy | 1 | No Google Fonts (HTML + network) |
| Navigation | 2 | Desktop nav + routing, mobile hamburger toggle |
| Events page | 1 | Title, list, subscribe, RSS, back link |
| Events content | 2 | Tags + filtering + month groups, sync status |
| Donations | 1 | Title, consent banner dismiss |
| Raum nutzen | 1 | Title, CTA, structured data |
| Impressum | 1 | Title + back link |
| Danke page | 1 | Title, noindex, content, back link |
| Terminal theme | 1 | Dark bg, monospace, no inline styles |
| JS errors | 6 | All 6 pages free of console errors |
| Internal links | 1 | Crawls all pages, verifies every internal link resolves |
| Accessibility | 1 | Aria-labels, alt texts, landmark roles |
Browsers: Chromium, Mobile Chrome (Pixel 5).
node scripts/sync-events.mjsThis fetches live ICS data and writes events-data.json + feed.xml to the project root.