From 9552fe89da2a2d6289b5f5cb54eed87893a9ef41 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Oct 2026 04:55:02 +0000 Subject: [PATCH 1/2] Initial plan From 03e7199d3e1e69f730bdd1a4e1b53e81c633455b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Oct 2026 04:58:44 +0000 Subject: [PATCH 2/2] Add Rust core node wrappers and CI Co-authored-by: tjkilgore93-stack <313495784+tjkilgore93-stack@users.noreply.github.com> --- .github/workflows/deno.yml | 42 ------------ .github/workflows/rust.yml | 27 ++++++++ .gitignore | 1 + Cargo.lock | 7 ++ Cargo.toml | 3 + deno.json | 9 --- rust/components/Cargo.toml | 7 ++ rust/components/src/lib.rs | 137 +++++++++++++++++++++++++++++++++++++ 8 files changed, 182 insertions(+), 51 deletions(-) delete mode 100644 .github/workflows/deno.yml create mode 100644 .github/workflows/rust.yml create mode 100644 Cargo.lock create mode 100644 Cargo.toml delete mode 100644 deno.json create mode 100644 rust/components/Cargo.toml create mode 100644 rust/components/src/lib.rs diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml deleted file mode 100644 index 782af35b4..000000000 --- a/.github/workflows/deno.yml +++ /dev/null @@ -1,42 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow will install Deno then run `deno lint` and `deno test`. -# For more information see: https://github.com/denoland/setup-deno - -name: Deno - -on: - push: - branches: ["main"] - pull_request: - branches: ["main"] - -permissions: - contents: read - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - name: Setup repo - uses: actions/checkout@v4 - - - name: Setup Deno - # uses: denoland/setup-deno@v1 - uses: denoland/setup-deno@61fe2df320078202e33d7d5ad347e7dcfa0e8f31 # v1.1.2 - with: - deno-version: v1.x - - # Uncomment this step to verify the use of 'deno fmt' on each commit. - # - name: Verify formatting - # run: deno fmt --check - - - name: Run linter - run: deno lint - - - name: Run tests - run: deno test -A diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 000000000..747951136 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,27 @@ +name: Rust + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install stable Rust + run: | + rustup toolchain install stable --profile minimal --component clippy --component rustfmt + rustup default stable + - name: Check formatting + run: cargo fmt --all -- --check + - name: Run Clippy + run: cargo clippy --workspace --all-targets -- -D warnings + - name: Run tests + run: cargo test --workspace diff --git a/.gitignore b/.gitignore index 12b93f6ac..9eea21a83 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ localstorage.json .notes/ node_modules/ +target/ build/ /world* \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..aec0b0b8a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "hyperfy-components" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..040be3a85 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["rust/components"] +resolver = "2" diff --git a/deno.json b/deno.json deleted file mode 100644 index b0882109a..000000000 --- a/deno.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "lint": { - "exclude": [ - "src/core/physx-js-webidl.js", - "dist/", - "public/" - ] - } -} diff --git a/rust/components/Cargo.toml b/rust/components/Cargo.toml new file mode 100644 index 000000000..ad3537af7 --- /dev/null +++ b/rust/components/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "hyperfy-components" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" diff --git a/rust/components/src/lib.rs b/rust/components/src/lib.rs new file mode 100644 index 000000000..91829dc5d --- /dev/null +++ b/rust/components/src/lib.rs @@ -0,0 +1,137 @@ +//! Pure Rust adapters for the core node component identities and shared node data. + +use std::marker::PhantomData; + +pub trait Component { + const KIND: &'static str; +} + +#[derive(Clone, Debug, PartialEq)] +pub struct NodeTransform { + pub position: [f64; 3], + pub rotation: [f64; 4], + pub scale: [f64; 3], +} + +impl Default for NodeTransform { + fn default() -> Self { + Self { + position: [0.0; 3], + rotation: [0.0, 0.0, 0.0, 1.0], + scale: [1.0; 3], + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct NodeWrapper { + pub id: String, + pub active: bool, + pub transform: NodeTransform, + component: PhantomData, +} + +impl NodeWrapper { + pub fn new(id: impl Into) -> Self { + Self { + id: id.into(), + active: true, + transform: NodeTransform::default(), + component: PhantomData, + } + } + + pub fn kind(&self) -> &'static str { + C::KIND + } +} + +macro_rules! define_components { + ($($marker:ident => $wrapper:ident => $kind:literal),+ $(,)?) => { + $( + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] + pub struct $marker; + + impl Component for $marker { + const KIND: &'static str = $kind; + } + + pub type $wrapper = NodeWrapper<$marker>; + )+ + + pub const COMPONENT_KINDS: &[&str] = &[$(<$marker as Component>::KIND),+]; + }; +} + +define_components! { + Group => GroupNode => "group", + Mesh => MeshNode => "mesh", + SkinnedMesh => SkinnedMeshNode => "skinnedmesh", + Lod => LodNode => "lod", + Audio => AudioNode => "audio", + Video => VideoNode => "video", + Image => ImageNode => "image", + Snap => SnapNode => "snap", + Prim => PrimNode => "prim", + Avatar => AvatarNode => "avatar", + Action => ActionNode => "action", + Anchor => AnchorNode => "anchor", + Nametag => NametagNode => "nametag", + Particles => ParticlesNode => "particles", + Sky => SkyNode => "sky", + Ui => UiNode => "ui", + UiView => UiViewNode => "uiview", + UiText => UiTextNode => "uitext", + UiImage => UiImageNode => "uiimage", + Controller => ControllerNode => "controller", + RigidBody => RigidBodyNode => "rigidbody", + Collider => ColliderNode => "collider", + Joint => JointNode => "joint", +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn wrapper_uses_core_node_defaults_and_component_kind() { + let node = MeshNode::new("mesh-1"); + + assert_eq!(node.id, "mesh-1"); + assert!(node.active); + assert_eq!(node.kind(), "mesh"); + assert_eq!(node.transform, NodeTransform::default()); + } + + #[test] + fn registry_matches_all_core_node_component_kinds() { + assert_eq!( + COMPONENT_KINDS, + &[ + "group", + "mesh", + "skinnedmesh", + "lod", + "audio", + "video", + "image", + "snap", + "prim", + "avatar", + "action", + "anchor", + "nametag", + "particles", + "sky", + "ui", + "uiview", + "uitext", + "uiimage", + "controller", + "rigidbody", + "collider", + "joint", + ] + ); + } +}