Skip to content
Apps— browse docs
On this page

Step 7: Wear the world's look, then ship it

useHostTheme, and the commands that turn this page into a real, shared app.

One thing left before this is done: right now the canvas is transparent and inherits whatever the docs site's background is. A real world has its own palette, and your app should wear it — not ship a background colour that clashes with every world it's installed in.

Read the world's look with useHostTheme(), and fall back to your own when there isn't one:

const { tokens } = useHostTheme()
const bg = tokens["--background"] ?? "#151515" // mine, when nobody has an opinion

One honesty note first: to keep the theme diff readable, this pane starts from the static Step-2 board — the shared state, drag handlers, and board picker from Steps 3–6 are left out. In your real file, keep all of that and add the same three lines.

Wear the room
src/app.tsx Lines 1 and 15 to 17 highlighted.

Edit and the example re-runs. Tab indents; press Escape to leave the editor.

Running · your edits, live
Starting the example…

You should see: a little caption at the bottom-left, honestly reporting that this page has no world palette to wear — because it doesn't. Drop this same file into a real world with a theme and the caption flips to "wearing the world's palette," with no change to the code. mode (light/dark) is available the same way, for decisions a colour token can't express. Theming covers both, plus useAppCustomization() for choices you expose yourself.

Make it real

Five commands take you from this page to the real thing — Host, Surface, route, and all — running in a world with a second board in it:

vvd create letter-blocks --app --template=blocks
Expected output:
→ Creating app letter-blocks in /Users/you/dev/letter-blocks — from the Blocks template

✦  letter-blocks — a brand-new app, ready to come alive.

Next:
cd letter-blocks
vvd run    # render it live in your world — hot-reloads as you edit
vvd save   # save a new version (a private draft)
✓ Created letter-blocks (app) → /Users/you/dev/letter-blocks
cd letter-blocks && vvd run --world=test-bench
Expected output:
? Open letter-blocks in which project? › (Use arrow keys)
❯ + New — a fresh letter-blocks

✓ Created project "letter-blocks"
● live in Test Bench
 https://beta.vvd.world/worlds/test-bench/letter-blocks?dev=9f21c4   — a private tab, only you can see it

Run it again with --project, or just answer the prompt differently, and you get a second, independent board in the same world — exactly the pair from Step 5, for real:

vvd run --world=test-bench --project='second board'
Expected output:
✓ Created project "second board"
● live in Test Bench
 https://beta.vvd.world/worlds/test-bench/letter-blocks?dev=a114fe   — a private tab, only you can see it
vvd save
Expected output:
✓ Saved letter-blocks v1 — a private draft only you can see

vvd save mints a private draft — only you can see it. vvd share is what lets your world (and both campaign tables in it) actually open the app:

vvd share
Expected output:
→ Sharing with your world…

✓ Shared letter-blocks v1 with your world.

vvd create --template=blocks scaffolds the fuller version with rotate, scale, sound, and a tumble gesture — one file, src/app.tsx, everything you just built by hand plus the parts this page skipped for time. The Blocks starter kit walks through exactly what's different.

Recap

  • An app is defineApp plus Host, Surface, route, and a tools registry around an ordinary tool.
  • useCollabState(shape) needs no coordinates — the host already knows which document this mount's state lives in.
  • That document is keyed by world, app, and project — which is the entire reason two instances don't share a block.
  • useHostCapability("projects") is what vvd run's own picker is built on; your app can offer the same choice.
  • useHostTheme() returns { mode, tokens } — wear the host's token when there's one, your own design when there isn't.

Where to next