add: focus repair case view

This commit is contained in:
Tom Boullay
2026-05-08 02:22:15 +01:00
parent 19dbcf6d15
commit d243872862
7 changed files with 35 additions and 15 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ This document lists features that are implemented in the current codebase.
- Reusable production `RepairGame` mounted for `bike`, `pylone`, and `ferme` mission states
- Repair mission config shared through `src/data/gameplay/repairMissions.ts`
- Repair-game flow supports `waiting -> inspected -> fragmented -> scanning -> repairing -> done -> next mission` with `.webm` prompts, repair case spawn/opening/exit, `E`, two-fists hold input, exploded model transition, per-part scan visuals, persistent red broken-part markers, centered broken-part UI videos, multiple grabbable replacement choices, correct-part install validation, and mission completion
- Repair-game flow supports `waiting -> inspected -> fragmented -> scanning -> repairing -> done -> next mission` with `.webm` prompts, repair case spawn/opening/exit, focused repair-case view, `E`, two-fists hold input, exploded model transition, per-part scan visuals, persistent red broken-part markers, centered broken-part UI videos, multiple grabbable replacement choices, correct-part install validation, and mission completion
## Audio
+2 -2
View File
@@ -16,7 +16,7 @@ The current user flow is:
6. Press `E` or hold both fists closed for one second to move from `inspected` to `fragmented`.
7. The mission object uses an exploded-model transition, then moves to `scanning`.
8. The scan visual moves across the fragmented model one part at a time and keeps a red marker plus the `cassé.webm` prompt centered on any configured broken part once it has been found.
9. In `repairing`, the case opens and several grabbable replacement parts appear near the case.
9. In `repairing`, the case opens in a larger focused view and several grabbable replacement parts appear near it.
10. Move the correct replacement part close to the install target.
11. Press `E` on the green install target to move to `done` and show the reassembled object. Wrong parts turn the target red and cannot finish the repair.
12. Press `E` on the completion target. The repair case closes, returns to the ground, disappears, then `completeMission` moves to the next mission or to `outro` after `ferme`.
@@ -33,7 +33,7 @@ When the player inspects the object, `RepairGame` writes `inspected` through the
In `inspected`, `RepairGame` can also move to `fragmented`. The player can use the interaction key or hold both fists closed for one second. The hand-tracking path is state-based, so it does not depend on being inside a local object interaction radius.
In `fragmented`, the repair object is rendered with `ExplodableModel`, then automatically advances to `scanning`. In `scanning`, the exploded model remains visible, a blue scan visual moves from part to part, and a red halo/wire marker plus the configured broken UI video stay attached to configured broken parts after the scanner reaches them. The scan can match a specific `nodeName` when mission data provides one, otherwise it falls back to the first scanned parts as placeholder broken parts. In `repairing`, the case opens, several grabbable replacement parts appear, and the install target only validates the configured correct part for the active mission. In `done`, the repaired object remains visible with a completion target that plays the case exit animation before advancing the global mission progression.
In `fragmented`, the repair object is rendered with `ExplodableModel`, then automatically advances to `scanning`. In `scanning`, the exploded model remains visible, a blue scan visual moves from part to part, and a red halo/wire marker plus the configured broken UI video stay attached to configured broken parts after the scanner reaches them. The scan can match a specific `nodeName` when mission data provides one, otherwise it falls back to the first scanned parts as placeholder broken parts. In `repairing`, the case opens in a larger focused transform, several grabbable replacement parts appear around that focused case view, and the install target only validates the configured correct part for the active mission. In `done`, the repaired object remains visible with a completion target that plays the case exit animation before advancing the global mission progression.
## Key Files
@@ -92,6 +92,7 @@ export function RepairGame({
<RepairMissionCase
config={config}
open={step === "repairing"}
zoomed={step === "repairing"}
showFragmentationPrompt={readyForFragmentation}
/>
) : null}
@@ -1,6 +1,10 @@
import { RepairCaseModel } from "@/components/three/gameplay/RepairCaseModel";
import { RepairPromptVideo } from "@/components/three/gameplay/RepairPromptVideo";
import { REPAIR_CASE_MODEL_PATH } from "@/data/gameplay/repairCaseConfig";
import {
REPAIR_CASE_FOCUS_POSITION,
REPAIR_CASE_FOCUS_SCALE,
REPAIR_CASE_MODEL_PATH,
} from "@/data/gameplay/repairCaseConfig";
import type { RepairMissionConfig } from "@/data/gameplay/repairMissions";
interface RepairMissionCaseProps {
@@ -8,6 +12,7 @@ interface RepairMissionCaseProps {
exiting?: boolean;
onExitComplete?: (() => void) | undefined;
open?: boolean;
zoomed?: boolean;
showFragmentationPrompt?: boolean;
}
@@ -16,8 +21,14 @@ export function RepairMissionCase({
exiting = false,
onExitComplete,
open = false,
zoomed = false,
showFragmentationPrompt = false,
}: RepairMissionCaseProps): React.JSX.Element {
const casePosition = zoomed
? REPAIR_CASE_FOCUS_POSITION
: config.case.position;
const caseScale = zoomed ? REPAIR_CASE_FOCUS_SCALE : config.case.scale;
return (
<group>
<RepairCaseModel
@@ -25,14 +36,14 @@ export function RepairMissionCase({
exiting={exiting}
onExitComplete={onExitComplete}
open={open}
position={config.case.position}
position={casePosition}
rotation={config.case.rotation}
scale={config.case.scale}
scale={caseScale}
/>
{showFragmentationPrompt && !exiting ? (
<RepairPromptVideo
src={config.interactUiPath}
position={[config.case.position[0], 2.4, config.case.position[2]]}
position={[casePosition[0], 2.4, casePosition[2]]}
size={80}
/>
) : null}
@@ -4,6 +4,7 @@ import { RepairObjectModel } from "@/components/three/gameplay/RepairObjectModel
import { RepairPromptVideo } from "@/components/three/gameplay/RepairPromptVideo";
import { GrabbableObject } from "@/components/three/interaction/GrabbableObject";
import { TriggerObject } from "@/components/three/interaction/TriggerObject";
import { REPAIR_CASE_FOCUS_POSITION } from "@/data/gameplay/repairCaseConfig";
import type {
RepairMissionConfig,
RepairMissionPartConfig,
@@ -13,9 +14,9 @@ import type { Vector3Tuple } from "@/types/three/three";
const INSTALL_TARGET_POSITION: Vector3Tuple = [0, 0.8, 0];
const INSTALL_TARGET_VECTOR = new THREE.Vector3(...INSTALL_TARGET_POSITION);
const REPLACEMENT_START_OFFSETS: Vector3Tuple[] = [
[-0.9, 1.35, 1.8],
[0, 1.35, 2.15],
[0.9, 1.35, 1.8],
[-1.15, 1, 0.25],
[0, 1.05, 0.45],
[1.15, 1, 0.25],
];
const REPAIR_INSTALL_RADIUS = 1.1;
@@ -109,9 +110,9 @@ export function RepairRepairingStep({
<GrabbableObject
key={part.id}
position={[
config.case.position[0] + offset[0],
config.case.position[1] + offset[1],
config.case.position[2] + offset[2],
REPAIR_CASE_FOCUS_POSITION[0] + offset[0],
REPAIR_CASE_FOCUS_POSITION[1] + offset[1],
REPAIR_CASE_FOCUS_POSITION[2] + offset[2],
]}
colliders="ball"
handControlled
@@ -123,7 +124,7 @@ export function RepairRepairingStep({
<RepairObjectModel
label={part.label}
modelPath={part.modelPath ?? config.modelPath}
scale={0.28}
scale={0.36}
/>
</GrabbableObject>
);
+1 -1
View File
@@ -442,7 +442,7 @@ Ce document liste les fonctionnalités présentes dans le code actuel.
- \`RepairGame\` de production réutilisable monté pour les états de mission \`bike\`, \`pylone\` et \`ferme\`
- Configuration de mission partagée via \`src/data/gameplay/repairMissions.ts\`
- Flow repair-game avec \`waiting -> inspected -> fragmented -> scanning -> repairing -> done -> next mission\`, prompts \`.webm\`, apparition/ouverture/sortie de la mallette, touche \`E\`, hold deux poings, transition de modèle explosé, scan visuel par pièce, marqueur rouge persistant et vidéo UI centrée sur les pièces cassées, plusieurs choix de pièces grabbables, validation de la bonne pièce et complétion de mission
- Flow repair-game avec \`waiting -> inspected -> fragmented -> scanning -> repairing -> done -> next mission\`, prompts \`.webm\`, apparition/ouverture/sortie de la mallette, vue focalisée de la mallette, touche \`E\`, hold deux poings, transition de modèle explosé, scan visuel par pièce, marqueur rouge persistant et vidéo UI centrée sur les pièces cassées, plusieurs choix de pièces grabbables, validation de la bonne pièce et complétion de mission
## Audio
+7
View File
@@ -1,3 +1,5 @@
import type { Vector3Tuple } from "@/types/three/three";
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";
@@ -17,3 +19,8 @@ export const REPAIR_CASE_FLOAT_UP_SPEED = 2.4;
export const REPAIR_CASE_FLOAT_DOWN_SPEED = 1.8;
export const REPAIR_CASE_ROTATION_RESET_SPEED = 3;
export const REPAIR_CASE_ROTATION_AMPLITUDE_DEGREES = 5;
export const REPAIR_CASE_FOCUS_POSITION = [
0, 1.05, 2.05,
] satisfies Vector3Tuple;
export const REPAIR_CASE_FOCUS_SCALE = 2.25;