Wo häre?
2026Schmeiss e Pfyl u lue, wo’s di häre nimmt.
Throw a dart at a map of Switzerland and let it decide where to go next. The whole interface is in Berndeutsch. No API keys, no environment variables — every data source is public.
Next.js · MapLibre GL · swisstopo · Web Audio · Tailwind CSS

How it works
A dart lands on a screen pixel, the pixel becomes a coordinate, and swisstopo turns the coordinate into a place.
- Tiles.
wmts.geo.admin.chserves the swisstopo Landeskarte with no key. - Reverse geocoding. One
identifyrequest against the Gemeinde layer returns the municipality and canton. Only the record withis_current_jahr === truecounts — the API also returns historical ones going back to 1850. - Elevation. The
heightendpoint needs LV95 coordinates, so the app converts them with swisstopo’s approximate formulas, checked against the reframe service and accurate to about 5 cm. - Water. swisstopo lists lakes in the Gemeinde layer under their own name, so Thunersee comes back as a “municipality”. That is how the app detects a splash without shipping any polygons.
- Abroad. No records at all means the dart left the country. Records but none current means border water, like the French half of Lac Léman.
One trap is worth writing down: mapExtent must bracket the queried point. A bogus extent makes identify return zero results instead of an error — which reads exactly like “abroad”.

Three views
| View | What it is |
|---|---|
| Charte | swisstopo Landeskarte, mercator, camera kept near Switzerland |
| Wäutchugele | MapLibre globe projection over OpenFreeMap world tiles |
| Aaflug | starts on the globe, dives into Switzerland, Landeskarte appears |
All three run on one MapLibre instance. setProjection, addSource and addLayer all throw before the style has loaded, and isStyleLoaded() never returns true for the world style — so readiness is tracked from the style.load event per map instance instead.

Three throw mechanics
Grab the dart at the bottom and drag. One gesture carries both the aim and the force: the drag’s direction points the dart, its length is the force. A live overlay draws the flight path and a crosshair on the predicted landing spot, so you can see where it will go before letting go.
| Style | What it does |
|---|---|
| Zieh | pull back like a slingshot; the dart flies the opposite way |
| Schlüder | drag straight at the target instead; the dart follows the drag |
| Ei Tipp | one tap, no aiming, pure luck |
The preview function is deliberately free of randomness, so the overlay and the actual throw agree. Drags shorter than a minimum threshold are ignored, so a plain click never throws. Pointer capture keeps the drag alive anywhere on screen while leaving the rest of the map free to pan.

How badly you miss
Aiming only ever biases the throw — it never determines it, because nobody playing this can actually throw darts. The miss is calibrated from Tibshirani, Price & Taylor, A statistician plays darts (J. R. Statist. Soc. A, 2011), who model a throw as a 2-D Gaussian around the aim point and measured themselves over 100 throws at a board of radius 170 mm.
| σ | Who |
|---|---|
| 64.6 mm | author 1 — not a dart player, trying his best. Averaged 11.65 points, worse than throwing uniformly at random (12.82) |
| 26.9 mm | author 2 — “a fairly skilled darts player” |
| < 20 mm | the threshold for actually being good |
64.6 / 170 ≈ 0.38, so a beginner’s spread is nearly 40% of the target radius. That is what this app throws with. The map is the dartboard, so σ scales with the map’s radius, and a throw at full force lands exactly on that beginner figure — ease off and you do better. Measured over 1.2M simulated throws per force level on a 1280×800 view, by a script that ships with the project and reads the constants off the game:
| Force | σ | Median miss | Off the board |
|---|---|---|---|
| 0% | 61 px | 23 km | 0.1% |
| 50% | 106 px | 40 km | 1.6% |
| 100% | 152 px | 57 km | 7.8% |
The paper’s remark that “a beginner will occasionally miss the board entirely” is where the occasional Dernäbe! card comes from. An earlier calibration ran to 23% off-board at full force, which is not “occasionally”.
Three further details, all of them things real throwers do:
- Not circularly symmetric. The paper’s section 3 moves to a general covariance matrix; release timing shows up mostly as height error, so the vertical spread is the wider one.
- A consistent tendency. Everyone pulls one way. The bias is drawn once per session, so it feels like your own wonky arm rather than fresh noise.
- The occasional shank. 7% of throws are a Chnorz: nearly double the spread, and the dart sails past the target, tumbles end over end and flutters back to stick in at a silly angle.
The dashed ring on the aim overlay is 1σ — roughly two thirds of throws land inside it. It grows with force, so you can see the gamble before taking it.
Sound
Everything is synthesised with the Web Audio API, so the app ships no audio files. It is off by default; the toggle sits in Yschtellige.
| When | What |
|---|---|
| pulling back | a tension tone that climbs in pitch with the force, plus a ratchet click every notch |
| release | a whoosh, louder the harder it was thrown |
| a Chnorz release | the whoosh plus a wobbling descending whistle for the tumble |
| landing | a filtered noise thwack |
| bullseye | a Chueglogge |
| off the map | a short descending blip |
The tension tone is a sustained oscillator, so starting it hands back a handle that the caller must always stop — including when a drag is cancelled or the component unmounts mid-drag. Audio can only start from a user gesture, and the pointer press that begins a drag is exactly that.

Copy
Every user-facing string lives in one file, and every word is checked against berndeutsch.ch by a script that ships with the project.
Words that failed the check were replaced rather than shipped: it is dernäbe not “danäbe”, preiche for hitting the target rather than “träffer”, and Badhose rather than “Badhösli”.
Destinations
A curated list holds the interesting spots. Coordinates came from swisstopo’s search API and were then verified against the Gemeinde layer and the elevation API — a wrong coordinate cannot survive an elevation check, which is how a football stadium in Thun stopped impersonating the Stockhorn summit. A second script re-runs that check against every coordinate on the list.
A dart that lands more than 8 km from any curated spot falls back to the plain municipality name, so the list never has to be complete.
Attribution
Required, and rendered by MapLibre from the source specs: © swisstopo for the Landeskarte, OpenFreeMap and OpenStreetMap for the globe.