Merge branch 'develop' into feat/e-bike
🔍 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
🔍 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
This commit is contained in:
@@ -135,7 +135,7 @@ export const galleryModels: GalleryModel[] = [
|
||||
},
|
||||
{ id: "potager", name: "Potager", path: "/models/potager/potager.gltf" },
|
||||
{ id: "puce", name: "Puce", path: "/models/puce/model.gltf" },
|
||||
{ id: "pylone", name: "Pylône", path: "/models/pylone/model.gltf" },
|
||||
{ id: "pylone", name: "Pylône", path: "/models/pylone/model.glb" },
|
||||
{
|
||||
id: "refroidisseur",
|
||||
name: "Refroidisseur",
|
||||
|
||||
@@ -4,7 +4,7 @@ export const REPAIR_CASE_MODEL_PATH = "/models/packderelance/model.gltf";
|
||||
export const REPAIR_CASE_OPEN_SOUND_PATH = "/sounds/effect/open-malette.mp3";
|
||||
export const REPAIR_CASE_CLOSE_SOUND_PATH = "/sounds/effect/close-malette.mp3";
|
||||
|
||||
export const REPAIR_CASE_LID_NODE_NAME = "partiesup";
|
||||
export const REPAIR_CASE_LID_NODE_NAME = "partsup";
|
||||
export const REPAIR_CASE_CLOSED_ROTATION_OFFSET_DEGREES = 0;
|
||||
export const REPAIR_CASE_OPEN_ROTATION_OFFSET_DEGREES = 115;
|
||||
export const REPAIR_CASE_ANIMATION_DURATION = 0.8;
|
||||
@@ -27,3 +27,50 @@ export const REPAIR_CASE_FOCUS_SCALE = 2.25;
|
||||
export const REPAIR_CASE_PLACEHOLDER_NAME_PREFIX = "placeholder_";
|
||||
export const REPAIR_CASE_PLACEHOLDER_SNAP_RADIUS = 0.65;
|
||||
export const REPAIR_CASE_PLACEHOLDER_SNAP_DURATION = 0.25;
|
||||
|
||||
/**
|
||||
* Names of nodes inside the packderelance GLTF where standalone part models
|
||||
* are anchored (visually injected). The original meshes under these nodes are
|
||||
* hidden at runtime so the standalone model takes their place.
|
||||
*
|
||||
* Some entries (e.g. `refroidisseur`) do not exist as nodes in the GLTF; an
|
||||
* empty Object3D is created at mount time at the corresponding case-local
|
||||
* fallback position so the anchoring pipeline is uniform.
|
||||
*/
|
||||
export const REPAIR_CASE_PART_ANCHOR_NAMES = [
|
||||
"cabledroit",
|
||||
"cablegauche",
|
||||
"pucehaut",
|
||||
"pucebas",
|
||||
"refroidisseur",
|
||||
] as const;
|
||||
|
||||
export type RepairCasePartAnchorName =
|
||||
(typeof REPAIR_CASE_PART_ANCHOR_NAMES)[number];
|
||||
|
||||
/**
|
||||
* Case-local positions used when an anchor node is missing from the GLTF.
|
||||
* Values are expressed in the case model's local coordinate system (the case
|
||||
* is rendered at small intrinsic scale; magnitudes are in the 0.01-0.25 range
|
||||
* to match the existing nodes such as `cabledroit`).
|
||||
*/
|
||||
export const REPAIR_CASE_PART_ANCHOR_FALLBACKS: Record<
|
||||
RepairCasePartAnchorName,
|
||||
Vector3Tuple
|
||||
> = {
|
||||
cabledroit: [0.0087, 0.0139, 0.1921],
|
||||
cablegauche: [0.0087, 0.0139, 0.2477],
|
||||
pucehaut: [-0.0207, 0.009, -0.0479],
|
||||
pucebas: [0.0987, 0.009, -0.0479],
|
||||
refroidisseur: [0.05, 0.014, 0.05],
|
||||
};
|
||||
|
||||
/**
|
||||
* Quaternion applied to anchor nodes that are created at runtime (because
|
||||
* the corresponding node is absent from the GLTF). Matches the rotation of
|
||||
* the existing part nodes in packderelance to keep visual orientation
|
||||
* consistent.
|
||||
*/
|
||||
export const REPAIR_CASE_PART_ANCHOR_FALLBACK_QUATERNION = [
|
||||
0.7071068286895752, 0, 0, 0.7071068286895752,
|
||||
] as const satisfies readonly [number, number, number, number];
|
||||
|
||||
@@ -25,26 +25,48 @@ export const REPAIR_MISSIONS: Record<RepairMissionId, RepairMissionConfig> = {
|
||||
interactUiPath: REPAIR_INTERACT_UI_PATH,
|
||||
brokenUiPath: REPAIR_BROKEN_UI_PATH,
|
||||
case: DEFAULT_REPAIR_CASE,
|
||||
requiredReplacementPartId: "ebike-cooling-core-replacement",
|
||||
requiredReplacementPartIds: ["ebike-cooling-core-replacement"],
|
||||
brokenParts: [
|
||||
{
|
||||
id: "ebike-cooling-core",
|
||||
label: "Cooling core",
|
||||
modelPath: "/models/refroidisseur/model.gltf",
|
||||
nodeName: "refroidisseur",
|
||||
targetNodeName: "refroidisseur",
|
||||
caseSlotName: "placeholder_1",
|
||||
},
|
||||
],
|
||||
replacementParts: [
|
||||
{
|
||||
id: "ebike-cooling-core-replacement",
|
||||
label: "Replacement cooling core",
|
||||
label: "Refroidisseur",
|
||||
modelPath: "/models/refroidisseur/model.gltf",
|
||||
caseAnchor: "refroidisseur",
|
||||
targetNodeName: "refroidisseur",
|
||||
},
|
||||
{
|
||||
id: "ebike-glove-distractor",
|
||||
label: "Insulation glove",
|
||||
modelPath: "/models/gant_l/model.gltf",
|
||||
id: "ebike-cable-right-distractor",
|
||||
label: "Câble droit",
|
||||
modelPath: "/models/cable1/model.gltf",
|
||||
caseAnchor: "cabledroit",
|
||||
},
|
||||
{
|
||||
id: "ebike-cable-left-distractor",
|
||||
label: "Câble gauche",
|
||||
modelPath: "/models/cable2/model.gltf",
|
||||
caseAnchor: "cablegauche",
|
||||
},
|
||||
{
|
||||
id: "ebike-puce-haut-distractor",
|
||||
label: "Puce haute",
|
||||
modelPath: "/models/puce/model.gltf",
|
||||
caseAnchor: "pucehaut",
|
||||
},
|
||||
{
|
||||
id: "ebike-puce-bas-distractor",
|
||||
label: "Puce basse",
|
||||
modelPath: "/models/puce/model.gltf",
|
||||
caseAnchor: "pucebas",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -53,43 +75,52 @@ export const REPAIR_MISSIONS: Record<RepairMissionId, RepairMissionConfig> = {
|
||||
label: "Power pylon",
|
||||
description:
|
||||
"Restore the pylon lamp relay and damaged panel before reconnecting the grid",
|
||||
modelPath: "/models/pylone/model.gltf",
|
||||
modelPath: "/models/pylone/model.glb",
|
||||
stageUiPath: "/assets/world/UI/pylon-mission-notification.webm",
|
||||
interactUiPath: REPAIR_INTERACT_UI_PATH,
|
||||
brokenUiPath: REPAIR_BROKEN_UI_PATH,
|
||||
case: DEFAULT_REPAIR_CASE,
|
||||
reassemblySeconds: 1.8,
|
||||
requiredReplacementPartId: "pylon-grid-relay-replacement",
|
||||
scanPartSeconds: 1.4,
|
||||
brokenParts: [
|
||||
{
|
||||
id: "pylon-grid-relay",
|
||||
label: "Grid relay",
|
||||
nodeName: "lampe",
|
||||
caseSlotName: "placeholder_1",
|
||||
},
|
||||
{
|
||||
id: "pylon-damaged-panel",
|
||||
label: "Damaged solar panel",
|
||||
nodeName: "panneau2",
|
||||
caseSlotName: "placeholder_2",
|
||||
},
|
||||
requiredReplacementPartIds: [
|
||||
"pylon-cable-right-replacement",
|
||||
"pylon-cable-left-replacement",
|
||||
],
|
||||
scanPartSeconds: 1.4,
|
||||
brokenParts: [],
|
||||
replacementParts: [
|
||||
{
|
||||
id: "pylon-grid-relay-replacement",
|
||||
label: "Replacement grid relay",
|
||||
modelPath: "/models/pylone/model.gltf",
|
||||
id: "pylon-cable-right-replacement",
|
||||
label: "Câble droit",
|
||||
modelPath: "/models/cable1/model.gltf",
|
||||
caseAnchor: "cabledroit",
|
||||
caseLockGroup: "pylon-cable",
|
||||
targetNodeName: "cable2",
|
||||
},
|
||||
{
|
||||
id: "pylon-stone-distractor",
|
||||
label: "Stone counterweight",
|
||||
modelPath: "/models/galet/model.gltf",
|
||||
id: "pylon-cable-left-replacement",
|
||||
label: "Câble gauche",
|
||||
modelPath: "/models/cable2/model.gltf",
|
||||
caseAnchor: "cablegauche",
|
||||
caseLockGroup: "pylon-cable",
|
||||
targetNodeName: "cable2",
|
||||
},
|
||||
{
|
||||
id: "pylon-cooling-distractor",
|
||||
label: "Cooling core",
|
||||
label: "Refroidisseur",
|
||||
modelPath: "/models/refroidisseur/model.gltf",
|
||||
caseAnchor: "refroidisseur",
|
||||
},
|
||||
{
|
||||
id: "pylon-puce-haut-distractor",
|
||||
label: "Puce haute",
|
||||
modelPath: "/models/puce/model.gltf",
|
||||
caseAnchor: "pucehaut",
|
||||
},
|
||||
{
|
||||
id: "pylon-puce-bas-distractor",
|
||||
label: "Puce basse",
|
||||
modelPath: "/models/puce/model.gltf",
|
||||
caseAnchor: "pucebas",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -104,7 +135,7 @@ export const REPAIR_MISSIONS: Record<RepairMissionId, RepairMissionConfig> = {
|
||||
brokenUiPath: REPAIR_BROKEN_UI_PATH,
|
||||
case: DEFAULT_REPAIR_CASE,
|
||||
reassemblySeconds: 1.2,
|
||||
requiredReplacementPartId: "farm-irrigation-pump-replacement",
|
||||
requiredReplacementPartIds: ["farm-irrigation-pump-replacement"],
|
||||
scanPartSeconds: 0.9,
|
||||
brokenParts: [
|
||||
{
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
export const HAND_TRACKING_FRAME_WIDTH = 320;
|
||||
export const HAND_TRACKING_FRAME_HEIGHT = 240;
|
||||
// The browser MediaPipe model (hand_landmarker.task float16) is more
|
||||
// sensitive than the backend Python model and needs a higher-resolution
|
||||
// frame to detect hands reliably. The backend keeps 320x240 because that
|
||||
// is the JPEG payload size sent over the WebSocket.
|
||||
export const HAND_TRACKING_BROWSER_CAMERA_WIDTH = 640;
|
||||
export const HAND_TRACKING_BROWSER_CAMERA_HEIGHT = 480;
|
||||
export const HAND_TRACKING_TARGET_FPS = 10;
|
||||
export const HAND_TRACKING_JPEG_QUALITY = 0.55;
|
||||
export const HAND_TRACKING_CAMERA_TIMEOUT_MS = 8_000;
|
||||
@@ -8,9 +14,21 @@ export const HAND_TRACKING_BROWSER_WASM_URL =
|
||||
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.35/wasm";
|
||||
export const HAND_TRACKING_BROWSER_MODEL_URL =
|
||||
"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task";
|
||||
export const HAND_TRACKING_BROWSER_DELEGATE: "CPU" | "GPU" = "CPU";
|
||||
export const HAND_TRACKING_BROWSER_DELEGATE: "CPU" | "GPU" = "GPU";
|
||||
|
||||
// Delay before the runtime actually starts after `enabled` flips to true.
|
||||
// Absorbs React StrictMode's mount/unmount/mount cycle in dev and rapid
|
||||
// `nearby` toggles at trigger borders. Invisible to the user (~5 frames).
|
||||
export const HAND_TRACKING_RUNTIME_START_DELAY_MS = 80;
|
||||
|
||||
// How long the hand tracking stays active after the trigger condition
|
||||
// (nearby / holding / repair step) turns off. Gives MediaPipe enough time
|
||||
// to initialize webcam + model + first frame inference before we cleanup,
|
||||
// so the user actually sees their hands when entering a zone briefly.
|
||||
export const HAND_TRACKING_LINGER_MS = 2000;
|
||||
|
||||
// EMA weight applied to the latest landmark frame. Lower = smoother but
|
||||
// laggier; higher = more responsive but more jitter from raw MediaPipe
|
||||
// noise. 0.4 keeps the glove and grabbed objects from trembling without
|
||||
// feeling sluggish.
|
||||
export const HAND_TRACKING_LANDMARK_SMOOTHING = 0.4;
|
||||
|
||||
@@ -9,7 +9,7 @@ export const MAP_INSTANCING_ASSETS = {
|
||||
},
|
||||
pylone: {
|
||||
mapName: "pylone",
|
||||
modelPath: "/models/pylone/model.gltf",
|
||||
modelPath: "/models/pylone/model.glb",
|
||||
scaleMultiplier: 1,
|
||||
castShadow: true,
|
||||
receiveShadow: true,
|
||||
|
||||
Reference in New Issue
Block a user