// case · upc-freiburg.de

a church calendar that keeps itself

websiteown codeparish · freiburgukrainian + germanlive since 21.09.2026

the most important question in a parish is always the same: when, at what time, which feast? i built a website for the ukrainian orthodox community in freiburg whose calendar answers that question by itself — a julian calendar in the browser, checked over 2,191 days without a single mismatch, synced with the chapel’s calendar three times a day. eleven pages, two languages, zero external requests on load. above you can scroll through the home page and see the calendar in action.

2,191
days checked · 0 mismatches
3×
daily sync with the chapel
0
external requests on load
11
pages · ua + de
↓ read the full case
// the build — one question, one calendar, one website

how “when is the next service?” became a website that answers it by itself, every day

one parish, two calendars, not a single stock photo ✦
✓ = what stayed✗ = what went
01 · the question

when, at what time, which feast?

the ukrainian orthodox community in freiburg has been worshipping since 2023 in a borrowed chapel in günterstal. there was no website — a youtube channel with five videos and a phone number. anyone new to the city, often just arrived, often in a hard hour, found nothing.

on top of that, the community lives by the julian calendar. every feast has two dates, every sunday a tone, every week a fasting rule. and that is exactly the question asked most often: when, at what time, which feast. the website had to answer it — not once, but every day, without anyone maintaining it.

✗ before: no website — a youtube channel, a phone number
✗ two calendars: old style, new style, tone, fasting — all kept in people’s heads
✗ the schedule: ended on 30.09.2026, and nobody maintains a website on the side
✓ the fix: a calendar that computes itself, syncs itself and never goes stale

02 · the first draft

the first draft looked like AI — so it went

on 22.08. a finished draft was ready: clean, modern, generic. small spaced-out capitals under every block, card grids with arrows, a “dashboard” hero with a giant 9:30. my verdict: looks like AI, pushes people away. so i looked at living parish sites in germany. they hold on to three things: a real photo of the church, the seal ІС ХС НІ КА, a plain list with dates. nothing more.

the next service became a sentence — “on sunday, 4 october, at 9:30” — instead of a tile with a number. the sacraments a list instead of a wall of cards. and the captions italic and quiet instead of in capitals.

✗ ~40 small spaced-out capital labels → ✓ 0 — italic, quiet captions
✗ a hero like a dashboard, 9:30 in giant type → ✓ the next service as a sentence
✗ two card grids with arrows (“i would like …”, sacraments) → ✓ one list
✗ frames and 1-px grids around everything → ✓ three colours: paper, ink, wine

Erste Version der Gemeinde-Website, September 2026, deutsche Seite: „Der nächste Gottesdienst — am Sonntag, 13. September, um 9:30 Uhr, in 5 Tagen“, darunter 15. Sonntag nach Pfingsten, links die Ikone des Tages
version 1, september 2026 — the next service as a sentence, with the icon of the day
03 · today in the church year

a calendar that computes itself in the browser

under the first picture sits a wine-red strip: the date, the date in the old style, the tone of the week, fast day or not, days until the next great feast — and on the right the next service as a sentence. nobody maintains this strip. it computes. once in python for the build, once in javascript for the browser, and both have to say exactly the same thing, byte for byte.

that’s why there is a test: 2,191 days, from 1 january 2025 to 31 december 2030, six easters, 6,573 comparisons. result on 02.10.2026: zero mismatches. the page doesn’t go stale between two builds — open it on a tuesday, and it shows tuesday.

Weinrote Leiste „Heute im Kirchenjahr“ auf upc-freiburg.de am 2. Oktober 2026: Freitag, 2. Oktober, nach altem Kalender 19. September, 8. Ton, Fasttag, Mariä Schutz und Fürbitte in 12 Tagen; rechts „Am Sonntag, 4. Oktober, um 9:30 Uhr“
“today in the church year” on 2 october 2026 — old style 19 september, tone 8, fast day, 12 days to the protection of the theotokos; right: “on sunday, 4 october, at 9:30”
// and today — live in your browser
Today in the church year
Friday, 2 October
old style: 19 September · tone 8 · Fast day (Friday)
Protection of the Theotokos in 12 days
computed
in the browser — no server, no upkeep
checked
2,191 days · 0 mismatches
as of 02.10.2026 — with javascript on, this strip computes itself in your browser for today
04 · the service schedule

