62 Commits

Author SHA1 Message Date
math-pixel a3e8e732f1 its functionning 2026-06-02 00:23:43 +02:00
math-pixel d975aac018 o think is not that 2026-06-01 22:26:58 +02:00
math-pixel cd0afcda8c feat mission-2 2026-06-01 14:40:17 +02:00
math-pixel 813c10f3f7 wip mission 2 refine 2026-06-01 11:49:48 +02:00
math-pixel d5feb07ff0 Merge pull request 'Feat/polish-perf' (#13) from feat/polish-perf into develop
📊 Quality / 🔒 Security Audit (push) Has been cancelled
📊 Quality / 📋 Dependency Freshness (push) Has been cancelled
📊 Quality / 📦 Bundle Size (push) Has been cancelled
🔍 Lint / 🪄 Check lint (push) Has been cancelled
🔍 Lint / 🎨 Check format (push) Has been cancelled
🔍 Lint / 🔎 Typecheck (push) Has been cancelled
🔍 Lint / 🏗 Build (push) Has been cancelled
Reviewed-on: #13
2026-05-31 22:11:58 +00:00
Tom Boullay 7dff4a1238 feat(characters): populate residential zones
🔍 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
2026-06-01 00:09:39 +02:00
Tom Boullay a8cd66dcaa fix(model): sync animated character textures 2026-05-31 23:59:36 +02:00
Tom Boullay 116746f838 fix(model): sync animated gerant textures 2026-05-31 23:45:36 +02:00
Tom Boullay a388c02ab3 fix(model): repair gerant materials 2026-05-31 23:36:54 +02:00
Tom Boullay 4b4162b7d2 tune(characters): adjust npc placement 2026-05-31 23:35:39 +02:00
Tom Boullay 4415faa1f1 chore(models): remove lafabrik old assets 2026-05-31 23:35:17 +02:00
Tom Boullay 4c5f08d772 fix(model): restore lafabrik window transparency 2026-05-31 23:07:24 +02:00
Tom Boullay 51569af7b8 feat(ui): add transient loading indicator
🔍 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
2026-05-31 22:43:48 +02:00
Tom Boullay d26c676edf polish(ui): compact pause menu backdrop 2026-05-31 22:22:29 +02:00
Tom Boullay d3b4a55e71 fix(model): load lafabrik glb 2026-05-31 22:14:13 +02:00
Tom Boullay e212e4bbd5 update(model): use a glb
🔍 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
2026-05-31 22:08:08 +02:00
Tom Boullay 39ec9feb0e fix(model): externalize lafabrik geometry buffer 2026-05-31 21:58:13 +02:00
Tom Boullay 4a43083178 fix(ui): preserve site cookie on restart
🔍 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
2026-05-31 21:45:55 +02:00
Tom Boullay efcbf9e972 polish(ui): refine pause settings menu 2026-05-31 21:42:59 +02:00
Tom Boullay f11ed67452 fix(model): reconnect lafabrik textures 2026-05-31 21:37:52 +02:00
Tom Boullay 3e7edcb1b7 docs(world): document map lod system
🔍 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
2026-05-31 21:23:07 +02:00
Tom Boullay b9c5d0c563 feat(world): add lafabrik lod support 2026-05-31 21:22:48 +02:00
Tom Boullay ebdb72ce0d update(model): add lafabrik lod models 2026-05-31 21:22:24 +02:00
Tom Boullay 34c198ebfd feat(world): add map lod graphics presets 2026-05-31 19:03:55 +02:00
Tom Boullay 564a455520 update(model): add lod models
🔍 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
2026-05-31 18:42:13 +02:00
Tom Boullay 2c2a90264d Merge branch 'develop' of https://git.fabrik.mathieu-chavanel.fr/math-pixel/La-Fabrik into develop
🔍 Lint / 🪄 Check lint (push) Has been cancelled
🔍 Lint / 🎨 Check format (push) Has been cancelled
🔍 Lint / 🔎 Typecheck (push) Has been cancelled
📊 Quality / 🔒 Security Audit (push) Has been cancelled
📊 Quality / 📋 Dependency Freshness (push) Has been cancelled
📊 Quality / 📦 Bundle Size (push) Has been cancelled
🔍 Lint / 🏗 Build (push) Has been cancelled
2026-05-31 11:02:34 +02:00
Tom Boullay e02d06b8a5 Update hand_landmarker.task 2026-05-31 11:02:31 +02:00
math-pixel 1901075e3a Merge pull request 'Feat/polish-intro' (#11) from feat/polisth-intro into develop
🔍 Lint / 🪄 Check lint (push) Has been cancelled
🔍 Lint / 🎨 Check format (push) Has been cancelled
🔍 Lint / 🔎 Typecheck (push) Has been cancelled
📊 Quality / 🔒 Security Audit (push) Has been cancelled
📊 Quality / 📋 Dependency Freshness (push) Has been cancelled
📊 Quality / 📦 Bundle Size (push) Has been cancelled
🔍 Lint / 🏗 Build (push) Has been cancelled
Reviewed-on: #11
2026-05-31 09:01:17 +00:00
Tom Boullay e073fc375b fix(world): warm up map shadows from environment
🔍 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
2026-05-31 11:00:40 +02:00
Tom Boullay bff8a16290 feat(intro): add ebike onboarding sequence
🔍 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
2026-05-31 10:42:46 +02:00
Tom Boullay a3f611e227 fix(webgl): auto-restore context after loss
🔍 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
The Canvas onCreated callback used to log Context Lost but never asked
the GPU to restore it, which left the page on a frozen black canvas
until the user reloaded. We now grab the WEBGL_lose_context extension
on mount and call restoreContext() 500ms after a loss, giving the GPU
time to free memory before we ask for a new context. The existing
webglcontextrestored handler reinstates the shadow map settings, so
recovery is transparent to the user.

This does not prevent context loss itself — frequent losses still
indicate VRAM pressure or HMR-driven context churn — but it removes
the need to reload manually when the GPU recycles us.
2026-05-30 20:58:58 +02:00
Tom Boullay b578e68c2e Update SiteTransitionOverlay.tsx 2026-05-30 20:55:51 +02:00
Tom Boullay 7c691a8044 fix: show dialogue subtitles on black screen
🔍 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
2026-05-30 20:25:21 +02:00
Tom Boullay f24704091a chore(logging): downgrade 'lite map skipped' to debug
This log fires every time the lite map loader skips heavy nodes, which
is the expected fast-path. It does not need to show up in a normal
console session — moving it to logger.debug keeps it accessible under
?debug for diagnostics while removing the noise from default runs.
2026-05-30 20:20:15 +02:00
Tom Boullay e6bfcbe960 feat(intro): polish loading transition 2026-05-30 20:11:40 +02:00
Tom Boullay 0fa7a82175 fix(perf): prevent Canvas double-mount on /site redirect
HomePage used to mount the Canvas before its effect fired the redirect
to /site, then unmount it as soon as the route changed. That left the
WebGL context torn down mid-load with GLTF requests still in flight,
which on slow GPUs ended in a 'Context Lost' and a stuck 1 FPS render
once the user came back from /site. The fix is a synchronous cookie
check after all hooks: if the user has not visited /site today we
return null and let the redirect happen without ever creating a GL
context.

Also drops the GameMap 'lite map skipped' log from warn to info: it
is an expected lite-loading path, not a problem worth a yellow warning.
2026-05-30 19:51:57 +02:00
Tom Boullay 82dc47a296 fix(assets): correct texture URIs in gant_r and pylone GLTFs
- gant_r/model.gltf: align casing with the actual files on disk
  (gant_basecolor / gant_occlusionroughnessmetallic) so the GLTFLoader
  stops logging 'Couldn't load texture' on case-sensitive filesystems
- pylone/model.gltf: nine missing Image_N.png references replaced with
  the existing color.png / normal.png so the pylone renders without
  console errors. Material slots are mapped by role: normalTexture ->
  normal.png, baseColorTexture and metallicRoughnessTexture -> color.png
2026-05-30 19:51:51 +02:00
Tom Boullay 970adf4853 feat(a11y): WCAG AA polish on the site onboarding flow
🔍 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
- index.css: add visible :focus-visible rings for .site-card-button
  and .site-button so keyboard users can see where focus lives
- SiteCard: drop outline:none, add aria-pressed and aria-label so
  screen readers announce selection state
- SiteButton: add the .site-button class for the shared focus ring
- SiteDisclaimerScreen: keyboard skip via Enter / Space / Escape, a
  role="region" + aria-label wrapper and aria-live="polite" on the
  message; honour prefers-reduced-motion on the fade
- IntroVideoPlayer: role="region" with a skip hint in aria-label,
  preload="auto", and aria-hidden on the decorative caption span
2026-05-30 18:44:03 +02:00
Tom Boullay 07b09c22af fix(site): repair onboarding audio cleanup, redirect, and manifest fetches
- loadDialogueManifest: cache the resolved manifest at module level and
  dedupe concurrent fetches so each screen no longer re-downloads it
- useGameStore: completeIntroState now also advances intro.currentStep
  to "playing" so callers do not need a separate setIntroStep call
- SiteNamingScreen and SiteTransitionOverlay: replace ref-based guards
  with an isCancelled flag captured per effect. The previous guards
  persisted across StrictMode remounts, leaving mount 2 unable to
  re-run the effect after mount 1's chain was cancelled, which broke
  the fade animations, the second narrator dialogue and the redirect.
  Both screens now also call stopCurrentDialogue on unmount so audio
  cannot bleed across routes, and the transition gets a safety timeout
  in case the dialogue audio fails to fire its "ended" event
- SiteTransitionOverlay: keep the <Subtitles /> mount inside the
  overlay so it renders inside the z-index 1000 stacking context
  (above the black screen); the one in SiteLayout sits behind it
- IntroDialogueOverlay: route through playDialogueById instead of
  AudioManager.playSoundWithCallback so the narrator subtitles play
  in sync, and add the same isCancelled cleanup pattern
- IntroRevealOverlay: rely on completeIntro alone now that it advances
  intro.currentStep, and skip the fade when reduced motion is requested
- SiteMobileBlocker: correct logo path from public/... to /...
2026-05-30 18:43:53 +02:00
Tom Boullay 0f6860f1ae refactor(site): extract shared utilities and centralise dialogue IDs
- new src/hooks/ui/useIsMobile.ts (matchMedia + useSyncExternalStore)
  replacing the resize-handler hook inlined inside pages/site/page.tsx
- new src/hooks/ui/usePrefersReducedMotion.ts
- new src/data/site/dialogueIds.ts so site and intro components stop
  carrying hard-coded narrator IDs
- siteConfig: add SITE_BACKGROUND_STYLE shared by SiteLayout and
  SiteMobileBlocker, rename forcedName to presetPlayerName, fix the
  swapped id/label pairing on situation cards
- useSiteStore: rename selectedExperience/Situation to *Index so the
  stored value (an array index) is obvious in callers
- audioConfig: drop dead AUDIO_PATHS placeholders
- propagate the renames and SITE_BACKGROUND_STYLE through SiteLayout,
  SiteWelcomeScreen, SiteSituationScreen and pages/site/page.tsx
2026-05-30 18:43:35 +02:00
Tom Boullay 6ae21a2427 fix(site): unified card styles, import Nersans One font, native naming input
🔍 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
2026-05-30 17:56:42 +02:00
Tom Boullay 29342d796c fix(site): reduce situation card font size 2026-05-30 17:21:44 +02:00
Tom Boullay 60e3c92511 fix(site): update situation cards 2026-05-30 17:06:29 +02:00
Tom Boullay 02c1fb33d0 feat(dialogues): support multi-cue subtitles
🔍 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
2026-05-30 04:00:25 +02:00
Tom Boullay ce5dc8ada0 update: intro flow overlays 2026-05-30 04:00:20 +02:00
Tom Boullay a2cff0567e feat: add site onboarding route 2026-05-30 04:00:09 +02:00
Tom Boullay 8cfee1ac93 update: reorganize public assets 2026-05-30 03:59:45 +02:00
Tom Boullay 4c5e2ed945 feat(types): add SiteStep and refactor GameStep for new intro flow
🔍 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
2026-05-30 02:14:10 +02:00
Tom Boullay 345d49f485 add: cinemactics and assets
🔍 Lint / 🪄 Check lint (push) Has been cancelled
🔍 Lint / 🎨 Check format (push) Has been cancelled
🔍 Lint / 🔎 Typecheck (push) Has been cancelled
📊 Quality / 🔒 Security Audit (push) Has been cancelled
📊 Quality / 📋 Dependency Freshness (push) Has been cancelled
📊 Quality / 📦 Bundle Size (push) Has been cancelled
🔍 Lint / 🏗 Build (push) Has been cancelled
2026-05-30 02:04:39 +02:00
math-pixel a6cc028848 Merge pull request 'Feat/gallery' (#9) from feat/galerie into develop
🔍 Lint / 🪄 Check lint (push) Has been cancelled
🔍 Lint / 🎨 Check format (push) Has been cancelled
🔍 Lint / 🔎 Typecheck (push) Has been cancelled
📊 Quality / 🔒 Security Audit (push) Has been cancelled
📊 Quality / 📋 Dependency Freshness (push) Has been cancelled
📊 Quality / 📦 Bundle Size (push) Has been cancelled
🔍 Lint / 🏗 Build (push) Has been cancelled
Reviewed-on: #9
2026-05-29 07:00:36 +00:00
Tom Boullay 52bb1b2915 chore: code quality audit and lint fixes
🔍 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
- Fix all 63 ESLint errors across codebase
- Consolidate MaterialWithTextureSlots type in src/types/three/three.ts
- Add CSS custom properties for design tokens
- Extract ebike constants to src/data/ebike/ebikeConfig.ts
- Add proper TypeScript types for window extensions
- Fix React hooks violations (refs during render, setState in effects)
- Remove unused exports and redundant CSS
- Add type guards for Three.js material handling
- Clean up AI slop comments and legacy CSS patterns
2026-05-29 09:00:04 +02:00
Tom Boullay ade301389e merge develop into feat/galerie - resolve model and code conflicts 2026-05-29 02:25:46 +02:00
Tom Boullay 47e50d9318 fix: issue in galley mode 2026-05-29 02:18:17 +02:00
math-pixel c7df58099a Merge pull request 'Feat/map-environment' (#6) from feat/map-environment into develop
🔍 Lint / 🪄 Check lint (push) Has been cancelled
🔍 Lint / 🎨 Check format (push) Has been cancelled
🔍 Lint / 🔎 Typecheck (push) Has been cancelled
📊 Quality / 🔒 Security Audit (push) Has been cancelled
📊 Quality / 📋 Dependency Freshness (push) Has been cancelled
📊 Quality / 📦 Bundle Size (push) Has been cancelled
🔍 Lint / 🏗 Build (push) Has been cancelled
Reviewed-on: #6
2026-05-29 00:00:50 +00:00
Tom Boullay 054cb975da fix: hide gallery export planes
🔍 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
2026-05-25 19:13:02 +02:00
Tom Boullay cf71148935 fix: smooth gallery preview seams
🔍 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
2026-05-25 18:02:36 +02:00
Tom Boullay 1b2241df49 feat: add gallery lighting controls 2026-05-25 17:57:51 +02:00
Tom Boullay d7351e5f37 fix: render gallery skybox unlit double-sided 2026-05-25 17:53:46 +02:00
Tom Boullay 6a412c7b00 fix: stabilize gallery skybox rendering 2026-05-25 17:31:27 +02:00
Tom Boullay e9fb36f9dc style: simplify gallery UI and rename route 2026-05-25 17:13:21 +02:00
Tom Boullay 36180279b2 docs: document model gallery 2026-05-25 16:24:12 +02:00
Tom Boullay 626dc47bbe feat: add model gallery viewer 2026-05-25 16:23:36 +02:00
696 changed files with 7970 additions and 1451 deletions
+11
View File
@@ -0,0 +1,11 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "dev",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"port": 5173
}
]
}
+6 -2
View File
@@ -26,10 +26,11 @@ The current prototype puts the player in a repair-oriented world where they prog
## Routes
| Route | Purpose |
| --------- | --------------------------------------------------- |
| ---------- | --------------------------------------------------- |
| `/` | Playable 3D experience |
| `/?debug` | Playable scene with debug GUI and overlays |
| `/editor` | Local map, dialogue, subtitle, and cinematic editor |
| `/gallery` | 3D model gallery for browsing project assets |
| `/docs` | In-app documentation index |
## Tech Stack
@@ -98,6 +99,7 @@ Useful local URLs:
```txt
http://localhost:5173/?debug
http://localhost:5173/editor
http://localhost:5173/gallery
http://localhost:5173/docs
```
@@ -110,7 +112,7 @@ npm run format:check
npm run build
```
Regenerate runtime map data after editing `public/map_raw.json`:
Regenerate runtime map data after editing `public/map_raw.json` that came from the hierachy node of the model Blocking.gltf:
```bash
npm run map:transform
@@ -150,11 +152,13 @@ WS ws://localhost:8000/ws
| `docs/technical/zustand.md` | Game, settings, and subtitle stores |
| `docs/technical/three-debugging.md` | DevTools workflow for stepping into Three.js internals |
| `docs/technical/map-performance.md` | Map draw-call bottlenecks and optimization notes |
| `docs/technical/map-lod.md` | Runtime map LOD presets, paths, and workflow |
| `docs/technical/editor.md` | Editor implementation details |
| `docs/technical/animation.md` | Animated, explodable, and reusable 3D model components |
| `docs/user/features.md` | Implemented feature inventory |
| `docs/user/main-feature.md` | User-facing repair-game walkthrough |
| `docs/user/editor.md` | Editor user guide |
| `docs/user/gallery.md` | Model gallery user guide |
| `docs/code-review-preparation.md` | French code-review preparation support |
## Current Caveats
Binary file not shown.
+119
View File
@@ -0,0 +1,119 @@
# Map LOD System
This document describes the runtime LOD system used by the production map.
## Goal
The map now supports two visual versions for selected models:
- the regular model in `public/models/<name>/`
- the lighter model in `public/models/<name>-LOD/`
The runtime chooses between those paths from the active graphics preset. This keeps nearby objects visually richer while reducing the cost of distant objects.
## Graphics Presets
Presets are configured in:
```txt
src/data/world/graphicsConfig.ts
```
Current behavior:
| Preset | Chunk load distance | Fog | LOD behavior |
| -------- | ------------------: | --- | ------------------------------------- |
| `low` | 10m | On | Always use `*-LOD` models |
| `medium` | 20m | On | Always use `*-LOD` models |
| `high` | Current default 50m | Off | Regular model up to 10m, then `*-LOD` |
| `ultra` | 50m | Off | Regular model up to 20m, then `*-LOD` |
The unload distance stays slightly larger than the load distance to avoid rapid mount/unmount flickering when the player stands near a boundary.
## Runtime Selection
LOD path mapping lives in:
```txt
src/data/world/mapLodConfig.ts
```
The main selector is `selectMapModelPathByDistance()`. It receives:
- the current camera distance
- the map model name
- the regular model path
- the active graphics preset
It returns either the regular path or the `*-LOD` path.
## Chunked Instanced Models
Repeated static assets are rendered through:
```txt
src/world/map-instancing/MapInstancingSystem.tsx
```
For each visible chunk, the system checks the nearest instance in that chunk. If the nearest instance is inside the high-detail threshold, the whole chunk uses the regular model. Otherwise, it uses the `*-LOD` model.
This is intentionally chunk-level LOD instead of per-instance LOD. It matches the existing chunk streaming architecture and avoids splitting every object into many tiny batches.
## Single And Generated Models
Single map nodes use:
```txt
src/hooks/world/useMapLodModelPath.ts
src/world/GameMap.tsx
```
Some named map objects are rendered through dedicated generated components instead of the generic `GameMap` path. Those components must call `useMapLodModelPath()` directly.
Current dedicated generated components with LOD support:
```txt
src/components/three/world/EcoleModel.tsx
src/components/three/world/LaFabrikMapModel.tsx
```
This matters for `lafabrik`: adding `public/models/lafabrik-LOD/` is not enough by itself. The component must also be connected to `useMapLodModelPath()`.
## Adding A New LOD Model
To add LOD support for a model:
1. Add the light model in `public/models/<name>-LOD/model.gltf`.
2. Keep the regular model in `public/models/<name>/model.glb` or `public/models/<name>/model.gltf`.
3. Add the mapping in `src/data/world/mapLodConfig.ts`.
4. If the model uses a dedicated component, call `useMapLodModelPath()` in that component.
5. Preload both paths when the component is dedicated and uses `useGLTF.preload()`.
6. Verify the GLTF/GLB references: buffers, textures, opacity maps, and relative paths.
## Current LOD Models
The current explicit LOD mappings are:
```txt
ebike
eolienne
pylone
boiteimmeuble
ecole
immeuble1
lafabrik
maison1
panneauaffichage
talkie
```
## Regression Risks
The most common failure modes are:
- the `*-LOD` folder exists but is missing from `mapLodConfig.ts`
- a dedicated generated component keeps a hardcoded model path
- GLTF references point to textures that were renamed during export
- a model is added to LOD config but does not spawn through `GameMap` or `MapInstancingSystem`
Before committing model changes, validate both the regular and LOD folders for missing GLTF refs.
+4 -4
View File
@@ -15,9 +15,9 @@ This document tracks the current map-rendering performance pass.
The first performance bottleneck was draw calls. Some assets were exported as many small GLTF primitives even when they used only a few materials.
| Model | Instances | Meshes / primitives | Notes |
| ---------------- | --------: | ------------------: | ---------------------------------------------------------------- |
| ---------------- | --------: | ------------------: | ------------------------------------------------------------------------------------ |
| `generateur` | 3 | 3152 | Worst draw-call offender. Needs asset-side mesh merging. |
| `lafabrik` | 4 | 56 | Moderate draw calls, heavy 2048 texture set. |
| `lafabrik` | 4 | 474 | High primitive count; current HD GLB has embedded geometry and no external textures. |
| `ecole` | 1 | 107 | One material but many primitives; should be merged. |
| `fermeverticale` | 3 | 1 | Geometry is fine; textures are large for the visible complexity. |
@@ -34,7 +34,7 @@ Estimated source primitive count versus runtime merged groups:
| `generateur` | 3152 | 8 |
| `ecole` | 107 | 2 |
| `eolienne` | 118 | 8 |
| `lafabrik` | 56 | 14 |
| `lafabrik` | 474 | ~77 |
This is a code-side safety net, not a replacement for clean asset exports. Clean GLB exports with merged meshes and fewer textures remain the preferred long-term path.
@@ -255,7 +255,7 @@ Design/export should prioritize:
1. Produce lower-poly `buisson`, `arbre`, `sapin`, and crop assets.
2. Add LOD or billboard variants for far vegetation.
3. Merge `generateur` meshes from 3152 primitives to a small number of material groups.
4. Reduce `lafabrik` texture count and downscale flat/low-detail maps.
4. Keep `lafabrik` exports texture-light, and merge repeated material primitives where possible.
5. Merge `ecole` primitives because it uses a single material.
6. Prefer runtime `.glb` or compressed runtime textures when the pipeline supports it.
+13 -2
View File
@@ -32,6 +32,8 @@ The loading progress in `HomePage` is monotonic:
This prevents the overlay from jumping backward when nested loaders finish in a slightly different order.
After the initial map boot is complete, late loading signals no longer reopen the full-screen loading overlay. Instead, `HomePage` shows the compact `AppLoadingIndicator` while the game remains visible. This is reserved for explicit runtime reload signals such as graphics preset changes, repair-state transitions, or late world loading events; chunk streaming intentionally does not drive this indicator.
## World Composition
`src/world/World.tsx` is the main scene composer.
@@ -72,14 +74,23 @@ It tracks:
- `gameMapLoaded`: map data and visible map nodes settled
- `gameStageLoaded`: Rapier gameplay stage mounted
- `showGameStage`: true when the map is ready enough to mount gameplay content
- `gameplayReady`: true when map, stage, and octree are all ready
- `shadowsReady`: renderer, shadow lights, and scene matrices have been forced once after the scene is mounted
- `gameplayReady`: true when map, stage, octree, and the shadow warmup are all ready
The final game-scene readiness condition is:
The base game-scene readiness condition before the shadow warmup is:
```ts
showGameStage && gameStageLoaded && octree !== null;
```
After that condition is met, `SceneShadowWarmup` runs one final loading step:
```txt
Activation des ombres -> Ombres prêtes -> Gameplay prêt
```
This keeps the loading overlay visible until the renderer shadow map, shadow-casting light, and mounted scene graph have all been explicitly refreshed.
The debug physics scene is ready when:
```ts
+46
View File
@@ -0,0 +1,46 @@
# Galerie des modèles
La galerie est disponible sur `/gallery`. Elle permet de parcourir les modèles 3D présents dans `public/models/` sans lancer la boucle de gameplay principale.
## Objectif
Cette page sert à remercier et valoriser le travail des designers du projet La Fabrik. Chaque modèle est affiché dans un canvas dédié, avec la même skybox et le même lighting que l'expérience principale.
## Utilisation
1. Ouvrir `/gallery`.
2. Utiliser les flèches en bas de l'écran pour passer au modèle précédent ou suivant.
3. Tourner autour du modèle avec la souris ou le doigt.
4. Utiliser le bouton de réglages à droite pour ouvrir ou fermer le panneau lumière.
5. Lire le diagnostic texture discret pour savoir si le modèle chargé semble correct côté textures.
## Fonctionnement
- La liste des modèles est déclarée dans `src/data/galleryModels.ts`.
- Le viewer utilise `@react-three/fiber` et `@react-three/drei`.
- `OrbitControls` permet de manipuler la caméra autour du modèle.
- `Bounds` et `Center` recadrent automatiquement le modèle actif.
- `SkyModel` réutilise la skybox du jeu, avec un matériau non éclairé uniquement dans la galerie pour éviter que certaines faces deviennent noires avec une caméra orbitale libre.
- Les lumières reprennent les valeurs par défaut du jeu, puis peuvent être ajustées dans le panneau latéral.
- `OrbitControls` autorise une orbite verticale complète pour inspecter le dessous des modèles.
- Le viewer désactive les normal maps dans la preview pour limiter les coutures visibles sur certains exports découpés en plusieurs meshes.
- Les animations GLTF présentes dans un modèle sont lancées automatiquement.
- Un diagnostic simple inspecte les matériaux chargés pour signaler les textures absentes ou non exploitables.
## Ajouter un modèle
1. Ajouter le dossier du modèle dans `public/models/{nom}`.
2. Vérifier que le modèle possède un fichier chargeable, par exemple `model.gltf`, `model.glb` ou un nom explicite comme `potager.gltf`.
3. Ajouter une entrée dans `src/data/galleryModels.ts` avec un `id`, un `name` et un `path`.
Exemple :
```ts
{ id: "nouveau-modele", name: "Nouveau modèle", path: "/models/nouveau-modele/model.gltf" }
```
## Limites connues
- Le navigateur ne liste pas automatiquement les dossiers de `public/models/`, donc la liste reste déclarative.
- Les modèles très lourds peuvent prendre du temps à charger.
- La galerie est un viewer simple : elle ne remplace pas les outils d'inspection avancée comme Blender ou le viewer d'upload.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -227
View File
@@ -584,22 +584,6 @@
}
]
},
{
"name": "arbre",
"type": "Object3D",
"position": [50.072, 2.2583, 78.7082],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "arbre",
"type": "Mesh",
"position": [50.072, 2.2583, 78.7082],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "arbre",
"type": "Object3D",
@@ -888,22 +872,6 @@
}
]
},
{
"name": "arbre",
"type": "Object3D",
"position": [59.1794, 2.2557, 73.349],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "arbre",
"type": "Mesh",
"position": [59.1794, 2.2557, 73.349],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "arbre",
"type": "Object3D",
@@ -1112,22 +1080,6 @@
}
]
},
{
"name": "arbre",
"type": "Object3D",
"position": [74.0452, 2.309, 59.2374],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "arbre",
"type": "Mesh",
"position": [74.0452, 2.309, 59.2374],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "arbre",
"type": "Object3D",
@@ -2754,22 +2706,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [73.7334, 1.1132, 54.1382],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [73.7334, 1.1132, 54.1382],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -3330,22 +3266,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [67.9046, 0.5562, 74.8395],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [67.9046, 0.5562, 74.8395],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -3714,22 +3634,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [73.5205, 0.3748, 75.9136],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [73.5205, 0.3748, 75.9136],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -3858,22 +3762,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [66.999, 1.7223, 48.3983],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [66.999, 1.7223, 48.3983],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -4914,22 +4802,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [61.3924, 0.4621, 82.2195],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [61.3924, 0.4621, 82.2195],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -5122,22 +4994,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [61.1082, 0.6236, 77.7642],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [61.1082, 0.6236, 77.7642],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -5170,22 +5026,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [53.1033, 1.6054, 63.3842],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [53.1033, 1.6054, 63.3842],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -5266,22 +5106,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [59.647, 1.5484, 59.429],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [59.647, 1.5484, 59.429],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -5410,22 +5234,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [69.2496, 0.6286, 71.5478],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [69.2496, 0.6286, 71.5478],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -6226,22 +6034,6 @@
}
]
},
{
"name": "buisson",
"type": "Object3D",
"position": [58.3126, 0.686, 77.9828],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "buisson",
"type": "Mesh",
"position": [58.3126, 0.686, 77.9828],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "buisson",
"type": "Object3D",
@@ -37602,23 +37394,6 @@
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "ebike",
"type": "Object3D",
"role": "group",
"position": [0, 0, 0],
"rotation": [0, 0, 0],
"scale": [1, 1, 1],
"children": [
{
"name": "ebike",
"type": "Object3D",
"position": [42.2399, 4.5484, 34.6468],
"rotation": [0, 0, 0],
"scale": [1, 1, 1]
}
]
},
{
"name": "zone1_residence",
"type": "Object3D",
@@ -40477,14 +40252,14 @@
"name": "lafabrik",
"type": "Object3D",
"position": [59.4973, 6.2746, 64.6354],
"rotation": [-3.1416, -0.7309, -3.1416],
"rotation": [-3.1416, 2.4107, -3.1416],
"scale": [1, 2, 1],
"children": [
{
"name": "lafabrik",
"type": "Mesh",
"position": [59.4973, 6.2746, 64.6354],
"rotation": [-3.1416, -0.7309, -3.1416],
"rotation": [-3.1416, 2.4107, -3.1416],
"scale": [1, 2, 1]
}
]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More