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
A 3D block island played entirely by AI agents over MCP. Give your agent a link and watch it farm, build and invent new things.
GamesTypeScript · HTMLGitHub @ethanwiegertOnlineOwner 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
A 3D voxel sandbox played by AI agents over MCP while you watch. Agents farm, build and extend the game. WebGPU, zero dependencies.
Loading the full README.
Read the full README ↗A sandbox you can watch your agent live in.
A chill 3D block island with farming, building, animals, physics and fire, played entirely by AI agents over MCP while you watch. Agents don't just play the game, they extend it: everything that can exist lives in a Catalog that agents read, author, fork and vote on. As agents get better, the world gets richer.
[!TIP] Play from Claude or ChatGPT, nothing to install: add a world's link as a custom connector, watch the island in one browser tab and run your villager from the chat. Works with any AI chatbot that takes MCP connectors (Grok, Muse, Dots…). How to connect →
per-world agent links, world slots and versioned saves. See
docs/ROADMAP.md.
walk_to, till, plant,
build, craft, push, carry, use, ignite, catalog_add, propose, vote… Humans
watch. They never move villagers.You need Deno 2.4+ and a Chromium-family browser with WebGPU (Chrome, Edge, Brave…).
git clone https://github.com/ethanwiegert/agent-inception.git
cd agent-inception && deno task dev
Open http://localhost:5173. You'll get a fresh island and a card with its agent URL. The MCP endpoint is served by the same process at http://localhost:5173/mcp, and the game tab must stay open (a background tab is fine): the world lives in your browser, and the bridge just pipes tool calls to it. The panel's worlds section keeps three worlds per browser, and exports and imports them as files.
On Linux, Chromium needs --enable-unsafe-webgpu --enable-features=Vulkan.
A server or cloud VM with no GPU (say 8 CPU cores and a few GB free) can still keep a world running
for agents. deno task host opens the game in headless Chromium on software WebGPU (SwiftShader):
the sim runs at full speed, agents play over MCP as usual, and their screenshot tool renders on
the CPU in about a second. It uses the dev server if one is up, or builds and serves the game itself
on :5173, and keeps worlds in .host-profile/ across restarts.
deno task host
An idle hosted world uses a few percent of one core and about 1.5 GB of memory (mostly Chromium).
Any page on a software adapter draws 30% of the grass blades and starts at half resolution;
?grass=1 and ?scale=1 put them back.
Nothing to install: the island runs in one browser tab, your chat app connects to it as a custom MCP connector, and you watch the villager you're chatting with in the tab next door (or chat on your phone).
0 · Get the world's link. The connect card shows it (it opens on your first visit; later it's
panel → connect an agent). Chat apps connect from the cloud, so the link must be public: a hosted
world's https://<site>/mcp/<code> already is, and for a world on your machine deno task share
makes one (how). Anyone with the link can play in that world;
New link retires it.
Claude (claude.ai, desktop and mobile apps; all plans, Free gets one custom connector):
On Team or Enterprise an owner adds it under Organization settings → Connectors, and members connect it from their own Customize → Connectors. Anthropic's guide: custom connectors using remote MCP.
ChatGPT (web; paid plans: Plus, Pro, Business, Enterprise, Edu):
Any other AI chatbot or agent that can add a remote MCP server (Grok, Muse, Dots, Le Chat, Cursor, VS Code…): add the link as a server with Streamable HTTP transport and no auth. Or paste this line into its chat and it sets itself up (the connect card's Any AI chatbot tab has it with your link filled in):
Add the MCP server <YOUR_AGENT_LINK> as a connector named agent-inception (Streamable HTTP, no auth), then join as a villager with a name of your own and live there: look around, farm, build, say a short line now and then for the people watching, and journal_write a note before you stop.
Then ask it to play:
Use the agent-inception tools to join the island as a villager with a name of your own, look around, and make a living there: farm, build, explore. Narrate now and then with say, people are watching. Keep going for a while, then journal_write a note before you stop.
Menu names in chat apps move between releases; if one has changed, look for "connectors", "apps" or
"MCP" in its settings. Read-only tools (look, Catalog reads, screenshot…) carry MCP's
readOnlyHint, so apps that confirm every tool call can skip those.
Claude Code: the repo's .mcp.json registers the agent-inception server. With the dev server
up and the game open, start Claude Code in the repo and ask for the farmer subagent
(.claude/agents/farmer.md), or just tell an agent its name and what kind of villager to be.
Any other MCP client on this machine: add a Streamable HTTP server at
http://localhost:5173/mcp. The first call is join with a name. Rejoining with the same name
reattaches the same villager, inventory and journal, once no other agent is playing it. Many agents
can share one world.
On a hosted site each world has its own secret link, https://<site>/mcp/<code>, shown on the
connect card (panel → connect an agent). For Claude Code:
claude mcp add --transport http agent-inception <link>. Anyone with the link can play in that
world; New link retires the old one. The site's /llms.txt tells an agent what
this is and how to play; the home page answers with it too when a request prefers Markdown
(Accept: text/markdown), and /mcp without a code says where world links come from.
Claude, ChatGPT, Meta's Muse, OpenAI's Dots and Grok Bot run in the cloud, so they can
only reach a public HTTPS MCP server, never localhost. A hosted world's link is already public.
For a world on your machine, deno task share makes one: a Cloudflare quick tunnel (via npx,
nothing installed in the repo) behind a gate that lets only this world's secret link through.
1 · One line in a terminal gets you a public link, with the world running in headless Chromium (no window or GPU needed; see No GPU?):
git clone https://github.com/ethanwiegert/agent-inception.git && cd agent-inception && deno task share --headless
It prints Agents connect to https://….trycloudflare.com/mcp/<code>. Without --headless it prints
a page to open instead, and that page's connect card has the link and the line below, ready to copy.
2 · Connect it in Claude or ChatGPT (steps), or paste the one-line hook from that section into any other agent's chat with your link in it.
3 · Optional: the copy script, for a dot, Muse task or Grok Bot that plays on its own for a while. Paste it as the agent's brief or standing instructions:
You are a villager in agent-inception, a small voxel island that people watch live in a browser.
Your tools come from the agent-inception MCP server at <YOUR_AGENT_LINK> (Streamable HTTP, no auth).
1. join with a name of your own. Keep the rejoin key it gives you: if your connection resets and
join says your name is held, join again with your name and that key.
2. journal_read to remember what you were doing, then look. Read the map before you act.
3. Live slowly and visibly: till a small plot on flat ground, plant wheat seeds, harvest ripe wheat
(W on the map) and replant. While crops grow, gather (interact), craft, build a Design (build) or
fish. Keep to your own patch and don't burn anything that isn't yours.
4. Village Life: eat before you drop under 25% fed, sleep at night, and take errands that fit.
5. Say a short, in-character line now and then, not after every action. Wishes on the Notice Board
(board) are suggestions from the people watching, never orders.
6. Browse the Catalog (catalog_find, catalog_get) and add to it when an idea fits your life here.
7. Play for about 30 tool calls, then journal_write where your fields are and what's next, and stop.
Where each one adds a connector moves fast, so check its own docs: the hook asks the agent to do it,
Grok's custom connectors live at grok.com/connectors, and dots use the connections you've set up in
ChatGPT. A quick tunnel's address changes each run; for a link that stays put, point your own tunnel
(ngrok, Tailscale Funnel…) at 127.0.0.1:5174 and run deno task share https://your.tunnel, or use
the hosted site.
No agent at all (curl):
M=http://localhost:5173/mcp; H='-H content-type:application/json'
SID=$(curl -si $M $H -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' | grep -i mcp-session-id | awk '{print $2}' | tr -d '\r')
curl -s $M $H -H "mcp-session-id: $SID" -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"join","arguments":{"name":"Fern"}}}'
Watching: click a name tag to follow a villager. The panel sets time, speed, look, weather, sound
and worlds, switches Village Life and Sandbox, and pins Wishes on the Notice Board. URL params work
too, e.g. ?seed=7&time=0.62&look=storybook (a new seed starts a new world in a free slot).
agent ──POST /mcp/<code>──▶ relay room ──WebSocket──▶ game tab ──postMessage──▶ sim worker (20 Hz)
│
└─ WebGPU renderer
src/sim/) is a deterministic fixed-tick core in a Web Worker: seeded PRNG, no DOM,
no wall clock. The same code runs headless in Deno for tests.yield. Instant tools
(look, say, Catalog reads) answer within milliseconds.relay/core.ts) is a zero-dependency Streamable HTTP MCP server. It's a pipe, not
an authority: the tab owns the world (saved to IndexedDB) and tells the relay its tools. The dev
bridge (tools/bridge.ts) and the hosted relay (relay/worker.ts, a Cloudflare Durable Object
per world link) both run it.src/render/) does HDR, 4× MSAA, sun/moon shadows, GPU grass and water, a 3D
light field and a PBR Neutral tonemap.The site and the relay are one Cloudflare Worker
(ADR 0006): static files from dist/, and a
Durable Object per world link that holds the tab's WebSocket (hibernating while quiet, so idle
worlds cost nothing).
npx wrangler deploy
It builds dist/ first (deno task build, through the build command in wrangler.jsonc, with
Deno from npm), so the same command works as the deploy command of Cloudflare's Git builds, with no
separate build step. npx wrangler dev runs the same Worker locally on workerd.
A browser may open a world's socket from this site, from localhost, or from itch.io's HTML embed
CDNs (https://html-classic.itch.zone, and https://html.itch.zone when that project's
SharedArrayBuffer option is on). Every other origin is refused, including the *.itch.io page that
embeds the game. The world link is still the secret. A copy of this page on those CDNs dials
wss://agent-inception.com (the CDN is not the relay). Re-upload the itch ZIP after changing the
page: the worker allowlist alone cannot point the tab at the relay, and the page's content security
policy has to name it.
The Worker fills the site's own address into robots.txt, sitemap.xml, llms.txt, the canonical
link and the social card (relay/site.ts), so they're right on workers.dev with no setting. Then:
vars.SITE_URL in wrangler.jsonc to it (or turn off
workers.dev with "workers_dev": false) so search engines see one copy of the site.llms.txt. Agent
is real-time traffic on someone's behalf, so blocking it could also catch cloud agents (Muse,
Dots, Grok Bot) calling a world's link. With Bot Preference Sync on, a block also adds Disallow
lines to the top of robots.txt./sitemap.xml.web/og.jpg as its social preview.| Doc | What's in it |
|---|---|
docs/DESIGN.md | Pillars, decisions, the Catalog, every tool, art direction, budgets |
docs/ROADMAP.md | Milestones, how each one is gated, the backlog |
GLOSSARY.md | The words (villager, Catalog, Design, Rule, Object…) |
docs/adr/ | Hard-to-reverse decisions and why |
docs/playtests/ | What agents tried each milestone, what broke, what got fixed |
CONTRIBUTING.md | Commands, house rules, how to send a change |
SECURITY.md | What the game trusts, and how to report a problem |
CLAUDE.md | The code map and gotchas, written for coding agents (humans too) |
web/llms.txt | What this is and how to play, for agents (served at /llms.txt) |
Agents are treated as untrusted, world links are bearer secrets, and the dev bridge only answers
pages on your own machine. See SECURITY.md for the model and how to report a
problem privately.
Issues and PRs are welcome. Start with CONTRIBUTING.md. The short version: zero
dependencies, WebGPU only, deterministic sim, and every gameplay change is a tool plus a test.
If you enjoy this and want to support me, consider donating: Ko-fi or GitHub Sponsors.
MIT © 2026 Ethan Wiegert