Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
One letter, every category, quickest wits win. A party word game for Discord — إنسان، حيوان، نبات، جماد
Translation pending
GamesTypeScript · PLpgSQLGitHub @mPhpMasterOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Human, Animal, Plant, Object - Discord Activity word game
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Human, Animal, Plant, Object — Discord Activity إنسان، حيوان، نبات، جماد. A multiplayer word game that runs inside a Discord voice channel as an Activity. Built with Next.js (App Router) on Vercel, Supabase (Postgres + Realtime), and the Discord Embedded App SDK. The UI comes in English and Arabic, with full right-to-left layout for Arabic.Read the full README ↗
إنسان، حيوان، نبات، جماد. A multiplayer word game that runs inside a Discord voice channel as an Activity. Built with Next.js (App Router) on Vercel, Supabase (Postgres + Realtime), and the Discord Embedded App SDK. The UI comes in English and Arabic, with full right-to-left layout for Arabic.
src/lib/scoring.ts)| Answer | Points |
|---|---|
| Valid, and nobody else wrote the same word in that category | 10 |
| Valid, but another player wrote the same word | 5 |
| Invalid, blank, or wrong starting letter | 0 |
The server decides whether an answer is valid, in this order:
Matching ignores case, accents, and Arabic diacritics. It treats أ/إ/آ/ا as the same letter, and likewise ى/ي and ة/ه. A leading "ال" or "the " is also allowed. So "الأسد" counts for أ, and "The Rock" counts for R.
Discord client ──iframe──▶ https://<client_id>.discordsays.com (Discord proxy)
│ / → your Vercel app
│ /supabase → <ref>.supabase.co (Realtime websocket)
│ /discord-cdn → cdn.discordapp.com (avatars)
▼
Next.js on Vercel
/api/auth/discord trades the OAuth code for a token, checks the user with Discord, returns a signed session (JWT)
/api/game/[action] join · state · settings · ready · start · answers · endRound · vote · verdict · tally · next · lobby
│ service-role key
▼
Supabase Postgres ── Realtime (postgres_changes on `games`) ──▶ every client refetches state
/api/game/*, which checks the Discord session before touching the database. Picking letters, round deadlines, closing rounds, and scoring all happen on the server. Race-prone steps run as atomic SQL functions (start_round, end_round, apply_round_scores).games.version. Clients subscribe to that row through Supabase Realtime and refetch a view of the game tailored to them. Clients also poll state every 5 seconds. That poll doubles as a heartbeat (who's online, host handover) and as a fallback if the websocket drops.rounds.ends_at is set in Postgres. Clients measure how far their clock is from the server's on each response and count down to the server's deadline. The server accepts answers up to 2 seconds after the deadline to catch the last auto-save, then closes the round itself.games row, and no table accepts writes from the client.supabase/migrations/…_init.sql tables, RLS, triggers, RPCs, realtime publication
src/app/api/auth/discord OAuth2 code exchange → session token
src/app/api/auth/guest local test mode (ALLOW_GUEST_MODE=true only)
src/app/api/game/[action] game action router
src/server/game.ts all game rules and state projection
src/server/session.ts session JWT (jose)
src/lib/letters.ts alphabets, normalization, letter check
src/lib/scoring.ts validity + points (shared by server and live preview)
src/lib/discord.ts Embedded App SDK boot + URL mapping patches
src/hooks/useGame.ts realtime subscription, polling, clock sync
src/components/ Lobby, RoundPlay, Voting, RoundResults, FinalLeaderboard
src/i18n/en.json, ar.json every UI string (CLDR plural forms for Arabic)
tests/ node:test unit tests (scoring, letters, i18n key parity)
supabase link --project-ref <ref> and then supabase db push, orsupabase/migrations/20260915000000_init.sql into the SQL editor.sb_publishable_… key)sb_secret_… key)pg_cron and schedule the cleanup:
select cron.schedule('cleanup-games', '0 * * * *', 'select public.cleanup_stale_games()');
Go to discord.com/developers/applications and click New Application.
On the OAuth2 page:
https://127.0.0.1. Discord requires one, but Activities never actually use it.On Activities → Getting Started, enable Activities for the app.
On Activities → URL Mappings, add these mappings. Targets have no https:// and no trailing slash.
| Prefix | Target |
|---|---|
/ | your-app.vercel.app |
/supabase | <project-ref>.supabase.co |
/discord-cdn | cdn.discordapp.com |
The app calls patchUrlMappings() on startup. That rewrites Supabase and avatar URLs to go through these prefixes, because Discord's content security policy (CSP) blocks every host that isn't mapped.
On Installation, enable Guild Install and User Install.
On Activities → Settings, choose the supported platforms: Web, iOS, and Android. The layout is responsive and works on phones.
OAuth scopes requested at runtime: identify and guilds.
To launch it, join a voice channel, open the 🚀 Activities menu, and pick your app. While the app is unverified, only you, your team members, and users you add under App Testers can launch it.
Import the repo into Vercel. The framework preset is detected automatically.
Add these environment variables (see .env.example):
| Variable | Where it's used |
|---|---|
NEXT_PUBLIC_DISCORD_CLIENT_ID | client + server |
DISCORD_CLIENT_SECRET | server only |
NEXT_PUBLIC_SUPABASE_URL | client + server |
NEXT_PUBLIC_SUPABASE_ANON_KEY | client (Realtime only) |
SUPABASE_SERVICE_ROLE_KEY | server only |
SESSION_SECRET | server only. Generate with openssl rand -base64 32 |
ALLOW_GUEST_MODE | set false in production |
Turn off Deployment Protection for the environment Discord points at (Project → Settings → Deployment Protection). Otherwise Discord's proxy gets a Vercel login page instead of the game.
Framing headers: next.config.ts sends Content-Security-Policy: frame-ancestors with Discord's domains (discord.com, *.discord.com, *.discordsays.com). It doesn't send X-Frame-Options, so the page can be embedded. No vercel.json is needed.
Point the / URL mapping at your production domain.
cp .env.example .env.local # fill in the values
npm install
npm run dev
Without Discord (quickest). With ALLOW_GUEST_MODE=true, open http://localhost:3000, pick a name and a room code, then open more tabs with the same ?room= to play against yourself. Each tab gets its own guest identity. Guest rooms are kept separate from real Discord instances.
Inside Discord. Expose your dev server over HTTPS and point the / URL mapping at it:
npx cloudflared tunnel --url http://localhost:3000
If hot reload complains about the tunnel host, add it to allowedDevOrigins in next.config.ts.
| Command | What it does |
|---|---|
npm run dev | Next.js dev server |
npm run build | production build |
npm run lint | TypeScript type-check |
npm test | unit tests for scoring, letter normalization, and that en/ar have matching keys and all used keys exist |
{ id, emoji } to src/lib/categories.ts.categories.<id> to both en.json and ar.json.npm test. It fails if a label is missing in either language.t("section.key", { vars }). For counts, pass count. Arabic plural forms (_zero, _one, _two, _few, _many, _other) are picked automatically.join. Call GET /applications/{id}/activity-instances/{instance_id} with a bot token. Today the instance id is treated as a secret you can only get by being in the call./api/game/*, for example with Vercel Firewall rules.