npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-three-game

v0.0.16

Published

Batteries included React Three Fiber game engine

Downloads

1,773

Readme

react-three-game

Component-based 3D game engine where everything is JSON. Built on React Three Fiber + WebGPU.

npm i react-three-game @react-three/fiber three

MIT License TypeScript React

Prefab Editor

Core Principle

Scenes are JSON prefabs. Components are registered modules. Hierarchy is declarative.

  <PrefabRoot data={{
      root: {
          id: "cube",
          components: {
              transform: { type: "Transform", properties: { position: [0, 1, 0] } },
              geometry: { type: "Geometry", properties: { geometryType: "box" } },
              material: { type: "Material", properties: { color: "green" } },
              physics: { type: "Physics", properties: { type: "dynamic" } }
          }
      }
  }} />

Styling

The prefab editor UI ships with inline styles (no Tailwind / CSS framework required). That means you can install and render it without any additional build-time CSS configuration.

If you want to fully restyle the editor, you can:

  • Wrap PrefabEditor in your own layout and override positioning.
  • Fork/compose the editor UI components (they’re plain React components).

Quick Start

npm install react-three-game @react-three/fiber @react-three/rapier three
import { Physics } from '@react-three/rapier';
import { GameCanvas, PrefabRoot } from 'react-three-game';

export default function App() {
  return (
    <GameCanvas>
      <Physics>
        <ambientLight intensity={0.8} />
        <PrefabRoot
          data={{
              id: "scene",
              name: "scene",
              root: {
                  id: "root",
                  children: [
                      {
                          id: "ground",
                          components: {
                              transform: { type: "Transform", properties: { position: [0, 0, 0], rotation: [-1.57, 0, 0] } },
                              geometry: { type: "Geometry", properties: { geometryType: "plane", args: [50, 50] } },
                              material: { type: "Material", properties: { color: "green" } },
                              physics: { type: "Physics", properties: { type: "fixed" } }
                          }
                      },
                      {
                          id: "player",
                          components: {
                              transform: { type: "Transform", properties: { position: [0, 2, 0] } },
                              geometry: { type: "Geometry", properties: { geometryType: "sphere" } },
                              material: { type: "Material", properties: { color: "#ff6b6b" } },
                              physics: { type: "Physics", properties: { type: "dynamic" } }
                          }
                      }
                  ]
              }
          }}
      />
      </Physics>
    </GameCanvas>
  );
}

GameObject Structure

interface GameObject {
  id: string;
  disabled?: boolean;
  hidden?: boolean;
  components: {
    transform?: TransformComponent;
    geometry?: GeometryComponent;
    material?: MaterialComponent;
    physics?: PhysicsComponent;
    model?: ModelComponent;
  };
  children?: GameObject[];
}

Custom Components

import { Component } from 'react-three-game';

const LaserComponent: Component = {
  name: 'Laser',
  Editor: ({ component, onUpdate }) => (
    <input 
      value={component.properties.damage} 
      onChange={e => onUpdate({ damage: +e.target.value })}
    />
  ),
  View: ({ properties }) => (
    <pointLight color="red" intensity={properties.damage} />
  ),
  defaultProperties: { damage: 10 }
};

// Register
import { registerComponent } from 'react-three-game';
registerComponent(LaserComponent);

Built-in Components

| Component | Properties | |-----------|-----------| | Transform | position: [x,y,z], rotation: [x,y,z], scale: [x,y,z] | | Geometry | geometryType: "box"\|"sphere"\|"plane"\|"cylinder", args: number[] | | Material | color: string, texture?: string, metalness?: number, roughness?: number | | Physics | type: "dynamic"\|"fixed" | | Model | filename: string, instanced?: boolean | | SpotLight | color: string, intensity: number, angle: number, penumbra: number |

Prefab Editor

import { PrefabEditor } from 'react-three-game';

export default function EditorPage() {
  return <PrefabEditor />;
}

Transform gizmos (T/R/S keys), drag-to-reorder tree, import/export JSON, edit/play toggle.

Implementation Details

Transform Hierarchy

  • Local transforms stored in JSON (relative to parent)
  • World transforms computed at runtime via matrix multiplication
  • computeParentWorldMatrix(root, targetId) traverses tree for parent's world matrix
  • TransformControls extract world matrix → compute parent inverse → derive new local transform

GPU Instancing

Enable with model.properties.instanced = true:

{
  "components": {
    "model": { 
      "type": "Model", 
      "properties": { 
        "filename": "tree.glb",
        "instanced": true
      }
    }
  }
}

Uses drei's <Merged> + <InstancedRigidBodies> for physics. World-space transforms, terminal nodes.

Model Loading

  • Supports GLB/GLTF (Draco compression) and FBX
  • Singleton loaders in modelLoader.ts
  • Draco decoder from https://www.gstatic.com/draco/v1/decoders/
  • Auto-loads when model.properties.filename detected

WebGPU Renderer

<Canvas gl={async ({ canvas }) => {
  const renderer = new WebGPURenderer({ canvas, shadowMap: true });
  await renderer.init(); // Required
  return renderer;
}}>

Use MeshStandardNodeMaterial not MeshStandardMaterial.

Patterns

Load External Prefabs

import levelData from './prefabs/arena.json';
<PrefabRoot data={levelData} />

Mix with React Components

<Physics>
  <PrefabRoot data={environment} />
  <Player />
  <AIEnemies />
</Physics>

Update Prefab Nodes

function updatePrefabNode(root: GameObject, id: string, update: (node: GameObject) => GameObject): GameObject {
  if (root.id === id) return update(root);
  if (root.children) {
    return { ...root, children: root.children.map(child => updatePrefabNode(child, id, update)) };
  }
  return root;
}

AI Agent Reference

Prefab JSON Schema

{
  "id": "unique-id",
  "root": {
    "id": "root-id",
    "components": {
      "transform": {
        "type": "Transform",
        "properties": {
          "position": [x, y, z],      // world units
          "rotation": [x, y, z],      // radians
          "scale": [x, y, z]          // multipliers
        }
      },
      "geometry": {
        "type": "Geometry",
        "properties": {
          "geometryType": "box" | "sphere" | "plane" | "cylinder" | "cone" | "torus",
          "args": [/* geometry-specific */]
        }
      },
      "material": {
        "type": "Material",
        "properties": {
          "color": "#rrggbb",
          "texture": "/path/to/texture.jpg",
          "metalness": 0.0-1.0,
          "roughness": 0.0-1.0
        }
      },
      "physics": {
        "type": "Physics",
        "properties": {
          "type": "dynamic" | "fixed"
        }
      },
      "model": {
        "type": "Model",
        "properties": {
          "filename": "/models/asset.glb",
          "instanced": true
        }
      }
    },
    "children": [/* recursive GameObjects */]
  }
}

Development

git clone https://github.com/prnthh/react-three-game.git
cd react-three-game
npm install
npm run dev     # tsc --watch + Next.js docs
npm run build   # TypeScript → /dist
npm publish     # publish to npm

Project structure:

/src              → library source
  /shared         → GameCanvas
  /tools
    /prefabeditor → editor + PrefabRoot
/docs             → Next.js site
  /app            → demo pages

Tech Stack

React 19 • Three.js r181 • TypeScript 5 • WebGPU • Rapier Physics

License

MIT © prnth