flip through months, the feast on hover, every service into your own calendar

its own page, “gottesdienstplan”: month by month, marked days, and on hover or tap the feast appears — with icon, saints of the day and tone. below it the list, and on every service “in den kalender”: one .ics file per service, plus the whole schedule as a subscription for google, apple or outlook — 33 services in one file.

on the phone the same logic, just with the thumb: tap instead of hover, month navigation 44 px big, no horizontal scroll from 320 to 390 px. the browser itself recognises past services — again without a new build.

Monatsraster Oktober 2026 mit markierten Tagen 4, 11, 13, 14 und 18, daneben das Fest des 4. Oktober; darunter die Liste der Gottesdienste mit Ikone, Heiligen des Tages und „in den Kalender“
october 2026 — 4, 11, 18 liturgy, 13 vespers, 14 protection of the theotokos, the patronal feast; every entry with “in den kalender”
Gottesdienstplan am Telefon: Überschrift, Monat Oktober 2026 mit großen Pfeilen, unten eine Leiste mit Gottesdienste, Anfahrt, Anrufen und Sprache
the schedule on a phone — bottom bar: services · directions · call · language
05 · the schedule keeps itself

three times a day the website asks the chapel’s calendar

the chapel doesn’t belong to the community. it is shared, and the bookings sit in a common calendar — our services in it as “ukrainischer gottesdienst”. since 30.09.2026 a script reads this calendar at 7, 13 and 19 o’clock: new services come in, cancelled ones go out, sundays and feasts get their names from the parish’s own church calendar, the site is built and published — only if something changed.

the rules matter more than the code: hand-kept entries are never overwritten. if the calendar doesn’t answer, everything stays as it is. saints of the day are never invented — where there is no source, nothing is written.

  1. the chapel’s calendar
  2. sync · 7 · 13 · 19 h
  3. parish schedule + church calendar
  4. online — only if something changed
services in the scheduleuntil 30.09.2026until 27.12.2026 — 15 services from the chapel’s calendar
upkeepby hand, for every new dateautomatic · 7 · 13 · 19 h
if the calendar is silent—nothing changes
06 · real pictures

no stock photo, no AI image — not even the chapel stayed borrowed

at the start there was a single borrowed picture: the chapel from wikimedia, with the photographer credited. then came the community’s own pictures — first 21 files, later 28. i took what tells a story and exposes no one: 16 pictures on the home page, the rest under “über uns”, plus a film of the christmas feast, 3:11, that only loads on click. gps data from the phone photos is gone before it ever reaches the server.

every picture has a “faces” field in the code. one switch — and all pictures with recognisable people disappear without breaking the grid. there are deliberately no captions, only alt texts: a wrong name under a holy picture is worse than none.

the pictures that stayed show what a parish is made of: the holy water, the reading, the faces after the liturgy — and the altar before anyone arrives.

