Feat/polish-mission1 #12

Merged
math-pixel merged 42 commits from feat/polish-mission1 into develop 2026-06-01 21:51:09 +00:00
2 changed files with 35 additions and 11 deletions
Showing only changes of commit 3b07f40f2d - Show all commits
+31 -10
View File
@@ -14,7 +14,16 @@ const TALKIE_REVEAL_STEPS = new Set([
"completed",
]);
function TalkieModel(): React.JSX.Element {
const TALKIE_REST_Y = -0.55;
const TALKIE_ACTIVE_Y = -0.18;
const TALKIE_FLOAT_Y_AMPLITUDE = 0.025;
const TALKIE_FLOAT_ROTATION_AMPLITUDE = THREE.MathUtils.degToRad(1.6);
interface TalkieModelProps {
active: boolean;
}
function TalkieModel({ active }: TalkieModelProps): React.JSX.Element {
const { scene } = useGLTF(TALKIE_MODEL_PATH);
const model = useMemo(() => scene.clone(true), [scene]);
const groupRef = useRef<THREE.Group>(null);
@@ -33,15 +42,26 @@ function TalkieModel(): React.JSX.Element {
if (!groupRef.current) return;
const t = clock.getElapsedTime();
groupRef.current.rotation.z = Math.sin(t * 22) * 0.025;
groupRef.current.position.y = Math.sin(t * 6) * 0.012;
const floatY = Math.sin(t * 1.4) * TALKIE_FLOAT_Y_AMPLITUDE;
const targetY = (active ? TALKIE_ACTIVE_Y : TALKIE_REST_Y) + floatY;
groupRef.current.position.y = THREE.MathUtils.lerp(
groupRef.current.position.y,
targetY,
0.14,
);
if (active) {
groupRef.current.rotation.z = Math.sin(t * 22) * 0.025;
} else {
groupRef.current.rotation.z =
Math.sin(t * 0.8) * TALKIE_FLOAT_ROTATION_AMPLITUDE;
}
});
return (
<group ref={groupRef}>
<group ref={groupRef} position={[0, TALKIE_REST_Y, 0]}>
<primitive
object={model}
position={[0, -0.18, 0]}
rotation={[0.18, Math.PI, -0.08]}
scale={1.45}
/>
@@ -73,11 +93,12 @@ export function TalkieDialogueOverlay(): React.JSX.Element | null {
if (!isAfterReveal) return null;
const overlayClassName = isNarratorDialogue
? "talkie-dialogue-overlay talkie-dialogue-overlay--active talkie-dialogue-overlay--raised"
: "talkie-dialogue-overlay";
return (
<aside
className={`talkie-dialogue-overlay${isNarratorDialogue ? " talkie-dialogue-overlay--raised" : ""}`}
aria-hidden="true"
>
<aside className={overlayClassName} aria-hidden="true">
{isNarratorDialogue ? <TalkieSignalLines /> : null}
<div className="talkie-dialogue-overlay__model-frame">
<Canvas
@@ -89,7 +110,7 @@ export function TalkieDialogueOverlay(): React.JSX.Element | null {
<ambientLight intensity={2.5} />
<directionalLight position={[2, 3, 4]} intensity={2.8} />
<Suspense fallback={null}>
<TalkieModel />
<TalkieModel active={isNarratorDialogue} />
</Suspense>
</Canvas>
</div>
+4 -1
View File
@@ -1257,10 +1257,13 @@ canvas {
.talkie-dialogue-overlay__model-frame {
position: absolute;
inset: 0;
animation: talkie-radio-shake 1s ease-in-out infinite;
filter: drop-shadow(0 16px 22px rgba(0, 0, 0, 0.55));
}
.talkie-dialogue-overlay--active .talkie-dialogue-overlay__model-frame {
animation: talkie-radio-shake 1s ease-in-out infinite;
}
.talkie-dialogue-overlay__model-frame canvas {
width: 100% !important;
height: 100% !important;