From a65d8a4f7939068a13451c21cf3cdb5543107cb6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:06:25 +0000 Subject: [PATCH] Update gh-pages to output generated at aab8841 --- .github/dependabot.yml | 7 + .github/workflows/ci.yml | 24 +++ .github/workflows/deploy.yml | 34 ++++ CNAME | 1 + LICENSE-APACHE | 176 +++++++++++++++++++ LICENSE-MIT | 21 +++ README.md | 28 +++ _config.yml | 3 + social/README.md | 59 +++++++ social/dwn/protocols/world-host.json | 52 ++++++ social/dwn/schemas/home.json | 21 +++ social/dwn/schemas/host-info.json | 22 +++ social/dwn/schemas/world.json | 22 +++ spatial/README.md | 44 +++++ spatial/capnp/datagram.capnp | 25 +++ spatial/capnp/world_server.capnp | 39 ++++ spatial/wit/wired-dwn/world.wit | 68 +++++++ spatial/wit/wired-input/deps/wired-math | 1 + spatial/wit/wired-input/types.wit | 61 +++++++ spatial/wit/wired-input/world.wit | 18 ++ spatial/wit/wired-log/world.wit | 16 ++ spatial/wit/wired-math/world.wit | 37 ++++ spatial/wit/wired-physics/deps/wired-math | 1 + spatial/wit/wired-physics/world.wit | 43 +++++ spatial/wit/wired-player/deps/wired-input | 1 + spatial/wit/wired-player/deps/wired-math | 1 + spatial/wit/wired-player/deps/wired-physics | 1 + spatial/wit/wired-player/deps/wired-scene | 1 + spatial/wit/wired-player/world.wit | 44 +++++ spatial/wit/wired-prelude/deps/wired-input | 1 + spatial/wit/wired-prelude/deps/wired-log | 1 + spatial/wit/wired-prelude/deps/wired-math | 1 + spatial/wit/wired-prelude/deps/wired-physics | 1 + spatial/wit/wired-prelude/deps/wired-player | 1 + spatial/wit/wired-prelude/deps/wired-scene | 1 + spatial/wit/wired-prelude/world.wit | 16 ++ spatial/wit/wired-scene/deps/wired-input | 1 + spatial/wit/wired-scene/deps/wired-math | 1 + spatial/wit/wired-scene/deps/wired-physics | 1 + spatial/wit/wired-scene/gltf.wit | 149 ++++++++++++++++ spatial/wit/wired-scene/glxf.wit | 108 ++++++++++++ spatial/wit/wired-scene/world.wit | 6 + spatial/wit/wired-script/world.wit | 13 ++ v0/protocols/world-host.json | 52 ++++++ v0/schemas/home.json | 21 +++ v0/schemas/host-info.json | 22 +++ v0/schemas/world.json | 22 +++ 47 files changed, 1289 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/deploy.yml create mode 100644 CNAME create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 _config.yml create mode 100644 social/README.md create mode 100644 social/dwn/protocols/world-host.json create mode 100644 social/dwn/schemas/home.json create mode 100644 social/dwn/schemas/host-info.json create mode 100644 social/dwn/schemas/world.json create mode 100644 spatial/README.md create mode 100644 spatial/capnp/datagram.capnp create mode 100644 spatial/capnp/world_server.capnp create mode 100644 spatial/wit/wired-dwn/world.wit create mode 120000 spatial/wit/wired-input/deps/wired-math create mode 100644 spatial/wit/wired-input/types.wit create mode 100644 spatial/wit/wired-input/world.wit create mode 100644 spatial/wit/wired-log/world.wit create mode 100644 spatial/wit/wired-math/world.wit create mode 120000 spatial/wit/wired-physics/deps/wired-math create mode 100644 spatial/wit/wired-physics/world.wit create mode 120000 spatial/wit/wired-player/deps/wired-input create mode 120000 spatial/wit/wired-player/deps/wired-math create mode 120000 spatial/wit/wired-player/deps/wired-physics create mode 120000 spatial/wit/wired-player/deps/wired-scene create mode 100644 spatial/wit/wired-player/world.wit create mode 120000 spatial/wit/wired-prelude/deps/wired-input create mode 120000 spatial/wit/wired-prelude/deps/wired-log create mode 120000 spatial/wit/wired-prelude/deps/wired-math create mode 120000 spatial/wit/wired-prelude/deps/wired-physics create mode 120000 spatial/wit/wired-prelude/deps/wired-player create mode 120000 spatial/wit/wired-prelude/deps/wired-scene create mode 100644 spatial/wit/wired-prelude/world.wit create mode 120000 spatial/wit/wired-scene/deps/wired-input create mode 120000 spatial/wit/wired-scene/deps/wired-math create mode 120000 spatial/wit/wired-scene/deps/wired-physics create mode 100644 spatial/wit/wired-scene/gltf.wit create mode 100644 spatial/wit/wired-scene/glxf.wit create mode 100644 spatial/wit/wired-scene/world.wit create mode 100644 spatial/wit/wired-script/world.wit create mode 100644 v0/protocols/world-host.json create mode 100644 v0/schemas/home.json create mode 100644 v0/schemas/host-info.json create mode 100644 v0/schemas/world.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..718572b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 + +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c91cf3c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + + - uses: creyD/prettier_action@v4.3 + with: + prettier_options: --write . + + - uses: EndBug/add-and-commit@v9 + with: + message: "chore: lint" + default_author: github_actions diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..ffeffcd --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,34 @@ +name: Deploy + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: | + mkdir -p out + cp -r social/dwn/protocols out/protocols + cp -r social/dwn/schemas out/schemas + - uses: s0/git-publish-subdir-action@develop + env: + BRANCH: gh-pages + COMMIT_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com + COMMIT_NAME: github-actions[bot] + FOLDER: out + GITHUB_TOKEN: ${{ github.token }} + REPO: self + SQUASH_HISTORY: true + TARGET_DIR: v0 diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..4ef3a35 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +wired-protocol.org diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..d9a10c0 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..3188970 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 UNAVI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..eeea0df --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# The Wired + +The Wired is an open protocol for the metaverse. It is a collection of open +standards focused on interactive 3D environments, self-sovereign identity, and +seamless interoperability. + +## Protocol + +- [Social](./social) +- [Spatial](./spatial) + +## Motivation + +Today's VR ecosystem is fragmented by proprietary platforms that confine users +and developers to isolated, controlled environments. Each platform enforces its +own set of rules and restrictions, often under leadership that makes arbitrary +decisions with no recourse for the people who live within the virtual spaces +they govern[^1]. + +With VR our digital rights matter more than ever. The Wired acknowledges this +importance by fostering a decentralized environment where anyone can contribute +and shape the future of the metaverse. + +By embracing open source principles, The Wired doesn't just safeguard against +abuse; it unleashes a wave of creativity and collaboration not possible within +walled gardens. + +[^1]: (https://www.ign.com/articles/vrchat-bans-mods-community-angry) diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..10f50fb --- /dev/null +++ b/_config.yml @@ -0,0 +1,3 @@ +remote_theme: pages-themes/cayman@v0.2.0 +plugins: + - jekyll-remote-theme diff --git a/social/README.md b/social/README.md new file mode 100644 index 0000000..0c5ad0b --- /dev/null +++ b/social/README.md @@ -0,0 +1,59 @@ +# Social Protocol + +The Wired's social protocol provides an application-agnostic self-hostable base +layer for user identity and data storage. + +## Identity + +[Decentralized Identifiers](https://en.wikipedia.org/wiki/Decentralized_identifier) +(DIDs) provide a globally unique namespace for users within The Wired. + +DIDs are a generic format for addressing content that can be extended to support +any protocol. For example, [`did:web`](https://w3c-ccg.github.io/did-method-web/) +can be used to address content using a traditional web URL, while +[`did:ipid`](https://did-ipid.github.io/ipid-did-method/) can be used to address +content over [IPFS](https://docs.ipfs.tech/). + +Each DID resolves to a JSON document containing information such as the user's +name, cryptographic keys that can be used to verify their identity, servers to +contact them at, and anything else they want to store. + +### DID Host + +A DID host is a server that remotely hosts a DID and provides convenient access +to it. For example, the server may use a method like `did:web` and host your DID +document at a web domain. + +You could then log in to the server with a typical login method - such as a +username and password or OAuth connection - then receive session keys which can +be used to verify your ownership of the hosted DID to other parties. This allows +you to use DIDs with the convienance of traditional app logins. + +Running your own DID host server is a great first step towards self-sovereignity +within The Wired. + +## Data + +[Decentralized Web Nodes](https://identity.foundation/decentralized-web-node/spec/) +(DWNs) are the data layer of The Wired. DWNs build upon DIDs to store user data +and provide an API for others to interact with it. These interactions could be a +simple read to view data hosted by the user, or more complex writes to add +comments or send encrypted messages. + +DWNs are built using +[CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)s that +sync their data with other DWNs. This allows you to, for example, make use of a +public cloud-hosted DWN, while at the same time running your own local DWN to +keep a backup of your data. + +## Moderation + +**The Wired is decentralized.** + +There is no central registry of users - a user cannot be "banned" from The Wired. +Same with any content within The Wired - files can be hosted and shared by anyone. +That's just the internet. + +However specific services (websites, worlds, APIs) can and WILL moderate as +necessary - but like the Web, users will always have the option of moving to a +different service they are not banned from (or running their own). diff --git a/social/dwn/protocols/world-host.json b/social/dwn/protocols/world-host.json new file mode 100644 index 0000000..b8c74c2 --- /dev/null +++ b/social/dwn/protocols/world-host.json @@ -0,0 +1,52 @@ +{ + "protocol": "https://wired-protocol.org/v0/protocols/world-host.json", + "published": true, + "types": { + "connect-url": { + "dataFormat": ["text/plain"] + }, + "host-info": { + "schema": "https://wired-protocol.org/v0/schemas/host-info.json", + "dataFormat": ["application/json"] + }, + "world": { + "schema": "https://wired-protocol.org/v0/schemas/world.json", + "dataFormat": ["application/json"] + } + }, + "structure": { + "connect-url": { + "$actions": [ + { + "who": "anyone", + "can": ["read"] + }, + { + "who": "recipient", + "can": ["write"] + } + ] + }, + "world": { + "$actions": [ + { + "who": "anyone", + "can": ["read", "write"] + } + ], + "host-info": { + "$actions": [ + { + "who": "anyone", + "can": ["read"] + }, + { + "who": "recipient", + "of": "world", + "can": ["write"] + } + ] + } + } + } +} diff --git a/social/dwn/schemas/home.json b/social/dwn/schemas/home.json new file mode 100644 index 0000000..bc019e9 --- /dev/null +++ b/social/dwn/schemas/home.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://wired-protocol.org/v0/schemas/home.json", + "type": "object", + "description": "Defines a user's home world.", + "properties": { + "world": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "record_id": { + "type": "string" + } + }, + "required": ["did", "record_id"] + } + }, + "required": ["world"] +} diff --git a/social/dwn/schemas/host-info.json b/social/dwn/schemas/host-info.json new file mode 100644 index 0000000..d6ed6a6 --- /dev/null +++ b/social/dwn/schemas/host-info.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://wired-protocol.org/v0/schemas/host-info.json", + "type": "object", + "properties": { + "active": { + "description": "Whether the world is currently being hosted.", + "type": "boolean" + }, + "numPlayers": { + "description": "The number of currently connected players.", + "type": "number" + }, + "maxPlayers": { + "description": "The maximum number of players allowed to join.", + "type": "number" + }, + "extras": { + "type": "object" + } + } +} diff --git a/social/dwn/schemas/world.json b/social/dwn/schemas/world.json new file mode 100644 index 0000000..291a3d1 --- /dev/null +++ b/social/dwn/schemas/world.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://wired-protocol.org/v0/schemas/world.json", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "extras": { + "type": "object" + } + } +} diff --git a/spatial/README.md b/spatial/README.md new file mode 100644 index 0000000..4bb4b51 --- /dev/null +++ b/spatial/README.md @@ -0,0 +1,44 @@ +# Spatial Protocol + +The Wired's spatial protocol is concerned with running interactive user-created +content within a dynamic 3D multiplayer environment. + +## Scenes (glXF) + +The Wired uses the [glXF](https://github.com/KhronosGroup/glXF) file format for +describing scenes. glXF is a variant of [glTF](https://github.com/KhronosGroup/glTF), +focused on the composition of multiple glTF (or other glXF) assets. glTF is a +well supported format for 3D models, and its extensible nature makes it a great +fit for The Wired. + +## Scripts (WASM) + +The Wired uses [WebAssembly](https://webassembly.org/) (WASM) as a cross-platform +compilation target and sandboxed execution environment for user scripting. +Scripts use the [component model](https://github.com/WebAssembly/component-model) +to interact with a set of [WIT](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md) +interfaces defined by The Wired. Host environments can then implement these +interfaces, allowing scripts to interact with the outside world in a controlled +manner. + +## Worlds + +A world is a hosted multiplayer environment running some glXF scene. + +### Host + +Each world must be hosted by a central server. This server acts as a relay for +communication between players within the world. + +Worlds are created at a host's [DWN](../social/#decentralized-web-nodes-dwns), +following the [world schema](../social/dwn/schemas/world.json). This contains +metadata about the world such as a name and description, as well as the glXF +scene and any used assets. + +Additionally the host DWN acts as a location for world discovery, where you can, +for example, query for active worlds to join. + +## Networking + +Networking within an world follows a [Cap'n Proto](https://capnproto.org/) +schema over [WebTransport](https://developer.mozilla.org/en-US/docs/Web/API/WebTransport). diff --git a/spatial/capnp/datagram.capnp b/spatial/capnp/datagram.capnp new file mode 100644 index 0000000..9608fe1 --- /dev/null +++ b/spatial/capnp/datagram.capnp @@ -0,0 +1,25 @@ +@0x875d2f2c381d4863; + +struct Vec3 { + x @0 :Float32; + y @1 :Float32; + z @2 :Float32; +} + +struct Vec4 { + x @0 :Float32; + y @1 :Float32; + z @2 :Float32; + w @3 :Float32; +} + +struct PublishTransform { + translation @0 :Vec3; + rotation @1 :Vec4; +} + +struct ReceiveTransform { + playerId @0 :UInt16; + translation @1 :Vec3; + rotation @2 :Vec4; +} diff --git a/spatial/capnp/world_server.capnp b/spatial/capnp/world_server.capnp new file mode 100644 index 0000000..2c7e4dc --- /dev/null +++ b/spatial/capnp/world_server.capnp @@ -0,0 +1,39 @@ +@0xae09eca2c525e50a; + +struct Option(T) { + union { + some @0 :T; + none @1 :Void; + } +} + +struct Result(T) { + union { + result @0 :T; + error @1 :Text; + } +} + +struct Success { + union { + success @0 :Void; + error @1 :Text; + } +} + +interface WorldServer { + join @0 (recordId :Text) -> (success :Success); + leave @1 (recordId :Text); + + # Tickrate of the server, in seconds. + # Sending updates faster than this will be detrimental. + tickrate @2 () -> (tickrate :Float32); + + player @3 (id :UInt16) -> (player :Option(Player)); + players @4 () -> (players :List(Player)); + + struct Player { + id @0 :UInt16; + did @1 :Text; + } +} diff --git a/spatial/wit/wired-dwn/world.wit b/spatial/wit/wired-dwn/world.wit new file mode 100644 index 0000000..aedd449 --- /dev/null +++ b/spatial/wit/wired-dwn/world.wit @@ -0,0 +1,68 @@ +package wired:dwn; + +world host { + import api; + import dwn; +} + +interface api { + use dwn.{dwn}; + + /// Get the local user's DWN. + local-dwn: func() -> dwn; + + /// Get the local user's default world host DWN. + world-host-dwn: func() -> dwn; +} + +interface dwn { + record encrypted-data { + alg: string, + ciphertext: string, + iv: string, + recipients: list, + tag: string, + } + + variant data { + base64(string), + encrypted(encrypted-data), + } + + record message { + record-id: string, + data: option + } + + record status { + code: u16, + detail: option, + } + + record query-reply { + entries: list, + status: status, + } + + resource query { + poll: func() -> option; + finished: func() -> bool; + } + + resource query-builder { + protocol: func() -> option; + set-protocol: func(value: option); + + record-id: func() -> option; + set-record-id: func(value: option); + + schema: func() -> option; + set-schema: func(value: option); + + run: func() -> query; + } + + resource dwn { + query: func() -> query-builder; + } +} diff --git a/spatial/wit/wired-input/deps/wired-math b/spatial/wit/wired-input/deps/wired-math new file mode 120000 index 0000000..967f496 --- /dev/null +++ b/spatial/wit/wired-input/deps/wired-math @@ -0,0 +1 @@ +../../wired-math/ \ No newline at end of file diff --git a/spatial/wit/wired-input/types.wit b/spatial/wit/wired-input/types.wit new file mode 100644 index 0000000..330fa1b --- /dev/null +++ b/spatial/wit/wired-input/types.wit @@ -0,0 +1,61 @@ +interface types { + use wired:math/types.{vec3, quat}; + + enum hand-side { + left, + right, + } + + record joint { + translation: vec3, + rotation: quat, + radius: f32, + } + + record finger { + tip: joint, + distal: joint, + proximal: joint, + metacarpal: joint, + } + + /// Hand tracking data. + record hand { + side: hand-side, + + thumb: finger, + index: finger, + middle: finger, + ring: finger, + little: finger, + + palm: joint, + wrist: joint, + elbow: option, + } + + /// A line with an origin and a direction. + record ray { + orientation: quat, + origin: vec3, + } + + variant input-data { + hand(hand), + ray(ray), + } + + variant input-action { + collision, + hover, + } + + record input-event { + /// Unique id for the event. + id: u64, + /// The action that created the event. + action: input-action, + /// Spatial input data. + data: input-data, + } +} diff --git a/spatial/wit/wired-input/world.wit b/spatial/wit/wired-input/world.wit new file mode 100644 index 0000000..bff0e4d --- /dev/null +++ b/spatial/wit/wired-input/world.wit @@ -0,0 +1,18 @@ +package wired:input; + +world host { + import handler; + import types; +} + +interface handler { + use types.{input-event}; + + resource input-handler { + constructor(); + + /// Handle the next recieved input event. + /// Events only last for one tick. + next: func() -> option; + } +} diff --git a/spatial/wit/wired-log/world.wit b/spatial/wit/wired-log/world.wit new file mode 100644 index 0000000..8293de7 --- /dev/null +++ b/spatial/wit/wired-log/world.wit @@ -0,0 +1,16 @@ +package wired:log; + +world host { + import api; +} + +interface api { + enum log-level { + debug, + info, + warn, + error, + } + + log: func(level: log-level, message: string); +} diff --git a/spatial/wit/wired-math/world.wit b/spatial/wit/wired-math/world.wit new file mode 100644 index 0000000..e8c1a6e --- /dev/null +++ b/spatial/wit/wired-math/world.wit @@ -0,0 +1,37 @@ +package wired:math; + +world prelude { + import types; +} + +interface types { + record vec2 { + x: f32, + y: f32, + } + + record vec3 { + x: f32, + y: f32, + z: f32, + } + + record quat { + x: f32, + y: f32, + z: f32, + w: f32, + } + + record transform { + rotation: quat, + scale: vec3, + translation: vec3, + } + + /// Codegen doesn't always include types, these function force its inclusion. + fake-fn-a: func() -> vec2; + fake-fn-b: func() -> vec3; + fake-fn-c: func() -> quat; + fake-fn-d: func() -> transform; +} diff --git a/spatial/wit/wired-physics/deps/wired-math b/spatial/wit/wired-physics/deps/wired-math new file mode 120000 index 0000000..967f496 --- /dev/null +++ b/spatial/wit/wired-physics/deps/wired-math @@ -0,0 +1 @@ +../../wired-math/ \ No newline at end of file diff --git a/spatial/wit/wired-physics/world.wit b/spatial/wit/wired-physics/world.wit new file mode 100644 index 0000000..a9b49ec --- /dev/null +++ b/spatial/wit/wired-physics/world.wit @@ -0,0 +1,43 @@ +package wired:physics; + +world host { + import types; +} + +interface types { + use wired:math/types.{vec3}; + + resource collider { + constructor(shape: shape); + + density: func() -> f32; + set-density: func(value: f32); + } + + record shape-cylinder { + height: f32, + radius: f32, + } + + variant shape { + cuboid(vec3), + cylinder(shape-cylinder), + sphere(f32), + } + + resource rigid-body { + constructor(rigid-body-type: rigid-body-type); + + angvel: func() -> vec3; + set-angvel: func(value: vec3); + + linvel: func() -> vec3; + set-linvel: func(value: vec3); + } + + enum rigid-body-type { + dynamic, + fixed, + kinematic, + } +} diff --git a/spatial/wit/wired-player/deps/wired-input b/spatial/wit/wired-player/deps/wired-input new file mode 120000 index 0000000..6160bce --- /dev/null +++ b/spatial/wit/wired-player/deps/wired-input @@ -0,0 +1 @@ +../../wired-input/ \ No newline at end of file diff --git a/spatial/wit/wired-player/deps/wired-math b/spatial/wit/wired-player/deps/wired-math new file mode 120000 index 0000000..967f496 --- /dev/null +++ b/spatial/wit/wired-player/deps/wired-math @@ -0,0 +1 @@ +../../wired-math/ \ No newline at end of file diff --git a/spatial/wit/wired-player/deps/wired-physics b/spatial/wit/wired-player/deps/wired-physics new file mode 120000 index 0000000..8caa253 --- /dev/null +++ b/spatial/wit/wired-player/deps/wired-physics @@ -0,0 +1 @@ +../../wired-physics/ \ No newline at end of file diff --git a/spatial/wit/wired-player/deps/wired-scene b/spatial/wit/wired-player/deps/wired-scene new file mode 120000 index 0000000..2b292a8 --- /dev/null +++ b/spatial/wit/wired-player/deps/wired-scene @@ -0,0 +1 @@ +../../wired-scene/ \ No newline at end of file diff --git a/spatial/wit/wired-player/world.wit b/spatial/wit/wired-player/world.wit new file mode 100644 index 0000000..81619e7 --- /dev/null +++ b/spatial/wit/wired-player/world.wit @@ -0,0 +1,44 @@ +package wired:player; + +world host { + import api; +} + +interface api { + use wired:scene/node.{node}; + + record skeleton { + hips: node, + spine: node, + chest: node, + upper-chest: node, + neck: node, + head: node, + + left-shoulder: node, + left-upper-arm: node, + left-lower-arm: node, + left-hand: node, + + right-shoulder: node, + right-upper-arm: node, + right-lower-arm: node, + right-hand: node, + + left-upper-leg: node, + left-lower-leg: node, + left-foot: node, + + right-upper-leg: node, + right-lower-leg: node, + right-foot: node, + } + + resource player { + root: func() -> node; + skeleton: func() -> skeleton; + } + + list-players: func() -> list; + local-player: func() -> player; +} diff --git a/spatial/wit/wired-prelude/deps/wired-input b/spatial/wit/wired-prelude/deps/wired-input new file mode 120000 index 0000000..1f55dd4 --- /dev/null +++ b/spatial/wit/wired-prelude/deps/wired-input @@ -0,0 +1 @@ +../../wired-input \ No newline at end of file diff --git a/spatial/wit/wired-prelude/deps/wired-log b/spatial/wit/wired-prelude/deps/wired-log new file mode 120000 index 0000000..056c845 --- /dev/null +++ b/spatial/wit/wired-prelude/deps/wired-log @@ -0,0 +1 @@ +../../wired-log \ No newline at end of file diff --git a/spatial/wit/wired-prelude/deps/wired-math b/spatial/wit/wired-prelude/deps/wired-math new file mode 120000 index 0000000..33c05fe --- /dev/null +++ b/spatial/wit/wired-prelude/deps/wired-math @@ -0,0 +1 @@ +../../wired-math \ No newline at end of file diff --git a/spatial/wit/wired-prelude/deps/wired-physics b/spatial/wit/wired-prelude/deps/wired-physics new file mode 120000 index 0000000..b981cad --- /dev/null +++ b/spatial/wit/wired-prelude/deps/wired-physics @@ -0,0 +1 @@ +../../wired-physics \ No newline at end of file diff --git a/spatial/wit/wired-prelude/deps/wired-player b/spatial/wit/wired-prelude/deps/wired-player new file mode 120000 index 0000000..d965478 --- /dev/null +++ b/spatial/wit/wired-prelude/deps/wired-player @@ -0,0 +1 @@ +../../wired-player/ \ No newline at end of file diff --git a/spatial/wit/wired-prelude/deps/wired-scene b/spatial/wit/wired-prelude/deps/wired-scene new file mode 120000 index 0000000..2b292a8 --- /dev/null +++ b/spatial/wit/wired-prelude/deps/wired-scene @@ -0,0 +1 @@ +../../wired-scene/ \ No newline at end of file diff --git a/spatial/wit/wired-prelude/world.wit b/spatial/wit/wired-prelude/world.wit new file mode 100644 index 0000000..3050f42 --- /dev/null +++ b/spatial/wit/wired-prelude/world.wit @@ -0,0 +1,16 @@ +package wired:prelude; + +/// Prelude to be included in your world for ease of use. +world imports { + import wired:input/handler; + import wired:log/api; + import wired:math/types; + import wired:physics/types; + import wired:player/api; + include wired:scene/prelude; +} + +world script { + include imports; + include wired:script/script; +} diff --git a/spatial/wit/wired-scene/deps/wired-input b/spatial/wit/wired-scene/deps/wired-input new file mode 120000 index 0000000..6160bce --- /dev/null +++ b/spatial/wit/wired-scene/deps/wired-input @@ -0,0 +1 @@ +../../wired-input/ \ No newline at end of file diff --git a/spatial/wit/wired-scene/deps/wired-math b/spatial/wit/wired-scene/deps/wired-math new file mode 120000 index 0000000..967f496 --- /dev/null +++ b/spatial/wit/wired-scene/deps/wired-math @@ -0,0 +1 @@ +../../wired-math/ \ No newline at end of file diff --git a/spatial/wit/wired-scene/deps/wired-physics b/spatial/wit/wired-scene/deps/wired-physics new file mode 120000 index 0000000..8caa253 --- /dev/null +++ b/spatial/wit/wired-scene/deps/wired-physics @@ -0,0 +1 @@ +../../wired-physics/ \ No newline at end of file diff --git a/spatial/wit/wired-scene/gltf.wit b/spatial/wit/wired-scene/gltf.wit new file mode 100644 index 0000000..05fb4fe --- /dev/null +++ b/spatial/wit/wired-scene/gltf.wit @@ -0,0 +1,149 @@ +interface gltf { + use material.{material}; + use mesh.{mesh}; + use node.{node}; + use scene.{scene}; + + /// A glTF document. + /// Can be saved or loaded independently of the rest of the world. + resource gltf { + constructor(); + + list-materials: func() -> list; + add-material: func(value: borrow); + remove-material: func(value: borrow); + + list-meshes: func() -> list; + add-mesh: func(value: borrow); + remove-mesh: func(value: borrow); + + list-nodes: func() -> list; + add-node: func(value: borrow); + remove-node: func(value: borrow); + + list-scenes: func() -> list; + add-scene: func(value: borrow); + remove-scene: func(value: borrow); + + /// The currently loaded scene. + active-scene: func() -> option; + set-active-scene: func(value: option>); + + /// The default active scene, used when an asset is first loaded. + /// If not explicitly set, the first scene will be used. + default-scene: func() -> option; + set-default-scene: func(value: borrow); + } +} + +interface material { + record color { + r: f32, + g: f32, + b: f32, + a: f32, + } + + resource material { + constructor(); + + id: func() -> u32; + /// Returns another reference to the same resource. + ref: func() -> material; + + name: func() -> string; + set-name: func(value: string); + + color: func() -> color; + set-color: func(value: color); + } +} + +interface mesh { + use material.{material}; + + resource primitive { + id: func() -> u32; + + material: func() -> option; + set-material: func(value: option>); + + set-indices: func(value: list); + set-normals: func(value: list); + set-positions: func(value: list); + set-uvs: func(value: list); + } + + resource mesh { + constructor(); + + id: func() -> u32; + /// Returns another reference to the same resource. + ref: func() -> mesh; + + name: func() -> string; + set-name: func(value: string); + + list-primitives: func() -> list; + create-primitive: func() -> primitive; + remove-primitive: func(value: primitive); + } +} + +interface node { + use mesh.{mesh}; + use wired:input/handler.{input-handler}; + use wired:math/types.{transform}; + use wired:physics/types.{collider, rigid-body}; + + resource node { + constructor(); + + id: func() -> u32; + /// Returns another reference to the same resource. + ref: func() -> node; + + name: func() -> string; + set-name: func(value: string); + + children: func() -> list; + add-child: func(value: borrow); + remove-child: func(value: borrow); + + parent: func() -> option; + + global-transform: func() -> transform; + + transform: func() -> transform; + set-transform: func(value: transform); + + mesh: func() -> option; + set-mesh: func(value: option>); + + collider: func() -> option; + set-collider: func(value: option>); + + rigid-body: func() -> option; + set-rigid-body: func(value: option>); + + input-handler: func() -> option; + set-input-handler: func(value: option>); + } +} + +interface scene { + use node.{node}; + + resource scene { + constructor(); + + id: func() -> u32; + + name: func() -> string; + set-name: func(value: string); + + nodes: func() -> list; + add-node: func(value: borrow); + remove-node: func(value: borrow); + } +} diff --git a/spatial/wit/wired-scene/glxf.wit b/spatial/wit/wired-scene/glxf.wit new file mode 100644 index 0000000..c566905 --- /dev/null +++ b/spatial/wit/wired-scene/glxf.wit @@ -0,0 +1,108 @@ +interface glxf { + use gltf.{gltf}; + use node.{node}; + use wired:math/types.{transform}; + + /// Returns the root glXF that the script is attached to. + get-root: func() -> glxf; + + /// A glXF document. + /// Used to compose multiple independent glTF assets together. + resource glxf { + constructor(); + + list-assets: func() -> list; + + add-asset: func(value: asset-borrow); + remove-asset: func(value: asset-borrow); + + list-nodes: func() -> list; + add-node: func(value: borrow); + remove-node: func(value: borrow); + + list-scenes: func() -> list; + add-scene: func(value: borrow); + remove-scene: func(value: borrow); + + /// The currently loaded scene. + active-scene: func() -> option; + set-active-scene: func(value: option>); + + /// The default active scene, used when an asset is first loaded. + /// If not explicitly set, the first scene will be used. + default-scene: func() -> option; + set-default-scene: func(value: borrow); + } + + variant asset { + gltf(asset-gltf), + glxf(asset-glxf), + } + variant asset-borrow { + gltf(borrow), + glxf(borrow), + } + + resource asset-gltf { + constructor(document: borrow); + + document: func() -> gltf; + + /// Asset nodes to use. + /// If empty, will use the default scene. + list-nodes: func() -> list; + add-node: func(value: borrow); + remove-node: func(value: borrow); + } + + resource asset-glxf { + constructor(document: borrow); + + document: func() -> glxf; + + /// Asset nodes to use. + /// If empty, will use the default scene. + list-nodes: func() -> list; + add-node: func(value: borrow); + remove-node: func(value: borrow); + } + + resource glxf-node { + constructor(); + + id: func() -> u32; + + name: func() -> string; + set-name: func(value: string); + + transform: func() -> transform; + set-transform: func(value: transform); + + parent: func() -> option; + + children: func() -> option; + set-children: func(value: option); + } + + variant children { + asset(asset), + nodes(list), + } + variant children-borrow { + asset(asset-borrow), + nodes(list>), + } + + resource glxf-scene { + constructor(); + + id: func() -> u32; + + name: func() -> string; + set-name: func(value: string); + + nodes: func() -> list; + add-node: func(node: borrow); + remove-node: func(node: borrow); + } +} diff --git a/spatial/wit/wired-scene/world.wit b/spatial/wit/wired-scene/world.wit new file mode 100644 index 0000000..67d51a3 --- /dev/null +++ b/spatial/wit/wired-scene/world.wit @@ -0,0 +1,6 @@ +package wired:scene; + +world prelude { + import gltf; + import glxf; +} diff --git a/spatial/wit/wired-script/world.wit b/spatial/wit/wired-script/world.wit new file mode 100644 index 0000000..52caf13 --- /dev/null +++ b/spatial/wit/wired-script/world.wit @@ -0,0 +1,13 @@ +package wired:script; + +world script { + export types; +} + +interface types { + resource script { + constructor(); + /// Called every tick. + update: func(delta: f32); + } +} diff --git a/v0/protocols/world-host.json b/v0/protocols/world-host.json new file mode 100644 index 0000000..b8c74c2 --- /dev/null +++ b/v0/protocols/world-host.json @@ -0,0 +1,52 @@ +{ + "protocol": "https://wired-protocol.org/v0/protocols/world-host.json", + "published": true, + "types": { + "connect-url": { + "dataFormat": ["text/plain"] + }, + "host-info": { + "schema": "https://wired-protocol.org/v0/schemas/host-info.json", + "dataFormat": ["application/json"] + }, + "world": { + "schema": "https://wired-protocol.org/v0/schemas/world.json", + "dataFormat": ["application/json"] + } + }, + "structure": { + "connect-url": { + "$actions": [ + { + "who": "anyone", + "can": ["read"] + }, + { + "who": "recipient", + "can": ["write"] + } + ] + }, + "world": { + "$actions": [ + { + "who": "anyone", + "can": ["read", "write"] + } + ], + "host-info": { + "$actions": [ + { + "who": "anyone", + "can": ["read"] + }, + { + "who": "recipient", + "of": "world", + "can": ["write"] + } + ] + } + } + } +} diff --git a/v0/schemas/home.json b/v0/schemas/home.json new file mode 100644 index 0000000..bc019e9 --- /dev/null +++ b/v0/schemas/home.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://wired-protocol.org/v0/schemas/home.json", + "type": "object", + "description": "Defines a user's home world.", + "properties": { + "world": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "record_id": { + "type": "string" + } + }, + "required": ["did", "record_id"] + } + }, + "required": ["world"] +} diff --git a/v0/schemas/host-info.json b/v0/schemas/host-info.json new file mode 100644 index 0000000..d6ed6a6 --- /dev/null +++ b/v0/schemas/host-info.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://wired-protocol.org/v0/schemas/host-info.json", + "type": "object", + "properties": { + "active": { + "description": "Whether the world is currently being hosted.", + "type": "boolean" + }, + "numPlayers": { + "description": "The number of currently connected players.", + "type": "number" + }, + "maxPlayers": { + "description": "The maximum number of players allowed to join.", + "type": "number" + }, + "extras": { + "type": "object" + } + } +} diff --git a/v0/schemas/world.json b/v0/schemas/world.json new file mode 100644 index 0000000..291a3d1 --- /dev/null +++ b/v0/schemas/world.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://wired-protocol.org/v0/schemas/world.json", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "extras": { + "type": "object" + } + } +}