From f9c449561088ad6cb6e29020dea10396d782d172 Mon Sep 17 00:00:00 2001 From: Tom Boullay Date: Fri, 17 Apr 2026 16:03:29 +0200 Subject: [PATCH] refacto: cleanning the codebase --- package-lock.json | 154 +++++++++++++++++- package.json | 2 +- public/skybox/sky.exr | 3 + src/App.tsx | 7 +- src/components/3d/TriggerObject.tsx | 9 +- src/components/ui/Crosshair.tsx | 4 +- src/components/ui/InteractPrompt.tsx | 8 +- src/data/debugConfig.ts | 11 ++ src/data/environmentConfig.ts | 11 +- src/hooks/debug/useDebugFolder.ts | 21 ++- src/hooks/useInteraction.ts | 26 +-- src/stateManager/AudioManager.ts | 42 ++++- src/stateManager/InteractionManager.ts | 13 +- src/utils/debug/Debug.ts | 32 +++- src/utils/debug/scene/DebugCameraControls.tsx | 18 +- src/utils/debug/scene/DebugHelpers.tsx | 19 ++- src/world/Environment.tsx | 13 +- 17 files changed, 317 insertions(+), 76 deletions(-) create mode 100644 public/skybox/sky.exr diff --git a/package-lock.json b/package-lock.json index 5b633d6..f0f691a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,10 @@ "dependencies": { "@react-three/drei": "^10.7.7", "@react-three/fiber": "^9.6.0", + "@react-three/postprocessing": "^3.0.4", "@react-three/rapier": "^2.2.0", + "gsap": "^3.15.0", + "lil-gui": "^0.21.0", "r3f-perf": "^7.2.3", "react": "^19.2.4", "react-dom": "^19.2.4", @@ -23,10 +26,11 @@ "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", "eslint": "^9.39.4", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.4.0", - "lil-gui": "^0.21.0", "madge": "^8.0.0", "prettier": "^3.8.2", "typescript": "~6.0.2", @@ -643,6 +647,19 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, "node_modules/@radix-ui/react-icons": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", @@ -752,6 +769,32 @@ } } }, + "node_modules/@react-three/postprocessing": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@react-three/postprocessing/-/postprocessing-3.0.4.tgz", + "integrity": "sha512-e4+F5xtudDYvhxx3y0NtWXpZbwvQ0x1zdOXWTbXMK6fFLVDd4qucN90YaaStanZGS4Bd5siQm0lGL/5ogf8iDQ==", + "license": "MIT", + "dependencies": { + "maath": "^0.6.0", + "n8ao": "^1.9.4", + "postprocessing": "^6.36.6" + }, + "peerDependencies": { + "@react-three/fiber": "^9.0.0", + "react": "^19.0", + "three": ">= 0.156.0" + } + }, + "node_modules/@react-three/postprocessing/node_modules/maath": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/maath/-/maath-0.6.0.tgz", + "integrity": "sha512-dSb2xQuP7vDnaYqfoKzlApeRcR2xtN8/f7WV/TMAkBC8552TwTLtOO0JTcSygkYMjNDPoo6V01jTw/aPi4JrMw==", + "license": "MIT", + "peerDependencies": { + "@types/three": ">=0.144.0", + "three": ">=0.144.0" + } + }, "node_modules/@react-three/rapier": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@react-three/rapier/-/rapier-2.2.0.tgz", @@ -2531,6 +2574,53 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react-hooks": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", @@ -2689,6 +2779,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2939,6 +3036,12 @@ "dev": true, "license": "ISC" }, + "node_modules/gsap": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.15.0.tgz", + "integrity": "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==", + "license": "Standard 'no charge' license: https://gsap.com/standard-license." + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3564,7 +3667,6 @@ "version": "0.21.0", "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.21.0.tgz", "integrity": "sha512-tpvxN7v1GvE/Tv+GRopfOp0W7fVEjF4PltkuX8vOCIfim22rD1ztvfkoEMcv9lzQeuNUSeIrUmUjBwmlW/oUew==", - "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -3788,6 +3890,16 @@ "dev": true, "license": "MIT" }, + "node_modules/n8ao": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/n8ao/-/n8ao-1.10.1.tgz", + "integrity": "sha512-hhI1pC+BfOZBV1KMwynBrVlIm8wqLxj/abAWhF2nZ0qQKyzTSQa1QtLVS2veRiuoBQXojxobcnp0oe+PUoxf/w==", + "license": "ISC", + "peerDependencies": { + "postprocessing": ">=6.30.0", + "three": ">=0.137" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -4059,6 +4171,15 @@ "postcss": "^8.2.9" } }, + "node_modules/postprocessing": { + "version": "6.39.0", + "resolved": "https://registry.npmjs.org/postprocessing/-/postprocessing-6.39.0.tgz", + "integrity": "sha512-/G6JY8hs426lcto/pBZlnFSkyEo1fHsh4gy7FPJtq1SaSUOzJgDW6f6f1K/+aMOYzK/eQEefyOb3++jPPIUeDA==", + "license": "Zlib", + "peerDependencies": { + "three": ">= 0.168.0 < 0.184.0" + } + }, "node_modules/potpack": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", @@ -4145,6 +4266,19 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-ms": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", @@ -4907,6 +5041,22 @@ "react": ">=17.0" } }, + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, "node_modules/tapable": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", diff --git a/package.json b/package.json index 603256c..da2590f 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@react-three/postprocessing": "^3.0.4", "@react-three/rapier": "^2.2.0", "gsap": "^3.15.0", + "lil-gui": "^0.21.0", "r3f-perf": "^7.2.3", "react": "^19.2.4", "react-dom": "^19.2.4", @@ -36,7 +37,6 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.4.0", - "lil-gui": "^0.21.0", "madge": "^8.0.0", "prettier": "^3.8.2", "typescript": "~6.0.2", diff --git a/public/skybox/sky.exr b/public/skybox/sky.exr new file mode 100644 index 0000000..c6ff8e1 --- /dev/null +++ b/public/skybox/sky.exr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:904b303c98f865526b9524b955f440e630f29d8e18a57bb7bf443fcd9715add1 +size 83079911 diff --git a/src/App.tsx b/src/App.tsx index 1a1b948..5879bcd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,3 +1,4 @@ +import { Suspense } from "react"; import { Canvas } from "@react-three/fiber"; import { Crosshair } from "@/components/ui/Crosshair"; import { InteractPrompt } from "@/components/ui/InteractPrompt"; @@ -8,8 +9,10 @@ function App(): React.JSX.Element { return ( <> - - + + + + diff --git a/src/components/3d/TriggerObject.tsx b/src/components/3d/TriggerObject.tsx index 51c919b..476b8de 100644 --- a/src/components/3d/TriggerObject.tsx +++ b/src/components/3d/TriggerObject.tsx @@ -1,4 +1,4 @@ -import { useRef, useState } from "react"; +import { useState } from "react"; import { useGLTF } from "@react-three/drei"; import { RigidBody } from "@react-three/rapier"; import { InteractableObject } from "@/components/3d/InteractableObject"; @@ -50,7 +50,6 @@ export function TriggerObject({ spawnOffset = TRIGGER_DEFAULT_SPAWN_OFFSET, }: TriggerObjectProps): React.JSX.Element { const [spawned, setSpawned] = useState([]); - const positionRef = useRef(position); return ( <> @@ -66,9 +65,9 @@ export function TriggerObject({ if (spawnModel) { const spawnPos: [number, number, number] = [ - positionRef.current[0] + spawnOffset[0], - positionRef.current[1] + spawnOffset[1], - positionRef.current[2] + spawnOffset[2], + position[0] + spawnOffset[0], + position[1] + spawnOffset[1], + position[2] + spawnOffset[2], ]; setSpawned((prev) => [ ...prev, diff --git a/src/components/ui/Crosshair.tsx b/src/components/ui/Crosshair.tsx index dae485e..73f31b5 100644 --- a/src/components/ui/Crosshair.tsx +++ b/src/components/ui/Crosshair.tsx @@ -1,9 +1,9 @@ import { useCameraMode } from "@/hooks/debug/useCameraMode"; -import { useInteraction } from "@/hooks/useInteraction"; +import { useInteractionSelector } from "@/hooks/useInteraction"; export function Crosshair(): React.JSX.Element | null { const cameraMode = useCameraMode(); - const { focused } = useInteraction(); + const focused = useInteractionSelector((state) => state.focused); if (cameraMode !== "player") return null; diff --git a/src/components/ui/InteractPrompt.tsx b/src/components/ui/InteractPrompt.tsx index 8fff76d..8acb5c3 100644 --- a/src/components/ui/InteractPrompt.tsx +++ b/src/components/ui/InteractPrompt.tsx @@ -1,16 +1,18 @@ +import { INTERACT_KEY } from "@/data/keybindings"; import { useCameraMode } from "@/hooks/debug/useCameraMode"; -import { useInteraction } from "@/hooks/useInteraction"; +import { useInteractionSelector } from "@/hooks/useInteraction"; export function InteractPrompt(): React.JSX.Element | null { const cameraMode = useCameraMode(); - const { focused, holding } = useInteraction(); + const focused = useInteractionSelector((state) => state.focused); + const holding = useInteractionSelector((state) => state.holding); if (cameraMode !== "player") return null; if (!focused || holding || focused.kind !== "trigger") return null; return (
- E + {INTERACT_KEY.toUpperCase()} {focused.label}
); diff --git a/src/data/debugConfig.ts b/src/data/debugConfig.ts index 946b8f6..6f5e4fc 100644 --- a/src/data/debugConfig.ts +++ b/src/data/debugConfig.ts @@ -3,3 +3,14 @@ export const INTERACTION_DEBUG_SPHERE_COLOR = "#facc15"; export const INTERACTION_DEBUG_SPHERE_OPACITY = 0.25; export const MAP_DEBUG_BOX_HELPER_COLOR = 0x00ff88; + +export const DEBUG_CAMERA_DAMPING_FACTOR = 0.05; +export const DEBUG_CAMERA_MIN_DISTANCE = 100; +export const DEBUG_CAMERA_MAX_DISTANCE = 1000; + +export const DEBUG_GRID_SIZE = 180; +export const DEBUG_GRID_DIVISIONS = 36; +export const DEBUG_GRID_PRIMARY_COLOR = "#1d4ed8"; +export const DEBUG_GRID_SECONDARY_COLOR = "#1e293b"; +export const DEBUG_GRID_Y = 0.01; +export const DEBUG_AXES_SIZE = 10; diff --git a/src/data/environmentConfig.ts b/src/data/environmentConfig.ts index 36c7dd9..fe277fa 100644 --- a/src/data/environmentConfig.ts +++ b/src/data/environmentConfig.ts @@ -1,11 +1,2 @@ +export const GAME_SCENE_SKYBOX_PATH = "/skybox/sky.exr"; export const PHYSICS_SCENE_BACKGROUND_COLOR = "#0b1018"; - -// CubeTextureLoader face order: +X, -X, +Y, -Y, +Z, -Z -export const SKYBOX_FACES = [ - "/skybox/px.jpg", - "/skybox/nx.jpg", - "/skybox/py.jpg", - "/skybox/ny.jpg", - "/skybox/pz.jpg", - "/skybox/nz.jpg", -] as const; diff --git a/src/hooks/debug/useDebugFolder.ts b/src/hooks/debug/useDebugFolder.ts index 7c19e96..ce51f1a 100644 --- a/src/hooks/debug/useDebugFolder.ts +++ b/src/hooks/debug/useDebugFolder.ts @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useRef } from "react"; import type GUI from "lil-gui"; import { Debug } from "@/utils/debug/Debug"; @@ -6,12 +6,23 @@ export function useDebugFolder( name: string, setup: (folder: GUI) => void, ): void { + const setupRef = useRef(setup); + + useEffect(() => { + setupRef.current = setup; + }, [setup]); + useEffect(() => { const debug = Debug.getInstance(); if (!debug.active) return; + const folder = debug.createFolder(name); - if (!folder) return; - setup(folder); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + if (folder) { + setupRef.current(folder); + } + + return () => { + debug.destroyFolder(name); + }; + }, [name]); } diff --git a/src/hooks/useInteraction.ts b/src/hooks/useInteraction.ts index 503c2a6..79582ff 100644 --- a/src/hooks/useInteraction.ts +++ b/src/hooks/useInteraction.ts @@ -1,18 +1,22 @@ -import { useEffect, useState } from "react"; +import { useSyncExternalStore } from "react"; import { InteractionManager, type InteractionSnapshot, } from "@/stateManager/InteractionManager"; +const manager = InteractionManager.getInstance(); + export function useInteraction(): InteractionSnapshot { - const manager = InteractionManager.getInstance(); - const [state, setState] = useState(manager.getState()); - - useEffect(() => { - return manager.subscribe(() => { - setState({ ...manager.getState() }); - }); - }, [manager]); - - return state; + return useSyncExternalStore( + manager.subscribe.bind(manager), + manager.getState.bind(manager), + ); +} + +export function useInteractionSelector( + selector: (state: InteractionSnapshot) => T, +): T { + return useSyncExternalStore(manager.subscribe.bind(manager), () => + selector(manager.getState()), + ); } diff --git a/src/stateManager/AudioManager.ts b/src/stateManager/AudioManager.ts index 7d7d418..5049dd6 100644 --- a/src/stateManager/AudioManager.ts +++ b/src/stateManager/AudioManager.ts @@ -1,5 +1,8 @@ export class AudioManager { private static _instance: AudioManager | null = null; + private readonly _audioPools = new Map(); + + private static readonly MAX_POOL_SIZE_PER_SOUND = 6; static getInstance(): AudioManager { if (!AudioManager._instance) { @@ -12,12 +15,47 @@ export class AudioManager { private constructor() {} playSound(path: string, volume = 1): void { - const audio = new Audio(path); + const audio = this._acquireAudio(path); audio.volume = Math.max(0, Math.min(1, volume)); - void audio.play(); + audio.currentTime = 0; + + void audio.play().catch(() => { + audio.pause(); + audio.currentTime = 0; + }); } destroy(): void { + this._audioPools.forEach((pool) => { + pool.forEach((audio) => { + audio.pause(); + audio.src = ""; + }); + }); + this._audioPools.clear(); AudioManager._instance = null; } + + private _acquireAudio(path: string): HTMLAudioElement { + const existingPool = this._audioPools.get(path); + + if (existingPool) { + const availableAudio = existingPool.find( + (audio) => audio.paused || audio.ended, + ); + if (availableAudio) return availableAudio; + + if (existingPool.length < AudioManager.MAX_POOL_SIZE_PER_SOUND) { + const pooledAudio = new Audio(path); + existingPool.push(pooledAudio); + return pooledAudio; + } + + return existingPool[0]!; + } + + const initialAudio = new Audio(path); + this._audioPools.set(path, [initialAudio]); + return initialAudio; + } } diff --git a/src/stateManager/InteractionManager.ts b/src/stateManager/InteractionManager.ts index 467a58c..1573997 100644 --- a/src/stateManager/InteractionManager.ts +++ b/src/stateManager/InteractionManager.ts @@ -39,12 +39,8 @@ export class InteractionManager { setFocused(handle: InteractableHandle | null): void { if (this._focused === handle) return; - // Never interrupt an active grab via focus change - if (this._holding) { - this._focused = handle; - this._emit(); - return; - } + if (this._holding) return; + this._focused = handle; this._emit(); } @@ -59,7 +55,7 @@ export class InteractionManager { } releaseInteract(): void { - const handle = this._holdingHandle ?? this._focused; + const handle = this._holding ? this._holdingHandle : null; if (!handle) return; handle.onRelease(); @@ -77,6 +73,9 @@ export class InteractionManager { } destroy(): void { + this._focused = null; + this._holding = false; + this._holdingHandle = null; this._listeners.clear(); InteractionManager._instance = null; } diff --git a/src/utils/debug/Debug.ts b/src/utils/debug/Debug.ts index ba98a2a..4860a23 100644 --- a/src/utils/debug/Debug.ts +++ b/src/utils/debug/Debug.ts @@ -7,7 +7,7 @@ export class Debug { public readonly active: boolean; private readonly gui: GUI | null; private readonly folders = new Map(); - private readonly registeredFolders = new Set(); + private readonly folderRefCounts = new Map(); private readonly listeners = new Set<() => void>(); private readonly controls: { cameraMode: CameraMode; @@ -63,27 +63,41 @@ export class Debug { } /** - * Creates a named GUI folder. Returns the folder on first call, null on - * subsequent calls with the same name — callers should skip `.add()` when - * null is returned to avoid duplicating controls under StrictMode double-mount. + * Acquires a named GUI folder. Returns the folder on first acquisition and null + * on subsequent acquisitions so callers only register controls once. */ createFolder(name: string): GUI | null { if (!this.gui) return null; - if (this.registeredFolders.has(name)) return null; - - this.registeredFolders.add(name); - const existing = this.folders.get(name); - if (existing) return existing; + if (existing) { + this.folderRefCounts.set(name, (this.folderRefCounts.get(name) ?? 0) + 1); + return null; + } const folder = this.gui.addFolder(name); this.folders.set(name, folder); + this.folderRefCounts.set(name, 1); return folder; } + destroyFolder(name: string): void { + const folder = this.folders.get(name); + const refCount = this.folderRefCounts.get(name); + if (!folder || refCount === undefined) return; + + if (refCount > 1) { + this.folderRefCounts.set(name, refCount - 1); + return; + } + + folder.destroy(); + this.folders.delete(name); + this.folderRefCounts.delete(name); + } + subscribe(listener: () => void): () => void { this.listeners.add(listener); diff --git a/src/utils/debug/scene/DebugCameraControls.tsx b/src/utils/debug/scene/DebugCameraControls.tsx index 85977a0..04efd92 100644 --- a/src/utils/debug/scene/DebugCameraControls.tsx +++ b/src/utils/debug/scene/DebugCameraControls.tsx @@ -1,13 +1,23 @@ import { OrbitControls } from "@react-three/drei"; +import { + DEBUG_CAMERA_DAMPING_FACTOR, + DEBUG_CAMERA_MAX_DISTANCE, + DEBUG_CAMERA_MIN_DISTANCE, +} from "@/data/debugConfig"; +import { + PLAYER_EYE_HEIGHT, + PLAYER_SPAWN_X, + PLAYER_SPAWN_Z, +} from "@/data/playerConfig"; export function DebugCameraControls(): React.JSX.Element { return ( ); } diff --git a/src/utils/debug/scene/DebugHelpers.tsx b/src/utils/debug/scene/DebugHelpers.tsx index 5abf9a9..738c46e 100644 --- a/src/utils/debug/scene/DebugHelpers.tsx +++ b/src/utils/debug/scene/DebugHelpers.tsx @@ -1,3 +1,11 @@ +import { + DEBUG_AXES_SIZE, + DEBUG_GRID_DIVISIONS, + DEBUG_GRID_PRIMARY_COLOR, + DEBUG_GRID_SECONDARY_COLOR, + DEBUG_GRID_SIZE, + DEBUG_GRID_Y, +} from "@/data/debugConfig"; import { Debug } from "@/utils/debug/Debug"; export function DebugHelpers(): React.JSX.Element | null { @@ -10,10 +18,15 @@ export function DebugHelpers(): React.JSX.Element | null { return ( <> - + ); } diff --git a/src/world/Environment.tsx b/src/world/Environment.tsx index b314bf4..72c12b6 100644 --- a/src/world/Environment.tsx +++ b/src/world/Environment.tsx @@ -1,17 +1,10 @@ -import * as THREE from "three"; -import { useLoader } from "@react-three/fiber"; +import { Environment as DreiEnvironment } from "@react-three/drei"; import { + GAME_SCENE_SKYBOX_PATH, PHYSICS_SCENE_BACKGROUND_COLOR, - SKYBOX_FACES, } from "@/data/environmentConfig"; import { useSceneMode } from "@/hooks/debug/useSceneMode"; -function SkyBox(): React.JSX.Element { - const texture = useLoader(THREE.CubeTextureLoader, [...SKYBOX_FACES]); - - return ; -} - export function Environment(): React.JSX.Element { const sceneMode = useSceneMode(); @@ -21,5 +14,5 @@ export function Environment(): React.JSX.Element { ); } - return ; + return ; }