add: repair fragmentation and scan flow

This commit is contained in:
Tom Boullay
2026-05-08 01:39:23 +01:00
parent f5da2f4994
commit eed0077dd1
11 changed files with 228 additions and 17 deletions
@@ -0,0 +1,53 @@
import { useCallback, useEffect, useRef } from "react";
import { REPAIR_FRAGMENTATION_FIST_HOLD_SECONDS } from "@/data/gameplay/repairGameConfig";
import { INTERACT_KEY } from "@/data/input/keybindings";
import { useBothFistsHold } from "@/hooks/handTracking/useBothFistsHold";
interface UseRepairFragmentationInputOptions {
enabled: boolean;
onFragment: () => void;
}
export function useRepairFragmentationInput({
enabled,
onFragment,
}: UseRepairFragmentationInputOptions): void {
const completedRef = useRef(false);
useEffect(() => {
if (enabled) return;
completedRef.current = false;
}, [enabled]);
const fragment = useCallback(() => {
if (!enabled) return;
if (completedRef.current) return;
completedRef.current = true;
onFragment();
}, [enabled, onFragment]);
useEffect(() => {
if (!enabled) return undefined;
const handleKeyDown = (event: KeyboardEvent): void => {
if (event.key.toLowerCase() !== INTERACT_KEY) return;
event.preventDefault();
fragment();
};
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [enabled, fragment]);
useBothFistsHold({
enabled,
holdSeconds: REPAIR_FRAGMENTATION_FIST_HOLD_SECONDS,
onComplete: fragment,
});
}
@@ -0,0 +1,48 @@
import { useEffect, useRef } from "react";
import { useFrame } from "@react-three/fiber";
import { useHandTrackingSnapshot } from "@/hooks/handTracking/useHandTrackingSnapshot";
interface UseBothFistsHoldOptions {
enabled: boolean;
holdSeconds: number;
onComplete: () => void;
}
export function useBothFistsHold({
enabled,
holdSeconds,
onComplete,
}: UseBothFistsHoldOptions): void {
const { hands } = useHandTrackingSnapshot();
const elapsedRef = useRef(0);
const completedRef = useRef(false);
const onCompleteRef = useRef(onComplete);
useEffect(() => {
onCompleteRef.current = onComplete;
}, [onComplete]);
useEffect(() => {
if (enabled) return;
elapsedRef.current = 0;
completedRef.current = false;
}, [enabled]);
useFrame((_, delta) => {
if (!enabled) return;
if (completedRef.current) return;
const fistCount = hands.filter((hand) => hand.isFist).length;
if (fistCount < 2) {
elapsedRef.current = 0;
return;
}
elapsedRef.current += delta;
if (elapsedRef.current < holdSeconds) return;
completedRef.current = true;
onCompleteRef.current();
});
}