Drei Geistliche in weißen und goldenen Gewändern mit der Schale für das Weihwasser, daneben eine ältere Frau im rosa Kopftuch mit einer Kerze — eigenes Bild der Gemeinde
holy water
Der Altar vor dem Gottesdienst unter weinroten, goldbestickten Decken, daneben eine brennende Kerze und Blumen — eigenes Bild der Gemeinde
the altar
Ein Priester in goldenem Gewand liest das Evangelium vom Pult mit violettem Tuch, hinter ihm stehen erwachsene Gemeindemitglieder — eigenes Bild der Gemeinde
the gospel
Nach der Liturgie: der Priester mit dem Kreuz spricht mit einer Frau im bunten Kopftuch, vorne eine Frau im blauen Tuch, daneben der Altardiener — eigenes Bild der Gemeinde
after the liturgy
Ein Priester in goldenem Gewand betet mit erhobenen Händen vor der Ikone der Auferstehung, davor Kelch und Kerze auf dem Altar — eigenes Bild der Gemeinde
prayer before the icon
Weihnachtsliturgie: zwei Geistliche in weißen Gewändern, einer mit Weihrauchfass, vor einem barocken Altar und einem geschmückten Weihnachtsbaum
christmas liturgy
six of the community’s own pictures — no stock photo, no AI image on the whole site
07 · type, colour, thumb

premium for ordinary people: type, contrast, a bar for the thumb

the audience: ukrainians between 30 and 70, on the phone, often on this site for the first time. premium here doesn’t mean effects, it means calm. cormorant garamond and fixel text — both with ukrainian cyrillic, both local, around 160 kb together, no connection to google fonts. three colours: paper, ink, wine. body text 18 px instead of 16. the quiet text from 3.3:1 to 6.8:1 contrast, so older eyes can read it.

on the phone a bottom bar with exactly four things: services, directions, call, language. and nothing moves that doesn’t help — with “reduced motion” nothing moves at all.

Göttliche Liturgie · Ton 1
Abschluss des Festes der Kreuzerhöhung · Hl. Apostel Quadratus
before · 3.3:1 · #8d8474 on paper
Göttliche Liturgie · Ton 1
Abschluss des Festes der Kreuzerhöhung · Hl. Apostel Quadratus
now · 6.8:1 · #5e5140 on paper
contrast of quiet text3.3:16.8:1
typefacessystem (iowan / georgia)cormorant + fixel · local · ~160 kb
external requests on loadosm iframe + youtube0
horizontal scroll 320–390 pxup to 20 px (imprint, privacy)0
08 · law and trust

imprint, privacy, faces — nothing you have to explain later

a parish isn’t a company, and still § 5 ddg applies. imprint and privacy policy are written, twelve sections, among them one on photos from parish life (§ 22/23 kunsturhg) and how to have yourself removed from a picture. youtube videos are facades: the preview lives with us, the iframe only comes on click — before that, not a single request goes to google. the map is a static image from our own server, not an iframe. the wikimedia photo keeps its licence credit for as long as it is on the site.

and for the offer to have a baptism or wedding filmed there is deliberately no price: the parish is not commercially active, and it has to stay that way.

✗ osm map as an iframe — a request on opening → ✓ static map, own server, 0 requests
✗ youtube iframe — a request to google before every click → ✓ facade: preview with us, iframe only on click
✗ photos without a rule → ✓ “faces” register in the code, one switch, § 22 kunsturhg in the privacy policy
✗ prices on the parish site → ✓ no price, not the word “leistung” — § 60a ao

09 · live

live since 21 september 2026 — the schedule has been running by itself ever since

domain, dns, hosting, certificate in one morning. eleven pages, ukrainian and german, each with canonical and hreflang, sitemap, llms.txt, json-ld for the church and every service as an event. the video plays on an iphone too, because the server answers range requests. 16 requests on load — all to the parish’s own domain. and since 30.09. the schedule keeps itself.

11 pages · 2 languages · 0 external requests · 15 services in the schedule
measured on 02.10.2026 — upc-freiburg.de
see the service schedule ↗

a website for a parish doesn’t have to impress. it has to give the right answer every day — when, at what time, which feast — without anyone maintaining it.

got a parish, a practice, a club — and nobody to maintain a website?the ball’s in your court →
// your move

Let’s talk 15 minutes.

Tell me what you need — I get back to you the same day with a clear proposal.

Heidar Rudyi
I answer myself.Heidar Rudyi · Freiburg

Websites — packages & prices (German) →Free audit →

I only use your details to reply to you. No newsletter, no sharing.

let's play