A developer-themed semantic guessing game — guess languages, frameworks, and tools from attribute clues, not letters.
Play: devdle.co.uk · Repo: github.com/jayc595/devdle
Devdle is like Wordle for developers, but instead of matching letters you decode semantic attributes. Pick a category, search for a name, submit your guess, and each column reveals how close you are — typing model, execution model, paradigm, year, and more.
- 6 guesses per puzzle
- Two modes:
- Unlimited — a new random target each session
- Daily — one shared puzzle per category each UTC day
- Feedback types: correct, partial (multi-value overlap), wrong, and higher/lower for numeric attributes
| Category | Words | Example clues |
|---|---|---|
| Languages | 45+ | typing, execution model, memory model, primary domain, concurrency model, paradigm, year |
| Frameworks | 65+ | framework type, host language, rendering strategy, opinionated, component based, runtime |
| Tools | 75+ | tool type, primary purpose, execution environment, statefulness, complexity |
- Server-authoritative game state — the target word is never sent to the client until you win or lose; progress lives in an AES-256-GCM encrypted httpOnly cookie.
- Deterministic daily puzzles — a server-only secret selects the same word for every player each day without exposing it client-side.
- Security-first edge layer — centralized request proxy with nonce-based CSP, HSTS, API lockdown CSP, same-origin guards, and IP rate limits.
- Typed, extensible content model — categories, attribute schemas (text / enum / multi_enum / number / boolean), and word data validated at seed time.
- Share results — Wordle-style emoji grid after each game; copy or native-share via
lib/game/share.ts. - Local player stats — streaks and score cards stored in browser localStorage.
- AI/crawler docs —
/llms.txt,/llms-full.txt, and/ai.txtfor LLM and crawler discovery. - Privacy-first analytics — optional PostHog via first-party
/ingestproxy; game events also logged in Postgres. Accept/Reject consent banner; PostHog is opt-out by default until accepted. No accounts. Policy at/privacy. - Test coverage where it matters — ~30 test files covering game logic, session crypto, API routes, security headers, rate limits, consent, share, and site docs.
- CI quality gate — GitHub Actions runs tests and ESLint on every push and pull request.
- Polished UX — staggered clue reveals, a navigation guard when leaving mid-game, and an interactive 404 terminal.
No user accounts. The game API is stateless aside from an encrypted cookie; the word catalog lives in Postgres.
flowchart LR
Browser --> NextApp[Next.js App Router]
NextApp --> Proxy[proxy.ts]
Proxy --> Pages[Pages and RSC]
Proxy --> API[Game API routes]
Proxy --> Ingest["/ingest PostHog proxy"]
API --> Session[Encrypted cookie session]
API --> Prisma[Prisma plus Neon Postgres]
API --> Analytics[lib/analytics dual-write]
Analytics --> Prisma
Analytics --> Ingest
Browser --> LocalStats[localStorage stats]
- Framework: Next.js 16 (App Router), React 19, TypeScript
- UI: Tailwind CSS 4, shadcn/ui, Base UI, next-themes
- Data: Prisma 7 + Neon Postgres (pooled + direct URLs)
- Analytics: PostHog (
@posthog/next) with first-party/ingestproxy; events also stored in Postgresanalytics_events - Validation: Zod 4
- Testing: Vitest, Testing Library, jsdom
- Tooling: ESLint 9, GitHub Actions CI
- Node.js 22 (matches CI)
- npm
- A Neon Postgres database (or any Postgres instance)
git clone https://github.com/jayc595/devdle.git
cd devdle
npm installCopy the example env file and fill in your values:
cp .env.example .env.local| Variable | Purpose |
|---|---|
DATABASE_URL |
Pooled connection for app runtime (Neon -pooler suffix) |
DIRECT_URL |
Direct connection for Prisma CLI and migrations |
GAME_SESSION_SECRET |
32+ character random string for cookie encryption |
DAILY_PUZZLE_SECRET |
Different 32+ character random string for daily word selection |
NEXT_PUBLIC_SITE_URL |
Public canonical URL for OG metadata, share links, sitemap (default https://devdle.co.uk) |
ALLOWED_API_ORIGINS |
Optional comma-separated extra origins for API same-origin checks (preview deploys) |
ENABLE_DEV_TOOLS |
Optional. Set to true to enable the dev-only answer reveal API |
DEV_TOOLS_ACCESS_KEY |
Required with dev tools enabled. Must match the devToolsKey URL query param |
NEXT_PUBLIC_POSTHOG_KEY |
Optional. PostHog project API key for anonymous analytics |
NEXT_PUBLIC_POSTHOG_HOST |
Optional. PostHog ingest host (default EU: https://eu.i.posthog.com) |
.env.local is gitignored — never commit secrets. Only .env.example is tracked as a template.
When PostHog is enabled, analytics only runs after the user accepts the consent banner.
Dev answer reveal: Set both ENABLE_DEV_TOOLS=true and DEV_TOOLS_ACCESS_KEY, then visit a game page with the key in the URL, e.g. /game/languages?devToolsKey=your-key. The reveal control only appears while that param is present.
npm run db:migrate # apply migrations
npm run db:seed # seed categories, attributes, and wordsnpm run devOpen http://localhost:3000.
npm run test:run
npm run lint- Set production env vars (unique
GAME_SESSION_SECRETandDAILY_PUZZLE_SECRET— never use.env.exampleplaceholders). - Do not set
ENABLE_DEV_TOOLSin production. - Set
NEXT_PUBLIC_SITE_URL=https://devdle.co.uk. - Optionally set
NEXT_PUBLIC_POSTHOG_KEY(+NEXT_PUBLIC_POSTHOG_HOSTfor EU). - Build and migrate:
npm run build
npm run db:deploy # includes analytics_events migration
npm run start # or deploy to Vercel- Re-seed only when adding/updating word catalog:
npm run db:seed.
Production site: devdle.co.uk.
| Script | Purpose |
|---|---|
dev |
Start dev server |
build / start |
Production build and serve |
test / test:run |
Vitest watch / CI mode |
lint |
ESLint |
postinstall |
Runs prisma generate after npm install |
db:migrate |
Run migrations (development) |
db:deploy |
Apply migrations (production) |
db:seed |
Seed word catalog |
app/ # pages, API routes, privacy, llms/ai.txt routes
components/ # game UI, layout, analytics, consent providers
lib/
analytics/ # PostHog capture, Postgres event store, distinct-id
consent/ # analytics consent localStorage helpers
game/ # session, compare, daily puzzle, share
...
instrumentation.ts # server env validation on Node boot
proxy.ts # CSP, rate limits, PostHog /ingest proxy
prisma/ # schema, migrations, seed
To add content, extend the seed data in lib/categories/words/ and ensure attributes match the schema in lib/categories/attributes/, then re-run npm run db:seed.
Issues and pull requests are welcome.
Before submitting, run:
npm run test:run
npm run lintTo add words: update the seed files in lib/categories/words/, match the category attribute schema, and re-seed the database.
Licensed under the MIT License.