Play it live: spoodytracker.com — no account, drop a sighting, watch it appear for everyone.
A retro pixel-art community sightings map. Anyone on Earth can drop a sighting — codename, message, optional photo, no account — and everyone else watches it pop onto a spinning globe live. Like reports, reply in threads, and keep an eye on the spider button for new alerts.
Unofficial fan project inspired by a certain web-slinger's tracker. All art is original hand-drawn pixel work; no studio assets are used. Not affiliated with or endorsed by any film studio or comics publisher.
100% free to run. No API keys for the map, no credit card anywhere in the default stack, MIT licensed.
git clone <your-fork-url> spoody-tracker
cd spoody-tracker
npm install
npm run devOpen http://localhost:5199. That's the whole thing: with no backend configured the app runs in demo mode — simulated worldwide sightings, your own reports persist in your browser, and every feature works locally.
Demo mode is local-only. To make reports visible to everyone, add a free Supabase project (no card required):
-
Create a project at database.new, then in the SQL editor run, in order:
supabase/migrations/0001_init.sqlsupabase/migrations/0002_social.sql
-
Deploy the edge functions (install the Supabase CLI first):
supabase link --project-ref <your-project-ref> supabase secrets set IP_SALT=$(openssl rand -hex 24) ADMIN_TOKEN=$(openssl rand -hex 24) supabase functions deploy report-sighting --no-verify-jwt supabase functions deploy flag-sighting --no-verify-jwt supabase functions deploy like-sighting --no-verify-jwt supabase functions deploy reply-sighting --no-verify-jwt supabase functions deploy admin --no-verify-jwt
-
Point the app at it — copy
.env.exampleto.env:VITE_SUPABASE_URL="https://YOUR-PROJECT.supabase.co" VITE_SUPABASE_ANON_KEY="YOUR-ANON-KEY"
-
npm run devagain. Open two browsers, report in one, watch the pin pop into the other. That's the realtime path everyone on your deployment shares.
Supabase free projects pause after ~7 idle days. This repo ships
.github/workflows/keepalive.yml — add SUPABASE_URL and
SUPABASE_ANON_KEY as GitHub Actions secrets and it pings every 3 days.
Any static host works. Cloudflare Pages is a
good default (unmetered bandwidth): connect the repo, build command
npm run build, output directory dist, and add your VITE_* variables in
the Pages environment settings.
- Users can FLAG any sighting; 3 unique flags auto-hide it everywhere.
- The hidden admin page lives at
/admin.html— paste yourADMIN_TOKENto see flagged/hidden/unscreened queues and restore/hide/delete. - Photos are screened in the browser (bundled NSFW model) before upload; anything that slips through can be flagged and removed.
- Fallback: the Supabase Studio table editor can do everything manually.
| Feature | How |
|---|---|
| Bot check on reports | Create a free Cloudflare Turnstile site, set VITE_TURNSTILE_SITE_KEY (client) and supabase secrets set TURNSTILE_SECRET=... (server) |
| Stricter photo policy | supabase secrets set TRUST_CLIENT_SCREEN=off — photos land blurred until you approve them in the admin queue |
Everything brandable is config: set VITE_SITE_NAME and VITE_TAGLINE, swap
the palette in src/styles/tokens.css, and redraw sprites in
src/sprites/*.pix.ts (ASCII grids — see CONTRIBUTING). The default identity
is intentionally our own.
- MapLibre GL JS — BSD, globe projection, no key
- OpenFreeMap tiles — no key, no limits
(
VITE_TILES_URLoverrides for self-hosting) - Vite + Preact + signals; WebAudio-synthesized SFX (no audio assets)
- Supabase free tier — Postgres + RLS, Realtime, Storage, Edge Functions
- nsfwjs — in-browser photo screening
- Geocoding: BigDataCloud free client API at report time, offline fallback
Pixel art is authored as ASCII grids in src/sprites/*.pix.ts — one char per
pixel, palette-locked. npm run sprites compiles them to crisp PNGs (1x/@3x)
in public/sprites/. Off-palette colors fail the build; diffs stay readable.
MIT — see LICENSE. Please keep your deployment's own branding honest about being an unofficial fan project.