diff --git a/src/data/world/fogConfig.ts b/src/data/world/fogConfig.ts index 7df1d7e..67a017c 100644 --- a/src/data/world/fogConfig.ts +++ b/src/data/world/fogConfig.ts @@ -2,7 +2,7 @@ import { TERRAIN_COLORS } from "@/data/world/terrainConfig"; export const FOG_CONFIG = { enabled: true, - color: "#eef3f5", + color: "#dce8df", near: 38, far: 45, }; diff --git a/src/utils/debug/Debug.ts b/src/utils/debug/Debug.ts index 1204442..fab6c24 100644 --- a/src/utils/debug/Debug.ts +++ b/src/utils/debug/Debug.ts @@ -1,6 +1,7 @@ import GUI from "lil-gui"; import type { CameraMode, SceneMode } from "@/types/debug/debug"; import type { HandTrackingSource } from "@/types/handTracking/handTracking"; +import { FOG_CONFIG } from "@/data/world/fogConfig"; import { EventEmitter } from "@/utils/core/EventEmitter"; import { isDebugEnabled } from "@/utils/debug/isDebugEnabled"; @@ -15,6 +16,15 @@ interface DebugEvents { change: void; } +const DEBUG_FOLDER_ORDER = [ + "La Fabrik", + "Lighting", + "Game", + "Interaction", + "Hand Tracking", + "Performance / Map", +] as const; + function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } @@ -58,6 +68,7 @@ export class Debug { private readonly folderRefCounts = new Map(); private readonly controls: { cameraMode: CameraMode; + fogEnabled: boolean; handTrackingSource: HandTrackingSource; showDebugOverlay: boolean; showHandTrackingSvg: boolean; @@ -80,7 +91,8 @@ export class Debug { this.controls = { cameraMode: storedControls.cameraMode ?? "player", - handTrackingSource: "backend", + fogEnabled: FOG_CONFIG.enabled, + handTrackingSource: "browser", showDebugOverlay: true, showHandTrackingSvg: false, showInteractionSpheres: false, @@ -88,10 +100,10 @@ export class Debug { sceneMode: storedControls.sceneMode ?? "game", }; - this.gui = this.active ? new GUI({ title: "La-Fabrik Debug" }) : null; + this.gui = this.active ? new GUI({ title: "Debug" }) : null; if (this.gui) { - const folder = this.createFolder("Debug"); + const folder = this.createFolder("La Fabrik", { open: true }); if (!folder) return; @@ -127,6 +139,14 @@ export class Debug { this.emit(); }); + folder + .add(this.controls, "fogEnabled") + .name("Fog") + .onChange((value: boolean) => { + this.controls.fogEnabled = value; + this.emit(); + }); + const handTrackingFolder = this.createFolder("Hand Tracking"); handTrackingFolder @@ -139,8 +159,8 @@ export class Debug { handTrackingFolder ?.add(this.controls, "handTrackingSource", { - Backend: "backend", "Browser JS": "browser", + Backend: "backend", }) .name("Source") .onChange((value: HandTrackingSource) => { @@ -154,7 +174,7 @@ export class Debug { * 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 { + createFolder(name: string, options?: { open?: boolean }): GUI | null { if (!this.gui) return null; const existing = this.folders.get(name); @@ -167,6 +187,13 @@ export class Debug { const folder = this.gui.addFolder(name); this.folders.set(name, folder); this.folderRefCounts.set(name, 1); + this.sortFolders(); + + if (options?.open) { + folder.open(); + } else { + folder.close(); + } return folder; } @@ -206,6 +233,10 @@ export class Debug { return this.controls.handTrackingSource; } + getFogEnabled(): boolean { + return this.controls.fogEnabled; + } + getShowInteractionSpheres(): boolean { return this.controls.showInteractionSpheres; } @@ -247,4 +278,29 @@ export class Debug { this.emit(); } + + private sortFolders(): void { + if (!this.gui) return; + + const rootElement = this.gui.domElement.querySelector(".children"); + if (!rootElement) return; + + const orderedFolders = [...this.folders.entries()].sort(([a], [b]) => { + const aIndex = DEBUG_FOLDER_ORDER.indexOf( + a as (typeof DEBUG_FOLDER_ORDER)[number], + ); + const bIndex = DEBUG_FOLDER_ORDER.indexOf( + b as (typeof DEBUG_FOLDER_ORDER)[number], + ); + const safeAIndex = aIndex === -1 ? DEBUG_FOLDER_ORDER.length : aIndex; + const safeBIndex = bIndex === -1 ? DEBUG_FOLDER_ORDER.length : bIndex; + + if (safeAIndex !== safeBIndex) return safeAIndex - safeBIndex; + return a.localeCompare(b); + }); + + for (const [, folder] of orderedFolders) { + rootElement.appendChild(folder.domElement); + } + } } diff --git a/src/world/Environment.tsx b/src/world/Environment.tsx index db7a280..e789104 100644 --- a/src/world/Environment.tsx +++ b/src/world/Environment.tsx @@ -14,10 +14,12 @@ import { useMapPerformanceStore, } from "@/managers/stores/useMapPerformanceStore"; import { SkyModel } from "@/components/three/world/SkyModel"; +import { useDebugStore } from "@/hooks/debug/useDebugStore"; export function Environment(): React.JSX.Element { const cameraMode = useCameraMode(); const sceneMode = useSceneMode(); + const fogEnabled = useDebugStore((debug) => debug.getFogEnabled()); const groups = useMapPerformanceStore((state) => state.groups); const models = useMapPerformanceStore((state) => state.models); const showSky = isMapModelVisible("sky", { groups, models }); @@ -30,7 +32,10 @@ export function Environment(): React.JSX.Element { return ( <> - {FOG_CONFIG.enabled && sceneMode === "game" && cameraMode === "player" ? ( + {FOG_CONFIG.enabled && + fogEnabled && + sceneMode === "game" && + cameraMode === "player" ? (