Build a world

A world is one JSON document. Here is the smallest valid, walkable one:

{
  "thread": "thread/0.1",
  "world": { "id": "myplace", "title": "My Place",
             "author": { "id": "did:web:example.com", "name": "You" },
             "license": "CC-BY-4.0" },
  "spawns": [ { "name": "entry", "position": [0,0,8], "yaw": 3.14159 } ],
  "prefabs": [ { "id": "60000001", "mesh": { "builtin": "plane" },
                 "material": { "base_color": [0.12,0.12,0.16,1.0], "roughness": 0.95 } } ],
  "placements": [ { "prefab": "60000001", "name": "floor",
                    "position": [0,0,0], "scale": [30,1,30] } ],
  "portals": [ { "id": "out", "position": [0,1.4,-6], "scale": [2,3,0.2],
                 "to": "thread://worlds.pixygon.io/wayshrine", "label": "A wayshrine" } ]
}
The rules that make it conformant
  • thread MUST be "thread/0.1".
  • Every world MUST declare a spawn (the arrival point).
  • Every placement MUST reference a declared prefab id.
  • A prefab mesh sets exactly one of builtin (cube/sphere/cylinder/capsule/plane/quad) or asset (a glTF asset).
  • Every portal to MUST be a valid thread:// locator — portals are the links that make this a web.
  • Unknown fields are ignored — additive changes are always safe.
  • Presence is opt-in: omit presence entirely and your world is a solo place. To let travelers meet, add "presence": { "relays": ["wss://relay.pixygon.io"] } (or run your own relay — the wire format is public).
  • World prefab ids use the StructuredId scheme (category 60 for world-local prefabs: 60000001, 60000002, …) — the reference implementation is the thread-structured-id crate; a prose spec section is in progress.

The full grammar: World Manifest v0.1 · Locators & resolution · Presence · Behavior ABI.

Publish — on your own domain, today

The standalone tier needs nobody's permission: serve your manifest at

https://<your-host>/.well-known/thread/world.json
# optionally per-path places:
https://<your-host>/.well-known/thread/<path>/world.json

…and thread://<your-host> is a live place. Any conformant browser can walk in. That escape hatch is deliberate — it is what keeps the Thread an open web rather than someone's product.

Verify — the suite is the arbiter

Conformance is decided by the public suite, not by taste. It builds standalone from the public repo (its only dependency is thread-manifest on crates.io):

git clone https://github.com/Pixygon/thread-spec
cd thread-spec
mkdir -p myworlds/myplace && cp /path/to/world.json myworlds/myplace/
cargo run --manifest-path conformance/Cargo.toml -- myworlds/   # exit 0 = ✓ CONFORMANT

And resolve any locator exactly like a browser would:

curl -s "https://api.pixygon.io/v1/thread/resolve?loc=thread://worlds.pixygon.io/wayshrine"

A note on the two tiers: the standalone tier (.well-known on your own host) is permissionless — that is the open standard. The registry tier (worlds hosted at worlds.pixygon.io) is operated by Pixygon and not yet open for public submissions. Build standalone; nothing is gated. A live standalone exemplar you can study: curl https://thread.pixygon.io/.well-known/thread/world.json — this very site is also a place.

See what exists

The public registry lists worlds Pixygon hosts: GET /v1/thread/worlds. Portal into them from your own world — a linked world is a real one; a dangling world is a page nobody links to.