react-three-game 0.0.40 → 0.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
2
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
3
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
2
  import { Canvas, useLoader } from "@react-three/fiber";
4
3
  import { OrbitControls, Stage, View, PerspectiveCamera } from "@react-three/drei";
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
2
  // DragDropLoader.tsx
4
3
  import { useEffect } from "react";
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
2
  import GameCanvas from "../../shared/GameCanvas";
4
3
  import { useState, useRef, useEffect, forwardRef, useImperativeHandle } from "react";
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
2
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
3
  return new (P || (P = Promise))(function (resolve, reject) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-three-game",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "description": "Batteries included React Three Fiber game engine",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -37,7 +37,8 @@
37
37
  "react": "^19.2.0",
38
38
  "react-dom": "^19.2.0",
39
39
  "three": "^0.182.0",
40
- "typescript": "^5.9.3"
40
+ "typescript": "^5.9.3",
41
+ "vite": "^7.3.1"
41
42
  },
42
43
  "dependencies": {
43
44
  "react-error-boundary": "^6.0.0"
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  import { Canvas, extend, CanvasProps } from "@react-three/fiber";
4
2
  import { WebGPURenderer, MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial, PCFShadowMap } from "three/webgpu";
5
3
  import { Suspense, useState } from "react";
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  import { Canvas, useLoader } from "@react-three/fiber";
4
2
  import { OrbitControls, Stage, View, PerspectiveCamera } from "@react-three/drei";
5
3
  import { Suspense, useEffect, useState, useRef } from "react";
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  // DragDropLoader.tsx
3
2
  import { useEffect, ChangeEvent } from "react";
4
3
  import { DRACOLoader, FBXLoader, GLTFLoader } from "three/examples/jsm/Addons.js";
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  import GameCanvas from "../../shared/GameCanvas";
4
2
  import { useState, useRef, useEffect, forwardRef, useImperativeHandle } from "react";
5
3
  import { Prefab } from "./types";
@@ -1,5 +1,3 @@
1
- "use client";
2
-
3
1
  import { MapControls, TransformControls, useHelper } from "@react-three/drei";
4
2
  import { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState } from "react";
5
3
  import { BoxHelper, Euler, Group, Matrix4, Object3D, Quaternion, SRGBColorSpace, Texture, TextureLoader, Vector3, } from "three";
@@ -1 +0,0 @@
1
- export {};
@@ -1,13 +0,0 @@
1
- import { extend } from "@react-three/fiber";
2
- import * as THREE from "three";
3
- import * as WEBGPU from "three/webgpu";
4
- console.log('EXTENDING THREE NAMESPACE');
5
- console.log('THREE keys:', Object.keys(THREE).length);
6
- console.log('Has Canvas?', 'Canvas' in THREE);
7
- console.log('Has AmbientLight?', 'AmbientLight' in THREE);
8
- console.log('Has GridHelper?', 'GridHelper' in THREE);
9
- // Extend entire THREE namespace to support all THREE objects in JSX
10
- // This must happen before any Canvas components are created
11
- extend(THREE);
12
- extend(WEBGPU);
13
- console.log('THREE NAMESPACE EXTENDED');
@@ -1,6 +0,0 @@
1
- import { ReactElement } from "react";
2
- export default function GameWithLoader({ children }: {
3
- children: ReactElement<{
4
- onCanvasReady?: () => void;
5
- }>;
6
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,8 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { cloneElement, useState } from "react";
4
- import LoadingSpinner from "../../sketches/loading/loading";
5
- export default function GameWithLoader({ children }) {
6
- const [isCanvasReady, setIsCanvasReady] = useState(false);
7
- return (_jsxs(_Fragment, { children: [!isCanvasReady && _jsx(LoadingSpinner, {}), cloneElement(children, { onCanvasReady: () => setIsCanvasReady(true) })] }));
8
- }
@@ -1,2 +0,0 @@
1
- declare const LoadingSpinner: () => import("react/jsx-runtime").JSX.Element;
2
- export default LoadingSpinner;
@@ -1,38 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useEffect, useState } from "react";
4
- const lines = [
5
- "$ initializing...",
6
- "✓ loading scene",
7
- "✓ ready"
8
- ];
9
- const LoadingSpinner = () => {
10
- const [index, setIndex] = useState(0);
11
- useEffect(() => {
12
- if (index < lines.length) {
13
- const timer = setTimeout(() => setIndex(index + 1), 300);
14
- return () => clearTimeout(timer);
15
- }
16
- }, [index]);
17
- return (_jsxs("div", { className: "terminal-loading", children: [lines.slice(0, index).map((line, i) => (_jsx("div", { children: line }, i))), _jsx("div", { className: "cursor", children: "\u2588" }), _jsx("style", { jsx: true, children: `
18
- .terminal-loading {
19
- position: fixed;
20
- inset: 0;
21
- z-index: 50;
22
- background: #0a0a0a;
23
- color: #00ff00;
24
- font-family: monospace;
25
- padding: 2rem;
26
- font-size: 14px;
27
- }
28
-
29
- .cursor {
30
- animation: blink 1s infinite;
31
- }
32
-
33
- @keyframes blink {
34
- 50% { opacity: 0; }
35
- }
36
- ` })] }));
37
- };
38
- export default LoadingSpinner;
@@ -1,7 +0,0 @@
1
- export declare const SCREENSHOT_EVENT = "prefab-editor-screenshot";
2
- export declare const EXPORT_GLB_EVENT = "prefab-editor-export-glb";
3
- export declare function ExportHelper({ prefabName }: {
4
- prefabName: string;
5
- }): null;
6
- export declare function triggerScreenshot(): void;
7
- export declare function triggerExportGLB(): void;
@@ -1,55 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- import { useThree } from "@react-three/fiber";
3
- import { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter.js";
4
- // Custom events for triggering exports
5
- export const SCREENSHOT_EVENT = "prefab-editor-screenshot";
6
- export const EXPORT_GLB_EVENT = "prefab-editor-export-glb";
7
- export function ExportHelper({ prefabName }) {
8
- const { gl, scene } = useThree();
9
- const sceneRef = useRef(scene);
10
- useEffect(() => {
11
- sceneRef.current = scene;
12
- }, [scene]);
13
- useEffect(() => {
14
- const handleScreenshot = () => {
15
- const canvas = gl.domElement;
16
- canvas.toBlob((blob) => {
17
- if (!blob)
18
- return;
19
- const url = URL.createObjectURL(blob);
20
- const a = document.createElement('a');
21
- a.href = url;
22
- a.download = `${prefabName || 'screenshot'}.png`;
23
- a.click();
24
- URL.revokeObjectURL(url);
25
- });
26
- };
27
- const handleExportGLB = () => {
28
- const exporter = new GLTFExporter();
29
- exporter.parse(sceneRef.current, (result) => {
30
- const blob = new Blob([result], { type: 'application/octet-stream' });
31
- const url = URL.createObjectURL(blob);
32
- const a = document.createElement('a');
33
- a.href = url;
34
- a.download = `${prefabName || 'scene'}.glb`;
35
- a.click();
36
- URL.revokeObjectURL(url);
37
- }, (error) => {
38
- console.error('Error exporting GLB:', error);
39
- }, { binary: true });
40
- };
41
- window.addEventListener(SCREENSHOT_EVENT, handleScreenshot);
42
- window.addEventListener(EXPORT_GLB_EVENT, handleExportGLB);
43
- return () => {
44
- window.removeEventListener(SCREENSHOT_EVENT, handleScreenshot);
45
- window.removeEventListener(EXPORT_GLB_EVENT, handleExportGLB);
46
- };
47
- }, [gl, prefabName]);
48
- return null;
49
- }
50
- export function triggerScreenshot() {
51
- window.dispatchEvent(new Event(SCREENSHOT_EVENT));
52
- }
53
- export function triggerExportGLB() {
54
- window.dispatchEvent(new Event(EXPORT_GLB_EVENT));
55
- }
@@ -1,3 +0,0 @@
1
- import { Component } from "./ComponentRegistry";
2
- declare const RotatorComponent: Component;
3
- export default RotatorComponent;
@@ -1,42 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useFrame } from "@react-three/fiber";
3
- import { useRef } from "react";
4
- function RotatorComponentEditor({ component, onUpdate }) {
5
- var _a, _b;
6
- const props = {
7
- speed: (_a = component.properties.speed) !== null && _a !== void 0 ? _a : 1.0,
8
- axis: (_b = component.properties.axis) !== null && _b !== void 0 ? _b : 'y'
9
- };
10
- return _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Rotation Speed" }), _jsx("input", { type: "number", step: "0.1", className: "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: props.speed, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { speed: parseFloat(e.target.value) })) })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Rotation Axis" }), _jsxs("select", { className: "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: props.axis, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { axis: e.target.value })), children: [_jsx("option", { value: "x", children: "X" }), _jsx("option", { value: "y", children: "Y" }), _jsx("option", { value: "z", children: "Z" })] })] })] });
11
- }
12
- // The view component for Rotator
13
- function RotatorView({ properties, children }) {
14
- var _a, _b;
15
- const groupRef = useRef(null);
16
- const speed = (_a = properties.speed) !== null && _a !== void 0 ? _a : 1.0;
17
- const axis = (_b = properties.axis) !== null && _b !== void 0 ? _b : 'y';
18
- useFrame((state, delta) => {
19
- if (groupRef.current) {
20
- if (axis === 'x') {
21
- groupRef.current.rotation.x += delta * speed;
22
- }
23
- else if (axis === 'y') {
24
- groupRef.current.rotation.y += delta * speed;
25
- }
26
- else if (axis === 'z') {
27
- groupRef.current.rotation.z += delta * speed;
28
- }
29
- }
30
- });
31
- return (_jsx("group", { ref: groupRef, children: children }));
32
- }
33
- const RotatorComponent = {
34
- name: 'Rotator',
35
- Editor: RotatorComponentEditor,
36
- View: RotatorView,
37
- defaultProperties: {
38
- speed: 1.0,
39
- axis: 'y'
40
- }
41
- };
42
- export default RotatorComponent;
@@ -1,10 +0,0 @@
1
- import { Object3D } from 'three';
2
- /**
3
- * Hook to load a model (GLB/GLTF/FBX) using drei's optimized loaders
4
- * Returns the loaded model with proper caching and suspense support
5
- */
6
- export declare function useModel(filename: string | undefined): Object3D | null;
7
- /**
8
- * Preload a model to avoid suspense boundaries during runtime
9
- */
10
- export declare function preloadModel(filename: string): void;
@@ -1,40 +0,0 @@
1
- import { useGLTF, useFBX } from '@react-three/drei';
2
- import { useMemo } from 'react';
3
- /**
4
- * Hook to load a model (GLB/GLTF/FBX) using drei's optimized loaders
5
- * Returns the loaded model with proper caching and suspense support
6
- */
7
- export function useModel(filename) {
8
- const isFBX = filename === null || filename === void 0 ? void 0 : filename.toLowerCase().endsWith('.fbx');
9
- const isGLTF = (filename === null || filename === void 0 ? void 0 : filename.toLowerCase().endsWith('.glb')) || (filename === null || filename === void 0 ? void 0 : filename.toLowerCase().endsWith('.gltf'));
10
- // Normalize path (ensure leading slash)
11
- const normalizedPath = useMemo(() => {
12
- if (!filename)
13
- return '';
14
- return filename.startsWith('/') ? filename : `/${filename}`;
15
- }, [filename]);
16
- // Load models using drei hooks (these handle caching automatically)
17
- const gltf = useGLTF(isGLTF && normalizedPath ? normalizedPath : '', true);
18
- const fbx = useFBX(isFBX && normalizedPath ? normalizedPath : '');
19
- // Return the appropriate model
20
- if (!filename)
21
- return null;
22
- if (isGLTF)
23
- return gltf.scene;
24
- if (isFBX)
25
- return fbx;
26
- return null;
27
- }
28
- /**
29
- * Preload a model to avoid suspense boundaries during runtime
30
- */
31
- export function preloadModel(filename) {
32
- const normalizedPath = filename.startsWith('/') ? filename : `/${filename}`;
33
- const isFBX = filename.toLowerCase().endsWith('.fbx');
34
- if (isFBX) {
35
- useFBX.preload(normalizedPath);
36
- }
37
- else {
38
- useGLTF.preload(normalizedPath);
39
- }
40
- }