Skip to content
Apps— browse docs
On this page

Step 1: What you're building

A pile of wooden letter blocks, shared live — then two separate boards that don't touch each other's blocks.

Let's say you're making a world where you're running two campaigns at once — The Salt Road and Winterhold — and you needed a tabletop toy each table could fidget with mid-session, without one table's blocks getting shoved around by the other's. Here's how you build that.

Here's the finished thing. Drag a block. Grab a handle to rotate or scale it. Tap one to tumble it to a new face:

Blocks, running (the toy, without the app shell)
Starting the example…

Drag the letters around. Their positions are shared state, so a second person sees your blocks move. The clacking sound needs the platform's audio engine, which a docs page doesn't run.

That's real — every block's position is shared state, the same as everything else you've built on this site. What it doesn't show you yet is the part this page is actually about: open it once for The Salt Road and once for Winterhold, and you get two boards, one per table, not one board both campaigns are fighting over.

That's the new idea. An app doesn't run once per world — it runs once per project, and a project is a real, running instance of your app: its own board, its own name, reading the same world everything else reads.

You will learn

  • Why an app runs once per project instead of once per world
  • How vvd run asks which instance to open — and how your app can ask the same question
  • useCollabState, the hook that gives your app a shared document with no coordinates to pass
  • How to read the world's look instead of shipping your own, hardcoded one

The version you're building here

The kit above is the polished one — rotate, scale, a tumble sound. This page builds a smaller version of the same idea by hand, one edit at a time, so you see exactly where the "multiple instances" part comes from rather than finding it already wired up. By the end you'll have two of these, side by side, proving neither one knows the other exists:

Where you're headed
src/app.tsx, running
Starting the example…

Drag a letter. Nothing is faked — useCollabState is the same shared-document machinery every tool on this site runs on, and you'll build this exact file by hand starting at Step 2.

Note:

Why the running example is a tool, not the app

The examples on this site mount a tool against a fake host, in your browser. An app provides a host and owns a route — it needs the real shell, which is what vvd run gives you. What you can honestly show here is the app's screen, which is a tool like any other. Apps covers the difference if you haven't met it yet.