Add movement gallery wings with period interiors and expand timeline features.
Movement galleries split large catalogs into chronological wings (~55 works), use era-themed 3D interiors with side-wall windows, wing navigator on the back exit, and front archways between wings. Also adds painting annotations, timeline event guides, portrait hover highlights, and documentation/API updates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
0972b5df99
commit
df29848d89
@@ -0,0 +1,106 @@
|
||||
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]} castShadow>
|
||||
<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]} castShadow>
|
||||
<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 };
|
||||
Reference in New Issue
Block a user