Skip to content
Get started— browse docs
On this page

Step 9: Run it for real

The exact file vvd create writes — and the three commands that put it in a world with real people in it.

One thing left, and it's not a step so much as a confession: every string you typed — "Add a note", "Write something…" — should live in a words file, not in your JSX. The host decides which language a reader is in; your tool can only follow along if its words are data, not literals — and then translating bestiary later is a find-and-replace instead of a rewrite.

The words live in a third file, src/locales/en.json:

src/locales/en.json (excerpt)
{ "board": { "add": "Add a note" }, "note": { "placeholder": "Write something…" } }

…and src/tool.tsx reads them through a translator instead of hardcoding them:

src/tool.tsx
import en from "@/locales/en.json"

const t = useT() // reads src/locales/en.json through the host's chosen language
<button onClick={addNote}>{t("board.add")}</button>

That's it — same idea as everywhere else in vvd, applied to the words you just wrote by hand. (@vvd/sdk also exports useT and useHostLocale ready-made — the scaffold hand-rolls a minimal translator instead, so you can see the mechanism it wraps.)

The whole thing

This is not a step to complete. It's src/codec.ts and src/tool.tsx, exactly as vvd create bestiary --tool writes them — the same file you've been building toward since Step 2, words file included. Still editable, if you want to keep poking at it.

In your real project this is three files — src/codec.ts, src/locales/en.json, and src/tool.tsx — and the // src/codec.ts / // src/tool.tsx comment lines in the pane mark exactly where each begins. When you run it for real and something breaks, that comment tells you which file to open: shape and fields → src/codec.ts; UI text → src/locales/en.json; everything else → src/tool.tsx. The glue also absorbs src/codec.ts's own import { defineStateCodec, field } from "@vvd/sdk" line and its trailing export default codec — your real codec.ts keeps both.

bestiary, complete
src/codec.ts + src/tool.tsx

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

Running · your edits, live
Starting the example…

Make it real

Three commands take you from this page to that same file, running in a world with a second person in it for real:

vvd create bestiary --tool
Expected output:
→ Creating tool bestiary in /Users/you/dev/bestiary — from the Hello World template

✦  ah — a bestiary tool. let's build it.

Next:
cd bestiary
vvd run    # render it live in your world — hot-reloads as you edit
vvd save   # save a new version (a private draft)
✓ Created bestiary (tool) → /Users/you/dev/bestiary
cd bestiary && vvd run --world=test-bench
Expected output:
  ● live in Test Bench
 https://beta.vvd.world/worlds/test-bench?dev=9f21c4   — a private tab, only you can see it

You should see: your browser opens on that URL, and it's the tool you just built — same fields, same ReferencePicker, same right-click menu, now backed by a real world instead of this frame. The Step 8 search that came back empty here finds your actual cards there.

vvd save
Expected output:
✓ Saved bestiary v1 — a private draft only you can see

One thing that will bite if you skip it: these commands need a signed-in CLI. Run them signed out and every one fails with «Not signed in. Run vvd login --token <code> — get your code at https://beta.vvd.world → Workshop → Developer.» — do exactly that, and Authentication covers getting signed in end to end.

Recap

  • src/codec.ts declares the shape; src/tool.tsx reads and renders it — nothing else is required.
  • field.map merges concurrent writes by key, which is why Step 6 needed no sync code at all.
  • useDocumentPresence and the platform's own cursor are two different things, and you only wrote one of them.
  • useHostCapability("search"), useDocDropTarget, and useContextMenu are how a tool joins the rest of vvd instead of living beside it.
  • vvd create bestiary --tool scaffolds exactly the file above — the Hello World template is the default for a tool (--template=hello names it explicitly). You already know every line of it.

Where to next

You built one of these from nothing. Here are eight more, ready to run — pick one closer to what you actually want to make, and skip everything you just did by hand.