hore(review): tighten pre-merge audit cleanup
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled

This commit is contained in:
Tom Boullay
2026-05-29 01:34:10 +02:00
parent 093ffd726d
commit 95ca1bbfde
12 changed files with 69 additions and 29 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ These vegetation and crop assets account for almost all of the current `~69M` tr
## Debug Performance Controls ## Debug Performance Controls
The next useful runtime tool is a debug-only performance folder that can isolate model families. This should be mounted only when `?debug` is enabled. The debug-only performance folder can isolate model families when `?debug` is enabled.
Proposed controls: Proposed controls:
+6 -7
View File
@@ -6,8 +6,12 @@ import * as THREE from "three";
import type { OrbitControls as OrbitControlsImpl } from "three-stdlib"; import type { OrbitControls as OrbitControlsImpl } from "three-stdlib";
import { EditorMap } from "@/components/editor/scene/EditorMap"; import { EditorMap } from "@/components/editor/scene/EditorMap";
import { FlyController } from "@/controls/editor/FlyController"; import { FlyController } from "@/controls/editor/FlyController";
import type { CinematicDefinition } from "@/types/cinematics/cinematics"; import type {
import type { MapNode, TransformMode, SceneData } from "@/types/editor/editor"; EditorCinematicPreviewRequest,
MapNode,
TransformMode,
SceneData,
} from "@/types/editor/editor";
const EDITOR_CAMERA_HOME_POSITION = new THREE.Vector3(0, 50, 100); const EDITOR_CAMERA_HOME_POSITION = new THREE.Vector3(0, 50, 100);
const EDITOR_CAMERA_HOME_TARGET = new THREE.Vector3(0, 0, 0); const EDITOR_CAMERA_HOME_TARGET = new THREE.Vector3(0, 0, 0);
@@ -23,11 +27,6 @@ function isEditableShortcutTarget(target: EventTarget | null): boolean {
); );
} }
export interface EditorCinematicPreviewRequest {
id: string;
cinematic: CinematicDefinition;
}
interface EditorSceneProps { interface EditorSceneProps {
sceneData: SceneData; sceneData: SceneData;
selectedNodeIndex: number | null; selectedNodeIndex: number | null;
+26 -2
View File
@@ -3,6 +3,7 @@ import { useGLTF } from "@react-three/drei";
import { Component, useEffect, useMemo, useRef, type ReactNode } from "react"; import { Component, useEffect, useMemo, useRef, type ReactNode } from "react";
import * as THREE from "three"; import * as THREE from "three";
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF"; import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
import { logger } from "@/utils/core/Logger";
interface SkyModelProps { interface SkyModelProps {
fallbackModelScale?: number | undefined; fallbackModelScale?: number | undefined;
@@ -20,6 +21,8 @@ interface SkyModelContentProps {
interface SkyModelErrorBoundaryProps { interface SkyModelErrorBoundaryProps {
children: ReactNode; children: ReactNode;
fallback: ReactNode; fallback: ReactNode;
label: string;
modelPath: string;
} }
interface SkyModelErrorBoundaryState { interface SkyModelErrorBoundaryState {
@@ -43,6 +46,17 @@ class SkyModelErrorBoundary extends Component<
return { hasError: true }; return { hasError: true };
} }
componentDidCatch(error: Error): void {
logger.warn(
"SkyModel",
`${this.props.label} model failed; using fallback`,
{
error,
modelPath: this.props.modelPath,
},
);
}
render(): ReactNode { render(): ReactNode {
if (this.state.hasError) { if (this.state.hasError) {
return this.props.fallback; return this.props.fallback;
@@ -63,7 +77,12 @@ export function SkyModel({
<color attach="background" args={[fallbackColor]} /> <color attach="background" args={[fallbackColor]} />
) : null; ) : null;
const fallback = fallbackModelPath ? ( const fallback = fallbackModelPath ? (
<SkyModelErrorBoundary key={fallbackModelPath} fallback={colorFallback}> <SkyModelErrorBoundary
key={fallbackModelPath}
fallback={colorFallback}
label="Fallback sky"
modelPath={fallbackModelPath}
>
<SkyModelContent <SkyModelContent
modelPath={fallbackModelPath} modelPath={fallbackModelPath}
scale={fallbackModelScale} scale={fallbackModelScale}
@@ -74,7 +93,12 @@ export function SkyModel({
); );
return ( return (
<SkyModelErrorBoundary key={modelPath} fallback={fallback}> <SkyModelErrorBoundary
key={modelPath}
fallback={fallback}
label="Primary sky"
modelPath={modelPath}
>
<SkyModelContent modelPath={modelPath} scale={scale} /> <SkyModelContent modelPath={modelPath} scale={scale} />
</SkyModelErrorBoundary> </SkyModelErrorBoundary>
); );
+1 -1
View File
@@ -2,8 +2,8 @@ import type {
MissionStep, MissionStep,
RepairMissionId, RepairMissionId,
} from "@/types/gameplay/repairMission"; } from "@/types/gameplay/repairMission";
import { REPAIR_MISSION_IDS } from "@/types/gameplay/repairMission";
const REPAIR_MISSION_IDS = ["ebike", "pylon", "farm"] as const;
const REPAIR_MISSION_ID_VALUES: ReadonlySet<string> = new Set( const REPAIR_MISSION_ID_VALUES: ReadonlySet<string> = new Set(
REPAIR_MISSION_IDS, REPAIR_MISSION_IDS,
); );
+6
View File
@@ -83,6 +83,12 @@ export const VEGETATION_TYPE_KEYS = [
export type VegetationType = (typeof VEGETATION_TYPE_KEYS)[number]; export type VegetationType = (typeof VEGETATION_TYPE_KEYS)[number];
export const VEGETATION_MAP_NODE_NAMES: ReadonlySet<string> = new Set(
Object.values(VEGETATION_TYPES)
.filter((config) => config.enabled)
.map((config) => config.mapName),
);
export function getVegetationModelScaleMultiplier(name: string): number { export function getVegetationModelScaleMultiplier(name: string): number {
return ( return (
Object.values(VEGETATION_TYPES).find((config) => config.mapName === name) Object.values(VEGETATION_TYPES).find((config) => config.mapName === name)
+6 -3
View File
@@ -2,13 +2,16 @@ import { useCallback, useEffect, useState } from "react";
import { Canvas, useThree } from "@react-three/fiber"; import { Canvas, useThree } from "@react-three/fiber";
import { EditorControls } from "@/components/editor/EditorControls"; import { EditorControls } from "@/components/editor/EditorControls";
import { EditorScene } from "@/components/editor/scene/EditorScene"; import { EditorScene } from "@/components/editor/scene/EditorScene";
import type { EditorCinematicPreviewRequest } from "@/components/editor/scene/EditorScene";
import { SceneLoadingOverlay } from "@/components/ui/SceneLoadingOverlay"; import { SceneLoadingOverlay } from "@/components/ui/SceneLoadingOverlay";
import { Subtitles } from "@/components/ui/Subtitles"; import { Subtitles } from "@/components/ui/Subtitles";
import { useEditorHistory } from "@/hooks/editor/useEditorHistory"; import { useEditorHistory } from "@/hooks/editor/useEditorHistory";
import type { CinematicDefinition } from "@/types/cinematics/cinematics"; import type { CinematicDefinition } from "@/types/cinematics/cinematics";
import { useEditorSceneData } from "@/hooks/editor/useEditorSceneData"; import { useEditorSceneData } from "@/hooks/editor/useEditorSceneData";
import type { MapNode, TransformMode } from "@/types/editor/editor"; import type {
EditorCinematicPreviewRequest,
MapNode,
TransformMode,
} from "@/types/editor/editor";
import type { SceneLoadingState } from "@/types/world/sceneLoading"; import type { SceneLoadingState } from "@/types/world/sceneLoading";
import { logger } from "@/utils/core/Logger"; import { logger } from "@/utils/core/Logger";
import { import {
@@ -82,7 +85,7 @@ export function EditorPage(): React.JSX.Element {
); );
const editorLoadingState: SceneLoadingState = isMapLoading const editorLoadingState: SceneLoadingState = isMapLoading
? { ? {
currentStep: "Récupération blocking", currentStep: "Chargement de la carte",
progress: 0.08, progress: 0.08,
status: "loading" as const, status: "loading" as const,
} }
+7
View File
@@ -1,3 +1,5 @@
import type { CinematicDefinition } from "@/types/cinematics/cinematics";
export type { export type {
HierarchicalMapNode, HierarchicalMapNode,
MapNode, MapNode,
@@ -5,3 +7,8 @@ export type {
} from "@/types/map/mapScene"; } from "@/types/map/mapScene";
export type TransformMode = "translate" | "rotate" | "scale"; export type TransformMode = "translate" | "rotate" | "scale";
export interface EditorCinematicPreviewRequest {
id: string;
cinematic: CinematicDefinition;
}
+2 -1
View File
@@ -1,4 +1,5 @@
import type { Vector3Tuple } from "@/types/three/three"; import type { Vector3Tuple } from "@/types/three/three";
import type { RepairMissionId } from "@/types/gameplay/repairMission";
export type GameStep = export type GameStep =
| "intro" | "intro"
@@ -12,7 +13,7 @@ export type GameStep =
| "manipulation" | "manipulation"
| "outOfFabrik"; | "outOfFabrik";
export type MainGameState = "intro" | "ebike" | "pylon" | "farm" | "outro"; export type MainGameState = "intro" | RepairMissionId | "outro";
export interface Zone { export interface Zone {
id: string; id: string;
+3 -1
View File
@@ -4,7 +4,9 @@ import type {
Vector3Tuple, Vector3Tuple,
} from "@/types/three/three"; } from "@/types/three/three";
export type RepairMissionId = "ebike" | "pylon" | "farm"; export const REPAIR_MISSION_IDS = ["ebike", "pylon", "farm"] as const;
export type RepairMissionId = (typeof REPAIR_MISSION_IDS)[number];
export interface RepairMissionTriggerConfig { export interface RepairMissionTriggerConfig {
mission: RepairMissionId; mission: RepairMissionId;
+7 -1
View File
@@ -1,3 +1,5 @@
import { logger } from "@/utils/core/Logger";
const DEBUG_GAME_STATE_COOKIE_NAME = "la-fabrik-debug-game-state"; const DEBUG_GAME_STATE_COOKIE_NAME = "la-fabrik-debug-game-state";
const DEBUG_GAME_STATE_COOKIE_MAX_AGE = 60 * 60 * 24 * 30; const DEBUG_GAME_STATE_COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
@@ -18,7 +20,11 @@ export function readDebugGameStateCookie(): unknown {
try { try {
return JSON.parse(decodeURIComponent(value)); return JSON.parse(decodeURIComponent(value));
} catch { } catch (error) {
logger.warn("DebugGameState", "Invalid debug game state cookie cleared", {
error: error instanceof Error ? error : String(error),
});
clearDebugGameStateCookie();
return null; return null;
} }
} }
+2 -10
View File
@@ -1,16 +1,8 @@
import type { MapNode } from "@/types/map/mapScene"; import type { MapNode } from "@/types/map/mapScene";
import { VEGETATION_MAP_NODE_NAMES } from "@/data/world/vegetationConfig";
import { isInstancedMapNodeName } from "@/utils/map/isInstancedMapNodeName"; import { isInstancedMapNodeName } from "@/utils/map/isInstancedMapNodeName";
const MAP_STRUCTURE_NODE_NAMES = new Set(["Scene", "blocking", "terrain"]); const MAP_STRUCTURE_NODE_NAMES = new Set(["Scene", "blocking", "terrain"]);
const RUNTIME_VEGETATION_NODE_NAMES = new Set([
"arbre",
"buisson",
"champdeble",
"champdesoja",
"champsdetournesol",
"potager",
"sapin",
]);
function isRuntimeStructureMapNode(name: string): boolean { function isRuntimeStructureMapNode(name: string): boolean {
return MAP_STRUCTURE_NODE_NAMES.has(name); return MAP_STRUCTURE_NODE_NAMES.has(name);
@@ -26,7 +18,7 @@ export function isRuntimeSingleMapNode(node: MapNode): boolean {
} }
return ( return (
!RUNTIME_VEGETATION_NODE_NAMES.has(node.name) && !VEGETATION_MAP_NODE_NAMES.has(node.name) &&
!isInstancedMapNodeName(node.name) !isInstancedMapNodeName(node.name)
); );
} }
+2 -2
View File
@@ -148,7 +148,7 @@ export function GameMap({
useEffect(() => { useEffect(() => {
onLoadingStateChange?.({ onLoadingStateChange?.({
currentStep: "Récupération blocking", currentStep: "Chargement de la carte",
progress: 0.05, progress: 0.05,
status: "loading", status: "loading",
}); });
@@ -163,7 +163,7 @@ export function GameMap({
} }
onLoadingStateChange?.({ onLoadingStateChange?.({
currentStep: "Importation des models", currentStep: "Importation des modèles",
progress: 0.18, progress: 0.18,
status: "loading", status: "loading",
}); });