Wahadle
Wahadle is a Wordle-like web game for identifying Warhammer 40k datasheets by comparing unit stats. The app uses a Supabase Edge Function to produce an aggregated dataset of datasheets and a Next.js frontend (App Router) for gameplay.
This is not an offical Games Workshop product. I am just a fan of the tabletop game and though this would be a fun idea :)
Features
- Search suggestions with variant-aware matching (datasheet sizes treated as separate suggestions).
- Exact variant selection using
variant_key(Unit ID + Model Count) to avoid ambiguous name matches. - Server-side validation of guesses (checks faction and points to avoid mixups). A debug endpoint is included to inspect mismatches.
- Data comes from a Supabase Edge Function that aggregates rows from a
unitsSQL view.
Prerequisites
- Node.js (16+) and npm installed
- A Supabase project (for the Edge Function or to host the
unitsview). You need the project URL and anon key to fetch the dataset.
Environment
Create a .env.local (Next.js) in the project root with the following values:
# .env.local (example)
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-keyNotes:
- The app's server code calls
loadUnits()which usescreateClient(SUPABASE_URL, SUPABASE_ANON_KEY)to invoke the Supabase Edge Function namedunti-view. Make sure the keys are set for local development. - Do not commit these keys
Install & Run (development)
Install dependencies and start the Next.js dev server:
npm install
npm run devOpen http://localhost:3000 to view the app.
Important Files
app/lib/csv.ts—loadUnits()implementation. It calls the Supabase Edge Functionunti-view, expands aggregatedmodelsinto individualUnitRowentries (one per variant), and returns the array. Currently it fetches fresh data on every call.supabase/Edge_Functions/get-units.ts— Edge Function that queries theunitsview and returns aggregated rows (in development this appears asreturn.jsonexample data).app/api/units/route.ts— Suggestion API used by the frontend. It normalizes names, deduplicates by name+model_count+faction and returns suggestion objects (includingvariant_key).app/api/guess/route.ts— Guess API that accepts{ id?, name?, variant_key?, faction?, points? }. It prefersvariant_keyfor exact variant matching and validates faction & points.app/api/guess/debug/route.ts— Temporary debug endpoint that echoes the incoming payload and the matched unit (useful when the server returns 400 and you need to inspect mismatches).
API Reference
-
GET
/api/units?q=...— Returns up to 20 suggestion objects. Each suggestion includes:id(Unit ID)name(Unit Name)factionpointsmodel_countvariant_key(format:UnitID::ModelCount), use this to select an exact datasheet variant.
-
POST
/api/guess— Submit a guess. Payload can include{ id?, name?, variant_key?, faction?, points? }.- The server will prefer
variant_key(exact variant) thenid, thennameto resolve the guess. - If
faction/pointsare supplied, the server validates them and returns400with a descriptive JSON body if they don't match.
- The server will prefer
-
POST
/api/guess/debug— Debug endpoint that returns the provided body, whether a match was found, matched unit fields, and any mismatch reasons (helpful for debugging 400 responses).
Troubleshooting
-
If suggestions are missing or ambiguous:
- Try the debug endpoint: POST the same payload to
/api/guess/debugand inspect the response. It shows which unit matched and where mismatches occur. - Ensure
SUPABASE_URLandSUPABASE_ANON_KEYpoint to the Supabase project that hosts theunitsview or the Edge Function.
- Try the debug endpoint: POST the same payload to
-
If you receive
400withPoints do not match selected unit:- The request will include a JSON response showing
providedandactualpoints (and rounded values). Use that to determine whether the UI sent the wrongpointsvalue or whether the server has a different points value.
- The request will include a JSON response showing
Performance & Caching
- By default
loadUnits()currently fetches fresh data on each call to ensure the UI sees updates immediately.
Contributing
Feel free to open issues. Not a very complicated app so not looking for programming help for now.
Author
Sean Thornton