Pinned via pnpm catalog in pnpm-workspace.yaml + root pnpm.overrides.
Fleet guide: skill grudge-3d-game-packages.
| Package | Role | Pin / range |
|---|---|---|
| three | Renderer, math, curves, loaders API | 0.185.1 (fleet r185) |
| @types/three | TypeScript | 0.185.1 |
| @react-three/fiber | React reconcilier for Three | ^9.6.1 |
| @react-three/drei | Helpers (Orbit, Grid, Html, curves, GizmoHelper…) | ^10.7.7 |
| @react-three/rapier | <Physics>, rigid bodies, CCT helpers |
^2.2.0 |
| @dimforge/rapier3d | Physics WASM (streaming via vite-plugin-wasm) | ^0.19.3 |
| @react-three/postprocessing | R3F EffectComposer bridge | ^3.0.4 |
| postprocessing | SSAO, bloom, SMAA, outline, etc. | ^6.39.4 |
| three-stdlib | Controls, loaders, helpers (editor DNA) | ^2.36.1 |
| three-mesh-bvh | Fast raycast / ground probes | ^0.9.13 |
| react / react-dom | UI shell | 19.1.0 |
| Node.js | Tooling engines | >=22.12 (workspace engines) |
Note: Imperative fleet games often use
@dimforge/rapier3d-compat(no separate WASM step). Forge uses@dimforge/rapier3d+vite-plugin-wasm+vite-plugin-top-level-awaitfor smaller streaming WASM. Do not mix both in one body graph.
| Package | Role |
|---|---|
| recast-navigation | Navmesh bake / query (emscripten) |
| @recast-navigation/three | Three geometry → Recast |
| yuka | Steering / AI agents on navmesh corridors |
Spline paths for cutscenes / roads use three curves + maath (not a separate “spline” npm required).
| Package | Role |
|---|---|
| maath | Easing, frames, vector helpers (with drei) |
three Curves / CatmullRomCurve3 |
Path spline SSOT |
@react-three/drei CurveModifier, Line |
R3F spline display |
| three-bvh-csg | Boolean mesh ops (editor tools) |
| quickhull3d / vhacd-js | Hull / collider helpers |
| Layer | Package |
|---|---|
| R3F wrapper | @react-three/postprocessing |
| Engine | postprocessing (pmndrs) |
| In-app | EffectsRig + quality gate (Cinematic vs Performance) |
Prefer pmndrs postprocessing over ad-hoc EffectComposer stacks.
| Package | Role |
|---|---|
| @gltf-transform/core (+ extensions, functions) | Offline GLB dedup / prune / weld |
| meshoptimizer | EXT_meshopt_compression (local, not esm.sh) |
| detect-gpu | Boot-time render quality (lib/deviceTier.ts) |
| idb-keyval | Large drafts when localStorage quota fails |
| comlink | Worker RPC helper (lib/comlinkWorker.ts) |
Optional later: howler (SFX), colyseus.js (play client only) — see multiplayer deploy.
| Layer | Authority | Forge usage |
|---|---|---|
| Binaries | R2 assets.grudge-studio.com |
builtin: keys, Fast options, search_fleet_assets |
| Mesh index | D1 grudge-assets-db via api.grudge-studio.com/assets |
Edge GET /api/catalog/search (Worker filters; fleet API has weak query) |
| Gamedata | ObjectStore weapons|equipment|materials.json |
Edge GET /api/catalog/gamedata — icons/stats, not meshes |
| Agent jobs | D1 forge-agent |
POST /api/agent/jobs only — never store GLBs here |
| Player bag | Railway Postgres | Not Forge D1 |
AI tools: list_fast_assets · search_fleet_assets · spawn_fleet_asset · list_gamedata · agent_stack_status.
Canonical heroes: builtin:grudge6:warrior|orc|… (FBX kits). Weapons: builtin:race-weapon:* (grudge6 library).
optionalDependencies)| Package | Role |
|---|---|
@grudge-studio/sdk |
Umbrella fleet helpers |
@grudge-studio/engine |
Physics defaults / debug gate |
@grudge-studio/assets / asset-resolver |
CDN paths |
@grudge-studio/animator |
Bip001 / bake clips |
@grudge-studio/core |
Auth origins |
| Chunk | Contents | TLA? |
|---|---|---|
vendor-3d |
three + fiber + drei + postprocessing + stdlib + mesh-bvh + maath + troika |
No |
vendor-rapier |
@dimforge/rapier3d (+ wasm) + @react-three/rapier + rapierShim.ts |
Yes (wasm) |
vendor-monaco |
monaco-editor only (not @monaco-editor/react) |
No |
Hard rule: Rapier must not live inside vendor-3d. If three imports Rapier’s __tla, production dies with:
static{De.prototype.isVector2=!0}
TypeError: Cannot read properties of undefined (reading 'prototype')
Live incident (forge.grudge-studio.com vendor-3d-kfUrB2f4.js): @react-three/rapier leaked into vendor-3d, which then import { …, __tla } from "./vendor-rapier-*.js". TLA wrapped the entire three graph; Vector2 static initializers hit TDZ.
| Edge | Allowed? |
|---|---|
vendor-rapier → vendor-3d |
Yes (three already evaluated) |
vendor-3d → vendor-rapier |
Never |
__tla export on vendor-3d |
Never |
Build gate: assertVendor3dNoRapierTla in artifacts/game-forge/vite.config.ts fails the build if the reverse edge appears. Matcher: isRapierModuleId() (scoped paths + react-three-rapier filename + local shim).
Pin one three via root pnpm.overrides (0.185.1). Nested stats-gl/three@0.170 dual copies also break Vector2.
# From monorepo root
pnpm install
pnpm --filter @workspace/game-forge run typecheck
pnpm --filter @workspace/game-forge run build
Bump versions only in pnpm-workspace.yaml catalog (+ root overrides for three / @types/three), then reinstall.
| Package | Why |
|---|---|
cannon-es / Ammo |
Second physics engine |
babylonjs |
Excluded from workspace |
three-pathfinding |
Prefer Recast + Yuka already wired |
@dimforge/rapier3d-compat alongside rapier3d |
Duplicate WASM stacks |
forge-editor · forge-gameplay-scripts