Files
Art-gallery/client/src/components/HallPassage.tsx
T
Danila KhodjaefandCursor f6c73c1792 Smooth 3D hall boot: disable shadows and warm door shaders under the loading overlay.
Keep Loading gallery until Environment and gl.compileAsync finish (with timeouts), GPU-upload painting textures before dismiss, and drop Canvas shadow maps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 15:32:10 +03:00

107 lines
3.5 KiB
TypeScript

import { useState } from 'react';
import * as THREE from 'three';
import { Text } from '@react-three/drei';
const DOOR_WIDTH = 2.4;
const DOOR_HEIGHT = 2.5;
const WALL_THICKNESS = 0.18;
/** Open archway connecting to the next movement wing. */
export default function HallPassage({
position,
active,
label,
onActivate,
wallColor = '#f0ebe3',
trimColor = '#ddd5c8',
}: {
position: [number, number, number];
active: boolean;
label: string;
onActivate: () => void;
wallColor?: string;
trimColor?: string;
}) {
const [hovered, setHovered] = useState(false);
const highlight = active || hovered;
const openingW = DOOR_WIDTH;
const openingH = DOOR_HEIGHT;
const jamb = 0.12;
const faceZ = 0.04;
const handleActivate = (e: THREE.Event & { stopPropagation: () => void }) => {
e.stopPropagation();
onActivate();
};
return (
<group position={position}>
<pointLight position={[0, openingH * 0.5, 0.3]} intensity={highlight ? 0.9 : 0.5} distance={5} color="#fff4e8" />
{/* Depth beyond passage */}
<mesh position={[0, openingH * 0.5, 0.15]}>
<planeGeometry args={[openingW * 0.9, openingH * 0.95]} />
<meshStandardMaterial color="#fff8f0" emissive="#ffe8c8" emissiveIntensity={highlight ? 0.28 : 0.14} />
</mesh>
{/* Side jambs */}
{([-1, 1] as const).map((sign) => (
<mesh key={sign} position={[sign * (openingW / 2 + jamb / 2), openingH / 2, faceZ]}>
<boxGeometry args={[jamb, openingH + 0.1, 0.1]} />
<meshStandardMaterial color={trimColor} roughness={0.45} metalness={0.25} />
</mesh>
))}
{/* Arch header */}
<mesh position={[0, openingH + 0.06, faceZ]}>
<boxGeometry args={[openingW + jamb * 2, 0.14, 0.1]} />
<meshStandardMaterial color={trimColor} roughness={0.4} metalness={0.3} />
</mesh>
<mesh position={[0, openingH + 0.22, faceZ]} rotation={[0, 0, Math.PI]}>
<sphereGeometry args={[openingW / 2 + 0.04, 16, 8, 0, Math.PI * 2, 0, Math.PI / 2]} />
<meshStandardMaterial color={wallColor} roughness={0.88} />
</mesh>
<group position={[0, openingH + 0.38, faceZ - 0.01]}>
<mesh onClick={handleActivate} onPointerOver={() => setHovered(true)} onPointerOut={() => setHovered(false)}>
<boxGeometry args={[1.4, 0.18, 0.02]} />
<meshStandardMaterial
color={highlight ? '#d4af37' : trimColor}
roughness={0.3}
metalness={0.5}
emissive={highlight ? '#5a4010' : '#000000'}
emissiveIntensity={highlight ? 0.2 : 0}
/>
</mesh>
<Text
position={[0, 0, -0.012]}
rotation={[0, Math.PI, 0]}
fontSize={0.1}
color={highlight ? '#fff8e8' : '#4a3020'}
anchorX="center"
anchorY="middle"
onClick={handleActivate}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
{label.toUpperCase()}
</Text>
</group>
<mesh
position={[0, openingH / 2, faceZ - 0.12]}
rotation={[0, Math.PI, 0]}
onClick={handleActivate}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
<planeGeometry args={[openingW * 1.1, openingH * 1.05]} />
<meshBasicMaterial transparent opacity={0} depthWrite={false} side={THREE.DoubleSide} />
</mesh>
</group>
);
}
export { DOOR_WIDTH, DOOR_HEIGHT, WALL_THICKNESS };