MCCF as a read-only Web of Worlds participant: design note.
Watch the MCCF demo
A short video of the Multi-Channel Coherence Field working in an X3D scene. Watch it on YouTube.
An MCCF world can take part in the Web of Worlds as a read-only provider: at export it publishes one JSON document set shaped like WoWAPI 0.0.1, plus X3D assets named by content hash. Nothing in MCCF's core changes, nothing in the WoW draft has to change, and nothing writable is exposed. A reference implementation and tests accompany this note; the open questions for the engineers are at the end.
Why this design
Each choice answers something the WoWAPI 0.0.1 specs or the Metaverse Standards Forum whitepaper ask for. Where the spec is silent, the choice says so.
| WoW requirement | What the WoW material says | MCCF design response |
|---|---|---|
| A world is one URI | Join, follow and preview are URL fragments (#join, #follow, #preview=aspect.id); persist and share mean store or send the URL | / redirects (302) to the MCCF player; browsers keep the fragment across a redirect, so the URL still carries the intent. #preview maps to the unattended performance of the scene, #join to free navigation |
| World status as data | Optional /wow/world returns a world summary: content, presence, technology, users, views, portals | Generated once at export, served as a static document. MCCF knows the label, version, duration and number of views at that moment, so nothing is computed per request |
| Assets detect change and negotiate format | HEAD plus ETag for change; content negotiation over IANA model/* types, including model/x3d+xml and model/gltf-binary | Every published asset is named by a hash of its bytes. The ETag is that hash, so a cached copy never goes stale and Cache-Control: immutable is safe. The scene stays X3D 4.0 and GLB inlines pass through unchanged |
| A spatial composition graph | Nodes carry id, label, names, localTransform, spatialAssetURI | Only authored scene content is exposed: named Transforms and Inlines. Timers, interpolators, routes and scripts are the cue machinery and stay private, so another engine could re-implement the same behaviour |
| Read and write are separate | User delete and node POST/PUT/DELETE exist, but the README lists writing nodes as optional, "if this is exposed" | No write endpoint is provided. Mutating methods answer 405 with an Allow header. Outside writes could corrupt a character's narrative state, and a static provider has nothing to write to |
| Portable, user-controlled identity | The whitepaper puts identity in the user's own manifest (DIDs, verifiable credentials); the world consumes it | MCCF stores and trusts no identity. Visitors are anonymous, /wow/user/{id} answers 404, and users counts report 0 |
| Open standards, no lock-in | The whitepaper names glTF, X3D and USD as IANA-registered, and asks for decentralisation | No MCCF-specific format. The provider can be a folder of files on any host. Extra MCCF facts sit under one x-mccf key a client can ignore |
| Versioned worlds | World.content.version is a number; the spec does not say how a link pins a version | An integer per publish, assets pinned by hash, older versions stay fetchable with ?v=N |
The shape
Publishing turns an export into plain files. The cue machinery is not described anywhere in them, and any host that can serve files can be the provider; the Flask facade only adds ETag handling, content negotiation and the 405s.
What MCCF generates
One file per version, versions/N/wow.json, holds everything the endpoints return; each endpoint serves a slice of it. The excerpt below comes from publishing the real Garden of the Goddess export, trimmed. The scene's asset files were not available in the test environment, so their bytes were stand-ins and the hashes are illustrative; the structure is exact.
{
"world": {
"content": { "label": "GardenOfTheGoddess_Scene01", "version": 1 },
"presence": { "navigation": "FLY, WALK, EXAMINE, ANY" },
"technology": { "runtime": "X3D 4.0 (X_ITE) with the MCCF cue runtime" },
"users": { "active_user_count": 0, "total_user_count": 0 },
"views": { "view_count": 2 },
"portals": { "portal_count": 1 },
"x-mccf": { "sceneAsset": "/wow/assets/GardenOfTheGoddess_Scene01-b714bf8f.x3d" }
},
"views": [{ "id": 1, "x-mccf": {
"def": "VP_Garden01", "label": "The Garden of Innana",
"localPose": { "frame": "scene-local", "units": "m", "up": "+y",
"position": [171.48, 3, 196.99], "orientation": [0, 0, 0, 0] } } }],
"portals": [{ "id": 1, "x-mccf": {
"label": "Back to the Library", "target": "https://example.org/library#preview" } }],
"nodes": { "id": 1, "label": "GardenOfTheGoddess_Scene01", "children": [
{ "id": 5, "label": "Avatar_Anna", "names": ["Avatar_Anna"], "parent": 1,
"localTransform": [1,0,0,0, 0,1,0,0, 0,0,1,0, 186.5,2.1,200.5,1],
"spatialAssetURI": "/wow/assets/Anna-c9ff85d2.x3d" } ] },
"assets": [{ "id": 16, "uri": "/wow/assets/GardenOfTheGoddess_Scene01-b714bf8f.x3d",
"mediaType": "model/x3d+xml", "etag": "\"b714bf8f...\"", "role": "scene" }]
}
The rules behind it:
- Nodes. Only Transforms named
Avatar_,PlacedAsset_,Zone_orZoneAsset_are described (the list is configurable). Anything the Composer generates for cues, such asPathTimer_EC_..., is never described. - Views. Named Viewpoints, minus the free camera and the terrain-capture camera, which are authoring tools.
- Portals. X3D
Anchornodes that link outward, plus portals listed in the publish config. Neither is in the Garden today, so the sample portal comes from config. - Ids. Integers in document order, as the spec requires. They are stable within a version only; the stable key is
names[0]. - Transforms.
localTransformis 16 numbers, column-major as in glTF. The spec does not say; see the questions.x-mccf.transformrepeats the same data as translation, rotation and scale. - Assets. The scene is itself an asset. Its
urlattributes are rewritten to hashed names, so a foreign X3D viewer resolves everything beside it without MCCF's server. - Versions. The integer rises only when the content changes; publishing the same export twice is a no-op. When the scene's XML is supplied,
content.durationis the end of the last cue.
Endpoints: what is served, what is refused
Every JSON and asset response below carries a strong ETag, answers 304 to If-None-Match, and sends Access-Control-Allow-Origin: *, which is safe because nothing is writable.
| Path | In WoWAPI 0.0.1 | MCCF behaviour |
|---|---|---|
GET / | Provisions the web app as text/html | 302 to the MCCF player. The Location has no fragment, so the browser re-applies #join, #follow or #preview |
GET /wow/world | World summary | The world object. no-cache, so a client revalidates and gets a 304 until the next publish |
GET /wow/view/{id} | View status | One view; 404 outside 1..view_count |
GET /wow/portal/{id} | Portal status | One portal; 404 outside the range |
GET /wow/spatial/{id} | Spatial composition graph | {id: 1, rootNodeID: 1} |
GET /wow/spatial/{id}/node/{nodeId} | A node and its subtree | The node with nested children |
POST, PUT, DELETE on a node | Create, update, delete nodes | 405 with Allow: GET, HEAD, OPTIONS |
GET /wow/user/{id} and DELETE | User status; delete user | GET answers 404 (no user records); DELETE answers 405 |
GET /wow/assets/{file} | Asset content, negotiated by IANA media type, HEAD and ETag for change | Bytes with the stored media type and Cache-Control: immutable. 406 if Accept excludes that type. Files of older versions stay served |
GET /wow/assets/{file}/wow/asset | Asset status | Label, media type, size, ETag, role |
any JSON path with ?v=N | not in the spec | Pins version N and marks it immutable. A bad value answers 400, an unknown version 404 |
To run it: python mccf_wow.py publish --x3d <exported.x3d> --scene-xml <scene.xml> --config publish.json --out wow_publish, then register_wow(app, "wow_publish", "<scene>", app_url=...) on a Flask app, or point any static host at the folder. 21 tests cover the publisher and the facade, including every refusal in the table.
Gaps found in WoWAPI 0.0.1
Found while mapping MCCF onto the actual API.yaml files. Each has a stopgap in the sample, marked x-mccf where it adds fields.
| Gap | Where | Effect on MCCF | Stopgap |
|---|---|---|---|
| Two path sets for the same graph | OpenSpatialWorld README says /wow/scene/ and /wow/scene/node; API.yaml says /wow/spatial/{id} and /wow/spatial/{id}/node/{nodeId} | A client may probe either | Follow API.yaml |
| Placement is geographic only | geoPose on World, User, View, Portal, Spatial, Asset; the longitude field is spelled lan | A local Cartesian world (the Garden's header says Grid: 500mx500m) cannot say where a view or portal is | x-mccf.localPose with frame, units and up axis |
View and Portal have only id and geoPose | components/schemas | No label, no destination world, no entry view | x-mccf.label, target, entry |
localTransform has no convention | Node schema: array of numbers | A reader cannot know length or order | 16 numbers, column-major; x-mccf.transform repeats it |
| Node paths omit a declared parameter | POST, GET, PUT on .../node/{nodeId} do not declare spatialID; DELETE declares nodeid for {nodeId} | A generated client or validator will reject the file | Not needed: MCCF serves GET only |
| Nothing is required | No required lists; world.schema.json has empty properties | A conformance test cannot fail, so "conformant" cannot be shown | Claim only "shape-compatible" |
| Version has no stated meaning | World.content.version is a number; assets use HTTP ETag | A link cannot say which version it means | Integer per publish, ?v=N, assets by hash |
Questions for the engineers
- Static provider. Is a world whose
/wow/*documents are pre-generated and immutable, with every write operation answering 405, an acceptable provider? Or must the node write operations exist? - Local frames. For a world with no geographic anchor, should
geoPosebecome optional with a local-pose alternative in the schema, or is a namespaced extension likex-mccf.localPosethe intended route? - Portal destination. Where does a portal's target world URI and entry view belong? Today the schema cannot express either.
- `localTransform`. What are the length and order? We assumed 16 numbers, column-major.
- Asset base. Is the asset's base URL the file URL itself, with
/wow/assetappended? We chose that so relativeurlattributes inside the X3D keep resolving. - Fragments. May
#previewrun with no session, and may a world define what it shows? We map it to an unattended performance of the scene. - Counts without tracking. A world that keeps no visitor records: should
usersreport 0, or be omitted?
Sources
Pages opened for this note, as of 2026-10-07. The WoWAPI files were read from a local clone of the repository (version 0.0.1 of each API).

Comments
Post a Comment