Inspiration

I'm a lifelong learner, and I've always loved the idea of studying new topics with tech. Over the last few years I've tried just about every way there is to learn with AI.

The seed for this project goes back further than the challenge. Years ago I bought the domain studytree.ai (I'm a bit of a domain freak) and it's been rattling around in my head ever since. The original concept was a way to organize your ChatGPT history: a folder system with interconnected nodes so you could go back and actually study what you'd learned in conversation. The problem was keeping that data in sync, so I could never make it seamless. (err proprietary systems)

So I pivoted toward a pure studying tool, but I never quite knew what it wanted to be. I even tried wiring in backend MCP servers to prototype it. It wasn't until WebMCP came out that I saw the real unlock: the agent could live inside the page and act through tools the page exposes, no backend required. That's what turned a vague study tool into a game you play with an AI. I mean I had experimented with somewhat of a complex node system here https://app.studytree.ai but I never was truly satisfied.

What it does

StudyTree is a turn-based learning game on a shared canvas. A human and an AI agent take turns building a knowledge tree around a single learning question.

  • The human clicks and types.
  • The agent can only change the board by calling registered tools. Voice is the agent's controller.

Node types: ๐ŸŒฑ Root (the learning question) ยท ๐Ÿ’ก Concept ยท ๐Ÿ“š Resource ยท โšก Skill ยท โ“ Gap

Moves: Plant, Branch, Prune, Mark Gap, Mark Clear, and a human-only Undo of the agent's last move.

Rules: 10 moves total, alternating turns. Win with 5+ nodes and zero gaps remaining when the moves run out. Lose if gaps are still open.

The game works through two agent surfaces, and both go through the same six tools:

  • WebMCP an in-browser agent (like ChatGPT's built-in browser) calls tools registered on document.modelContext.
  • ElevenLabs voice an on-canvas voice panel connects to a public ElevenLabs agent that invokes the same moves as client tools.

get_board is read-only and free; the other five are the legal moves. Tool arguments accept a node's label as well as its id, so a voice agent can say "branch from First Principles" instead of spelling out n3.

How I built it

The build was almost entirely agent-driven, in stages:

  1. Voice dump. I started by talking the idea out loud with a Grok voice bot and let it spit the concept back to me.
  2. Cloud agent scaffold. That spec went into a Cursor Cloud agent, which spun up the first version. I pulled it down and tested it on a local port inside the Codex browser.
  3. Refinement. I brought in Claude Opus 5 to refine the architecture and tighten the tool layer.
  4. Redesign. When Claude 5.1 dropped yesterday, I had it re-evaluate the whole design. I pulled visual references from Cosmos for inspiration and had it pick apart the game mechanics. That's where it evolved from "a tree you build" into a real turn-based pairing between human and agent.

Stack: Vite ยท React 19 ยท TypeScript ยท React Flow (canvas) ยท Zustand (state)

Architecture: there is exactly one implementation of each move, in the Zustand store. Three entry points reach it:

human buttons  โ”€โ”€โ”
WebMCP tools   โ”€โ”€โ”ผโ”€โ”€โ†’ applyMove() โ”€โ”€โ†’ store action โ”€โ”€โ†’ React re-render
voice tools    โ”€โ”€โ”˜

Neither agent surface can touch the DOM or skip a rule, because both call the identical store actions the human's buttons call. Adding a move means adding it once in moves.ts, and both surfaces pick it up. WebMCP registration is feature-detected, so nothing breaks in browsers without it, and the ElevenLabs SDK is code-split so the board is interactive before the voice stack loads.

Challenges I ran into

Getting the agent to take its turn on its own. Right now the agent moves when you prompt it. I want true back-and-forth: I make a move, and the agent immediately responds without me nudging it. I don't think I've solved this yet. My current thinking is a polling or event loop that watches get_board and triggers the agent when the turn flips.

Keeping the agent honest. The agent needed real agency without being able to cheat. Routing every move through the same applyMove dispatcher the human uses, and giving the human an undo, was how I solved that.

Accomplishments that I'm proud of

  • Two completely different agent surfaces (WebMCP and ElevenLabs voice) driving one shared rule set, with zero duplicated game logic.
  • No API keys, no backend, fully static deploy. The whole thing runs in the browser.
  • A concept I've been circling for years finally has a shape I can actually play.

What I learned

  • WebMCP is far more powerful than I expected. Exposing a handful of well-defined tools on the page is enough to turn a static app into something an agent can genuinely collaborate in.
  • The Codex browser is going to change how people use the internet. Once the general public starts adopting agent-driven browsers, the interactions are going to get profound.
  • Voice-first, agent-first workflows (talk the idea out, let cloud agents scaffold it, iterate with frontier models) are a real way to build now, not a gimmick.

What's next for StudyTree

  • Autonomous turn-taking. Finish the polling/event system so the agent moves the instant the human does. Real back-and-forth, no prompting.
  • Fold it into StudyTree. Finished trees persist as study maps, resource nodes become live links, and the 10-move game becomes the on-ramp to a longer learning session. This is the studytree.ai vision I've been sitting on, finally with a front door.
  • Classroom mode. Make this fun for younger students: a whole class builds one tree together with the agent as a co-player, taking turns to plant concepts, spot gaps, and fill them. The game format already has the ingredients (a shared board, clear turns, a win condition) to turn "what do we know about this topic?" into something kids actually want to play.

Built With

  • 11labs
  • react
  • react-flow
  • vercel
  • vite
  • zustand
Share this project:

Updates