← Back to work
Product design UX Content strategy SvelteKit

Gåri

A bilingual event aggregator for Bergen, designed, built and run solo. Live at gaari.no.

Gåri's event discovery filter
The idea

One place for: what can I do tonight?

Event information in Bergen is scattered. Every venue publishes its own programme, on its own site, in its own format. The only overviews are tourism marketing or ticket-vendor listings, which show only what they have a commercial interest in showing.

Gåri pulls what's on across around sixty local sources into one filterable listing. The name is Bergen dialect: a contraction of "ke det går i?", roughly "what's going on?"

The product

Not a wall of filters. A question.

The discovery flow asks in sequence: who are you, when, what, and where in the city. Every filter state lives in the URL, so any view is shareable and survives the back button. It is built as an accessible pill-and-grid pattern with full keyboard navigation and live result counts.

Decisions worth explaining
01
A photo-less event still looks intentional
Many event listings have no usable image. Instead of a broken card, a photo-less event renders as a category-coloured field with a category icon, so it reads as a deliberate design state rather than a gap.
02
Aggregating without plagiarising
Norwegian copyright law (åndsverksloven, the Copyright Act) protects the source text, so no description is ever copied. Each one is regenerated from scratch as a short bilingual summary by Gemini 2.5 Flash, with a plain template as fallback. A design constraint resolved by a technical choice.
03
Honest by default
The collector cannot always be sure an event is free, so the badge says "likely free", never "free". Ticket links always resolve to the actual venue, never to another aggregator. Paid placement is always labelled "Featured", because Norwegian marketing law requires it to be identifiable.
Design system

Funkis.

The design language is named after the Sundt building in Bergen (1938), a landmark of Norwegian functionalism: clean lines, honest materials, function before decoration. One accent colour drawn from the building, Barlow Condensed and Inter, flat surfaces, no gradients.

Colour is never the only signal, so every badge is colour, icon and text together. WCAG 2.2 AA, with 44-pixel touch targets throughout. (Funkis is the Norwegian word for functionalism.)

Built to run, not just launch

Collection runs automatically twice a day. Anomaly detection classifies every source as healthy, warning, dormant or broken, and a daily digest flags anything that drifts. A public data-collection page, a venue opt-out form, an honest crawler identity, and rate-limited requests that respect robots.txt. Non-public events are excluded on purpose.

It has been operating continuously, not launched and left.

Where it stands

Live and in daily use. Some things are deliberately unfinished: dark mode is designed but disabled, a map view is planned but not built, and the canonical-URL strategy for filtered views is still unresolved. There are no traffic figures here on purpose, only what can be measured goes in public.

Built with
SvelteKit TypeScript Supabase Vercel Tailwind Gemini Stripe Resend MailerLite Umami UptimeRobot GitHub Actions
My role
Product, design, build, content, SEO and ops — solo
Type
Live product, in production
Built with
SvelteKit + Supabase + Vercel
Live
Other projects

Have a role or a project in mind?

Let's work together!