refactor: clean architecture and remove unused code

This commit is contained in:
Tom Boullay
2026-04-30 13:33:28 +02:00
parent b1187b68ae
commit cfb1eaf39a
30 changed files with 303 additions and 696 deletions
+6 -6
View File
@@ -1,8 +1,9 @@
import { useMemo, useRef, useEffect, useState } from "react";
import { useRef, useEffect, useState } from "react";
import { Grid, TransformControls, useGLTF } from "@react-three/drei";
import type { ThreeEvent } from "@react-three/fiber";
import * as THREE from "three";
import { useClonedObject } from "@/hooks/three/useClonedObject";
import type { SceneData, MapNode, TransformMode } from "@/types/editor/editor";
interface EditorMapProps {
@@ -138,7 +139,7 @@ export function EditorMap({
const objectsMapRef = useRef<Map<number, THREE.Object3D>>(new Map());
const handleTransformMouseDown = () => {
onTransformStart?.();
onTransformStart();
};
const handleTransformMouseUp = () => {
@@ -153,10 +154,10 @@ export function EditorMap({
rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z],
scale: [obj.scale.x, obj.scale.y, obj.scale.z],
};
onNodeTransform?.(selectedNodeIndex, updatedNode);
onNodeTransform(selectedNodeIndex, updatedNode);
}
}
onTransformEnd?.();
onTransformEnd();
};
const [selectedObject, setSelectedObject] = useState<THREE.Object3D | null>(
@@ -258,8 +259,7 @@ function EditorModelNode({
new Map<THREE.Mesh, THREE.Material | THREE.Material[]>(),
);
const { scene } = useGLTF(modelUrl);
const sceneInstance = useMemo(() => scene.clone(true), [scene]);
const sceneInstance = useClonedObject(scene);
const pointerHandlers = createEditorNodePointerHandlers(
index,
onSelectNode,
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef } from "react";
import { useEffect, useRef } from "react";
import { useGLTF } from "@react-three/drei";
import { useFrame, useThree } from "@react-three/fiber";
import gsap from "gsap";
@@ -15,14 +15,13 @@ import {
REPAIR_CASE_ROTATION_AMPLITUDE_DEGREES,
REPAIR_CASE_ROTATION_RESET_SPEED,
} from "@/data/gameplay/repairCaseConfig";
import type { Vector3Tuple } from "@/types/three/three";
import { useClonedObject } from "@/hooks/three/useClonedObject";
import type { ModelTransformProps } from "@/types/three/three";
import { toVector3Scale } from "@/utils/three/scale";
interface RepairCaseModelProps {
interface RepairCaseModelProps extends ModelTransformProps {
modelPath: string;
open: boolean;
position?: Vector3Tuple;
rotation?: Vector3Tuple;
scale?: number | Vector3Tuple;
}
const CASE_CLOSED_ROTATION_OFFSET_Z = THREE.MathUtils.degToRad(
@@ -44,7 +43,7 @@ export function RepairCaseModel({
}: RepairCaseModelProps): React.JSX.Element {
const camera = useThree((state) => state.camera);
const { scene } = useGLTF(modelPath);
const model = useMemo(() => scene.clone(true), [scene]);
const model = useClonedObject(scene);
const groupRef = useRef<THREE.Group>(null);
const lidRef = useRef<THREE.Object3D | null>(null);
const worldPosition = useRef(new THREE.Vector3());
@@ -53,8 +52,7 @@ export function RepairCaseModel({
const phase = useRef({ x: 0, y: 0, z: 0 });
const initialOpen = useRef(open);
const openedRotationZ = useRef(0);
const parsedScale =
typeof scale === "number" ? ([scale, scale, scale] as Vector3Tuple) : scale;
const parsedScale = toVector3Scale(scale);
useEffect(() => {
phase.current = {
@@ -1,7 +1,8 @@
import { useMemo, useState } from "react";
import { useState } from "react";
import { useGLTF } from "@react-three/drei";
import { RigidBody } from "@react-three/rapier";
import { InteractableObject } from "@/components/three/interaction/InteractableObject";
import { useClonedObject } from "@/hooks/three/useClonedObject";
import {
TRIGGER_DEFAULT_COLLIDERS,
TRIGGER_DEFAULT_LABEL,
@@ -38,7 +39,7 @@ function SpawnedModelInstance({
position: Vector3Tuple;
}): React.JSX.Element {
const { scene } = useGLTF(path);
const model = useMemo(() => scene.clone(true), [scene]);
const model = useClonedObject(scene);
return <primitive object={model} position={position} />;
}
+13 -15
View File
@@ -2,12 +2,14 @@ import type { ReactNode } from "react";
import { Component, useEffect, useMemo } from "react";
import { useFrame } from "@react-three/fiber";
import { useGLTF } from "@react-three/drei";
import { useClonedObject } from "@/hooks/three/useClonedObject";
import { ExplodedModel } from "@/utils/three/ExplodedModel";
import type { Vector3Tuple } from "@/types/three/three";
import type { ModelTransformProps, Vector3Tuple } from "@/types/three/three";
import { toVector3Scale } from "@/utils/three/scale";
interface ModelErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode;
position?: Vector3Tuple | undefined;
}
interface ModelErrorBoundaryState {
@@ -32,17 +34,17 @@ class ModelErrorBoundary extends Component<
}
render(): ReactNode {
if (this.state.hasError) return this.props.fallback ?? null;
if (this.state.hasError) {
return <MissingModelFallback position={this.props.position} />;
}
return this.props.children;
}
}
interface ExplodableModelInnerProps {
interface ExplodableModelInnerProps extends ModelTransformProps {
modelPath: string;
split: boolean;
position?: Vector3Tuple;
rotation?: Vector3Tuple;
scale?: number | Vector3Tuple;
splitDistance?: number;
}
@@ -50,10 +52,7 @@ export function ExplodableModel(
props: ExplodableModelInnerProps,
): React.JSX.Element {
return (
<ModelErrorBoundary
key={props.modelPath}
fallback={<MissingModelFallback position={props.position ?? [0, 0, 0]} />}
>
<ModelErrorBoundary key={props.modelPath} position={props.position}>
<ExplodableModelInner {...props} />
</ModelErrorBoundary>
);
@@ -68,13 +67,12 @@ function ExplodableModelInner({
splitDistance = 1.2,
}: ExplodableModelInnerProps): React.JSX.Element {
const { scene } = useGLTF(modelPath);
const model = useMemo(() => scene.clone(true), [scene]);
const model = useClonedObject(scene);
const explodedModel = useMemo(
() => new ExplodedModel(model, { distance: splitDistance }),
[model, splitDistance],
);
const parsedScale =
typeof scale === "number" ? ([scale, scale, scale] as Vector3Tuple) : scale;
const parsedScale = toVector3Scale(scale);
useEffect(() => {
explodedModel.setSplit(split);
@@ -94,7 +92,7 @@ function ExplodableModelInner({
function MissingModelFallback({
position = [0, 0, 0],
}: {
position?: Vector3Tuple;
position?: Vector3Tuple | undefined;
}): React.JSX.Element {
return (
<mesh position={position}>
+3 -2
View File
@@ -1,7 +1,8 @@
import { useFrame, useThree } from "@react-three/fiber";
import { useGLTF } from "@react-three/drei";
import { useMemo, useRef } from "react";
import { useRef } from "react";
import * as THREE from "three";
import { useClonedObject } from "@/hooks/three/useClonedObject";
interface SkyModelProps {
modelPath: string;
@@ -13,7 +14,7 @@ export function SkyModel({ modelPath }: SkyModelProps): React.JSX.Element {
const camera = useThree((state) => state.camera);
const groupRef = useRef<THREE.Group>(null);
const { scene } = useGLTF(modelPath);
const model = useMemo(() => scene.clone(true), [scene]);
const model = useClonedObject(scene);
useFrame(() => {
groupRef.current?.position.copy(camera.position);