Merge branch 'develop' into feat/polish-mission1
🔍 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-06-01 00:15:46 +02:00
1075 changed files with 1242 additions and 1722 deletions
+12 -6
View File
@@ -92,6 +92,12 @@ export const docGroups: DocGroup[] = [
subtitle: "Draw calls, triangles, and streaming",
meta: "13",
},
{
path: "/docs/map-lod",
title: "Map LOD System",
subtitle: "Presets, paths, and model workflow",
meta: "14",
},
],
},
{
@@ -101,31 +107,31 @@ export const docGroups: DocGroup[] = [
path: "/docs/features",
title: "Features",
subtitle: "Implemented scope",
meta: "14",
meta: "15",
},
{
path: "/docs/main-feature",
title: "Main Feature",
subtitle: "Repair-game prototype",
meta: "15",
meta: "16",
},
{
path: "/docs/editor",
title: "Editor User Guide",
subtitle: "Editing workflow",
meta: "16",
meta: "17",
},
{
path: "/docs/animation",
title: "Animation & 3D Model System",
subtitle: "Components and usage",
meta: "17",
meta: "18",
},
{
path: "/docs/gallery",
title: "Model Gallery",
subtitle: "Browsing 3D assets",
meta: "18",
meta: "19",
},
],
},
@@ -136,7 +142,7 @@ export const docGroups: DocGroup[] = [
path: "/docs/code-review",
title: "Code Review Prep",
subtitle: "Presentation support",
meta: "19",
meta: "20",
},
],
},
+1 -1
View File
@@ -101,7 +101,7 @@ export const galleryModels: GalleryModel[] = [
path: "/models/habitant2-animated/model.gltf",
},
{ id: "immeuble1", name: "Immeuble", path: "/models/immeuble1/model.gltf" },
{ id: "lafabrik", name: "La Fabrik", path: "/models/lafabrik/model.gltf" },
{ id: "lafabrik", name: "La Fabrik", path: "/models/lafabrik/model.glb" },
{ id: "maison1", name: "Maison", path: "/models/maison1/model.gltf" },
{
id: "packderelance",
+81 -6
View File
@@ -1,6 +1,15 @@
import type { Vector3Tuple } from "@/types/three/three";
export type CharacterId = "electricienne" | "gerant" | "fermier";
export type CharacterId =
| "electricienne"
| "gerant"
| "fermier"
| "zone1_habitant1"
| "zone1_habitant2"
| "zone2_habitant1"
| "zone2_habitant2"
| "zone3_habitant1"
| "zone3_habitant2";
export interface CharacterConfig {
id: CharacterId;
@@ -21,7 +30,7 @@ export const CHARACTER_CONFIGS = {
modelPath: "/models/electricienne-animated/model.gltf",
position: [-40.5, 0, 45.5],
rotation: [0, -0.35, 0],
scale: [1, 1, 1],
scale: [1.55, 1.55, 1.55],
animations: ["Dance"],
defaultAnimation: "Dance",
},
@@ -29,9 +38,9 @@ export const CHARACTER_CONFIGS = {
id: "gerant",
label: "Gerant",
modelPath: "/models/gerant-animated/model.gltf",
position: [59.5, 6.3, 64.64],
rotation: [0, 2.41, 0],
scale: [1, 1, 1],
position: [58, 0, 62.5],
rotation: [0, 1.83, 0],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
snapToTerrain: false,
@@ -42,7 +51,67 @@ export const CHARACTER_CONFIGS = {
modelPath: "/models/fermier-animated/model.gltf",
position: [-6.5, 0, -69.5],
rotation: [0, -1.18, 0],
scale: [1, 1, 1],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
},
zone1_habitant1: {
id: "zone1_habitant1",
label: "Zone 1 - Habitant 1",
modelPath: "/models/habitant1-animated/model.gltf",
position: [-43.64, 0, -16.72],
rotation: [0, -1.23, 0],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
},
zone1_habitant2: {
id: "zone1_habitant2",
label: "Zone 1 - Habitant 2",
modelPath: "/models/habitant2-animated/model.gltf",
position: [-43.46, 0, -4.93],
rotation: [0, -2.42, 0],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
},
zone2_habitant1: {
id: "zone2_habitant1",
label: "Zone 2 - Habitant 1",
modelPath: "/models/habitant1-animated/model.gltf",
position: [-3.41, 0, 73.01],
rotation: [0, 1.97, 0],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
},
zone2_habitant2: {
id: "zone2_habitant2",
label: "Zone 2 - Habitant 2",
modelPath: "/models/habitant2-animated/model.gltf",
position: [-2.22, 0, 60.59],
rotation: [0, 0.86, 0],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
},
zone3_habitant1: {
id: "zone3_habitant1",
label: "Zone 3 - Habitant 1",
modelPath: "/models/habitant1-animated/model.gltf",
position: [82.52, 0, -29.01],
rotation: [0, -0.89, 0],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
},
zone3_habitant2: {
id: "zone3_habitant2",
label: "Zone 3 - Habitant 2",
modelPath: "/models/habitant2-animated/model.gltf",
position: [92.95, 0, -18.1],
rotation: [0, -1.59, 0],
scale: [1.55, 1.55, 1.55],
animations: ["idle", "walk"],
defaultAnimation: "idle",
},
@@ -52,4 +121,10 @@ export const CHARACTER_IDS = [
"electricienne",
"gerant",
"fermier",
"zone1_habitant1",
"zone1_habitant2",
"zone2_habitant1",
"zone2_habitant2",
"zone3_habitant1",
"zone3_habitant2",
] as const satisfies readonly CharacterId[];
+51
View File
@@ -1,4 +1,55 @@
import { CHUNK_CONFIG } from "@/data/world/chunkStreamingConfig";
export const GRAPHICS_PRESET_KEYS = ["low", "medium", "high", "ultra"] as const;
export type GraphicsPreset = (typeof GRAPHICS_PRESET_KEYS)[number];
export interface GraphicsPresetConfig {
chunkLoadRadius: number;
chunkUnloadRadius: number;
fogEnabled: boolean;
forceLodModels: boolean;
label: string;
lodHighDetailDistance: number;
}
export const GRAPHICS_PRESETS = {
low: {
label: "Basse",
chunkLoadRadius: 10,
chunkUnloadRadius: 18,
fogEnabled: true,
forceLodModels: true,
lodHighDetailDistance: 0,
},
medium: {
label: "Moyenne",
chunkLoadRadius: 20,
chunkUnloadRadius: 30,
fogEnabled: true,
forceLodModels: true,
lodHighDetailDistance: 0,
},
high: {
label: "High",
chunkLoadRadius: CHUNK_CONFIG.loadRadius,
chunkUnloadRadius: CHUNK_CONFIG.unloadRadius,
fogEnabled: false,
forceLodModels: false,
lodHighDetailDistance: 10,
},
ultra: {
label: "Ultra",
chunkLoadRadius: 50,
chunkUnloadRadius: 65,
fogEnabled: false,
forceLodModels: false,
lodHighDetailDistance: 20,
},
} as const satisfies Record<GraphicsPreset, GraphicsPresetConfig>;
export const GRAPHICS_DEFAULTS = {
preset: "high" as GraphicsPreset,
dynamicGrass: true,
dynamicTrees: true,
dynamicClouds: true,
+45
View File
@@ -0,0 +1,45 @@
import {
GRAPHICS_PRESETS,
type GraphicsPreset,
} from "@/data/world/graphicsConfig";
export const MAP_LOD_MODEL_PATHS = {
ebike: "/models/ebike-LOD/model.gltf",
eolienne: "/models/eolienne-LOD/model.gltf",
pylone: "/models/pylone-LOD/model.gltf",
boiteimmeuble: "/models/boiteimmeuble-LOD/model.gltf",
ecole: "/models/ecole-LOD/model.gltf",
immeuble1: "/models/immeuble1-LOD/model.gltf",
lafabrik: "/models/lafabrik-LOD/model.gltf",
maison1: "/models/maison1-LOD/model.gltf",
panneauaffichage: "/models/panneauaffichage-LOD/model.gltf",
talkie: "/models/talkie-LOD/model.gltf",
} as const satisfies Record<string, string>;
export function getMapLodModelPath(modelName: string): string | null {
return (
MAP_LOD_MODEL_PATHS[modelName as keyof typeof MAP_LOD_MODEL_PATHS] ?? null
);
}
export function selectMapModelPathByDistance({
distance,
modelName,
modelPath,
preset,
}: {
distance: number;
modelName: string;
modelPath: string;
preset: GraphicsPreset;
}): string {
const lodModelPath = getMapLodModelPath(modelName);
if (!lodModelPath) return modelPath;
const presetConfig = GRAPHICS_PRESETS[preset];
if (presetConfig.forceLodModels) return lodModelPath;
return distance <= presetConfig.lodHighDetailDistance
? modelPath
: lodModelPath;
}