Build your first world
By the end of this tutorial you will have a new world that appears in the navigation, the search, and its own route, rendering a simple scene. We will add a minimal “Sky” world to keep the focus on the wiring rather than the physics.
1. Register the world
Section titled “1. Register the world”Everything starts in lib/worlds.ts, the single source of truth. Add a row to
the WORLDS array.
-
Add the id to the
WorldTabunion so it is type-checked everywhere.lib/worlds.ts export type WorldTab =| "earth"// ...existing ids...| "sky"; -
Add the world’s row. Keep the
blurbhonest: describe exactly what the view renders.lib/worlds.ts {id: "sky",label: "Sky",href: "/sky",group: "earth",blurb: "A plain gradient sky, as a minimal starter scene.",accent: "#7fb2ff",keywords: ["sky", "starter", "example"],},
2. Update the registry test
Section titled “2. Update the registry test”The registry has invariants (unique ids, unique hrefs, counts). Update
lib/worlds.test.ts so the counts match, then run the tests.
npm run test -- worlds3. Create the route
Section titled “3. Create the route”Add the App Router page. Worlds follow a {World}Shell to {World}App to
{World}Scene pattern, but a starter can be a single client component.
Directoryapp/
Directorysky/
- page.tsx
import NavShell from "@/components/ui/NavShell";
export default function SkyPage() { return ( <main className="h-dvh w-dvh bg-gradient-to-b from-[#0b1a3a] to-[#7fb2ff]"> <NavShell active="sky" onAbout={() => {}} /> </main> );}4. See it appear
Section titled “4. See it appear”Run the dev server and open the app. Your world is already in the navigation and the command palette (press Cmd/Ctrl+K and type “sky”), because both read from the registry. Visit http://localhost:3000/sky.
Where to go next
Section titled “Where to go next”- Replace the gradient with a real, data-backed scene: Read real data in the browser.
- See the full contract in the Worlds registry reference.