Street Art Game — case study

Street Art Game ← ARCHIJS.DEV

Case study · RĪGA · SARKANDAUGAVA · 2026

Street Art Game

A street-art hunt for ROW Baltics' Street Art Month: walk Sarkandaugava, find the murals, prove you were there, and play the wall itself. Built end to end by one engineer.

No app store needed Latvian + English Launches with Street Art Month 2026
01 / THE BRIEF

A neighborhood
becomes the
game board

Street Art Game turns a real Rīga district into a playable map. You sign up with just a name and an email, get a map of locked street-art spots, and walk. Arrive at a mural — your phone knows you're really there — and the spot unlocks: the artwork, the artist's story, and a game played on the art itself.

It's not a competition. No rankings, no clock ticking — you play against the wall, not against other people, and it's paced for families and slow Sunday walks. The games still have teeth if you want them: each one climbs through three difficulty levels, from easy to genuinely tricky.

And it runs as a months-long season, not a one-day stunt. New spots appear in waves, so there's always a reason to come back; when the festival ends, the same app lives on as a gallery — a shareable art map of the neighborhood. The reveal is the reward — nothing shows the full artwork before you've actually stood in front of it.

  • 3APPS — PLAYER · ORGANIZER · SERVER
  • 5WAYS TO PLAY A WALL
  • 1,315AUTOMATED TESTS
  • 0PASSWORDS — A NAME + EMAIL IS THE SIGNUP
02 / THE MAP

The city, restyled
in brand orange

GEOLOCATION / BASEMAP

GPS that earns your trust

City GPS lies — off by 7–13 meters on a good day, a hundred on a bad one, and phones oversell their own accuracy about a third of the time. So "you're here" is never one lucky reading: positions are smoothed, bad readings get thrown out, and only several clean fixes in a row inside the circle count. Your location never leaves your phone — the server only ever hears "visited".

The map is part of the brand too: every street recolored in the festival orange, in light and dark. And the whole map is one self-hosted 13 MB file — no Google, no map service, no trackers.

This band is a real frame of that basemap, rendered from the game's own tiles and palette. Pins: green collected, orange live, dimmed locked.

03 / THE LOOP

How a spot gets
collected

  1. Locked teaser

    The gallery shows a mystery card — a name and a point on the map, never the artwork. Just enough to make you walk.

  2. Walk

    The map shows where; your feet do the rest. Sessions are short bursts between spots, built for one hand and street glare.

  3. Arrive

    Your phone checks, then double-checks — several clean location readings in a row — and the spot flips to "you're here" exactly once.

  4. Open

    Nothing pops up mid-street on its own. You tap Open — that's the moment the spot counts as yours, even if you skip the game.

  5. Play

    A quiz about the piece, or a mini-game played on the artwork itself. Optional — the spot is already yours either way.

  6. Reveal

    The uncropped art and the artist's story unlock, and the gallery keeps them — the reveal is the reward.

04 / THE ARCADE — PLAYABLE

Four games,
one seam

Every game type plugs into the same seam — one registry on the server, one in the app, and a test that fails the build if the two ever disagree. Five types shipped that way; a sixth would need no new plumbing. And an app that meets a game it doesn't know yet politely asks for an update instead of crashing.

The games run entirely on the phone — the server just records the result. Which is why they can run here: these are the app's own game engines, byte-identical, mounted in this page with real Sarkandaugava street-art photos from the game's content.

These embeds run the medium tier — in the real app every game ladders up through bronze, silver, and gold boards. Desktop controls: click the tiles, cells, and palettes; arrows/WASD for the snake; mouse for the paddle, space to serve. On the street it's all thumbs.

Game

05 / THE ENGINEERING

The parts that
have to hold

Offline that converges

A festival crowd saturates cells, and courtyards eat signal, so every write — visit, completion, score — goes through a typed queue in local storage and replays when the network returns. Rejections (4xx) drop; network failures retry; a completion the server hasn't graded yet is honestly is_correct: null, never a fabricated "wrong". App updates re-download only the shell — the 30-day artwork cache stays put.

Players without accounts

Players aren't users: a device-generated token is the whole session, and a name + email is the whole signup. A signed 7-day link verifies the address in the background — play is never gated on it — and switching phones re-binds identity with an emailed 6-digit code. No passwords, no OAuth, nothing to leak; the admin's real auth lives in a fully separate world with roles and an audit log.

A game engine, not an event app

The schema is deliberately content-agnostic — game → locations → activities plus config flags for sequencing, unlock rules, basemap mode, and guidance. "Street art" appears nowhere in API logic. The season model (waves of locations, an explore-mode afterlife) is configuration, not a fork.

Push that respects the platform

The service worker is hand-written (injectManifest) so precache and web-push handlers coexist. Announcements are staged as batches, decoupled from content activation, and fanned out by the scheduler off-request. iOS gets the truth: web push exists only in the installed PWA on 16.4+, and the UI gates its promises accordingly.

An admin the organizer runs alone

Locations are placed on a MapLibre picker with a live capture-radius circle; photos are cropped and compressed in the browser, and iPhone HEIC uploads convert server-side. Waves activate in batches, every game string is editable per-game in both languages, and a KPI funnel shows registrations → visits → completions live during the event.

Proof it holds

Built test-first: 594 Pest cases on the API and admin, 721 Vitest cases on the SPA — including a guard that fails the build if backend and frontend ever disagree about activity types — plus Playwright end-to-end happy paths. The stack ships as Docker Compose behind Caddy with auto-TLS.

The map has no server

The whole basemap is one self-hosted PMTiles file read by HTTP range requests — no tile service, no API keys, no third-party trackers. A single palette restyles every Protomaps layer to the brand: solid orange roads where width alone carries hierarchy, in matching light and dark flavors.

06 / THE STACK

One repo,
three apps

API2026
Laravel 12
thin player JSON APIunauthenticated by design
ADMIN2026
TALL + Mary UI
Livewire · RBAC · audit logorganizer-operated
PLAYER APP2026
Vue 3 PWA
Vite · Pinia · hand-written SWinstallable · offline
MAP2026
MapLibre + PMTiles
self-hosted vector tileszero tile servers
DATA2026
PostgreSQL 16
Docker Compose · Caddydedicated box
QUALITY2026
Pest + Vitest
TDD · Playwright e2e1,315 tests
STREET ART GAME · IELU MĀKSLAS MĒNESIS · SARKANDAUGAVA · RĪGA 2026 IZSTRĀDE: ARTŪRS GREBEŽS · ARCHIJS.DEV