import { useMemo } from 'react'; import type { MovementInteriorStyle, GalleryWindowSpec } from '../data/movement-interior-styles'; import type { RoomDims } from './hall-details/geometry'; import { CinquecentoDetails, QuattrocentoDetails, RomanAtriumDetails, } from './hall-details/classical'; import { BaroqueStateDetails, FlemishDetails, ManneristDetails, NeoclassicalDetails, RococoDetails, } from './hall-details/courtly'; import { ArtNouveauDetails, BourgeoisSalonDetails, GothicRevivalDetails, NorthLightSalonDetails, ParisAtelierDetails, SymbolistDetails, } from './hall-details/nineteenth'; import { ConstructivistDetails, CubistAtelierDetails, DadaDetails, ExpressionistDetails, FauvistDetails, FuturistDetails, LoftDetails, SuprematistDetails, SurrealistDetails, WhiteCubeDetails, } from './hall-details/modernism'; interface Props { style: MovementInteriorStyle; width: number; depth: number; halfW: number; halfD: number; /** Runtime window placement, so upper-wall relief can step around openings. */ windows?: GalleryWindowSpec[]; } function GothicDetails({ width, depth, halfW, halfD, trim }: Omit & { trim: string }) { // Compound piers along the side walls, spaced by bay, each rising into the // vault springer. Shafts stay flush against the wall (0.16 m proud) so they // never intrude on the ~0.7 m frame hang margin. const bays = useMemo(() => { const spacing = 4.2; const count = Math.max(2, Math.min(9, Math.floor(depth / spacing))); const step = depth / (count + 1); return Array.from({ length: count }, (_, i) => -halfD + step * (i + 1)); }, [depth, halfD]); const shaftHeight = 3.5; return ( {bays.map((z, i) => ( {[-1, 1].map((side) => ( {/* Compound pier: a heavier centre shaft flanked by colonnettes */} {[-0.17, 0.17].map((dz) => ( ))} {/* Moulded base and foliate capital */} {/* Vault springer resting on the capital */} ))} {/* Transverse rib arching across the nave between opposite piers */} {Array.from({ length: 9 }, (_, s) => { const segs = 9; const t0 = s / segs; const t1 = (s + 1) / segs; const xAt = (t: number) => -halfW + 0.09 + t * (halfW - 0.09) * 2; const yAt = (t: number) => Math.sin(Math.PI * t) * 0.34; const x0 = xAt(t0); const x1 = xAt(t1); const y0 = yAt(t0); const y1 = yAt(t1); const len = Math.hypot(x1 - x0, y1 - y0); return ( ); })} ))} {/* Moulded string course running the length of both side walls */} {[-1, 1].map((side) => ( ))} {/* Chancel-style cornice on the end wall */} ); } function ByzantineDetails({ halfW, halfD, trim }: Pick & { trim: string }) { // Engaged porphyry colonnettes with Byzantine basket/impost capitals at the // corners (flush — never proud of the ~0.7m frame hang margin), a marble // revetment dado at spring-line height, and hanging brass polycandela in // place of wall torches (a Byzantine basilica hangs its light, not sconces it). const colonnettes = useMemo( () => [ [-halfW + 0.08, -halfD + 0.08], [halfW - 0.08, -halfD + 0.08], [-halfW + 0.08, halfD - 0.08], [halfW - 0.08, halfD - 0.08], ] as [number, number][], [halfW, halfD] ); const lampPositions = useMemo( () => [ [0, -halfD * 0.32], [0, halfD * 0.18], ] as [number, number][], [halfD] ); const dadoW = Math.max(0, halfW * 2 - 0.3); const dadoD = Math.max(0, halfD * 2 - 0.3); return ( {/* Marble revetment dado — imperial banding course at chair-rail height */} {[ [0, -halfD + 0.07, dadoW, 0.1] as const, [0, halfD - 0.07, dadoW, 0.1] as const, [-halfW + 0.07, 0, 0.1, dadoD] as const, [halfW - 0.07, 0, 0.1, dadoD] as const, ].map(([x, z, w, d], i) => ( ))} {/* Engaged colonnettes, basket capital, and impost block */} {colonnettes.map(([x, z], i) => ( {/* Polished porphyry shaft — the imperial stone of the reference basilicas */} {/* Basket capital in white marble, then an impost block carrying the ceiling */} ))} {/* Hanging polycandela — brass ring lamps suspended from the vault */} {lampPositions.map(([x, z], i) => ( {Array.from({ length: 6 }, (_, j) => { const a = (j / 6) * Math.PI * 2; return ( ); })} ))} ); } /** * Period architecture for a movement hall. * * Every movement has its own interior, built from the architecture of the same * period as the movement itself. The Gothic nave and Byzantine basilica below * are the reference implementations; everything else lives in * `hall-details/`, sharing the geometry budget documented in * `hall-details/primitives.tsx`. */ export default function MovementHallDetails({ style, width, depth, halfW, halfD, windows }: Props) { const trim = style.tints.trim; const room: RoomDims = useMemo( () => ({ width, depth, halfW, halfD }), [width, depth, halfW, halfD] ); const period = { room, trim, windows }; switch (style.details) { case 'gothic': return ; case 'byzantine': return ; case 'roman': return ; case 'quattrocento': return ; case 'cinquecento': return ; case 'flemish': return ; case 'mannerist': return ; case 'baroque': return ; case 'rococo': return ; case 'neoclassical': return ; case 'gothic-revival': return ; case 'bourgeois': return ; case 'north-light': return ; case 'paris-atelier': return ; case 'symbolist': return ; case 'art-nouveau': return ; case 'fauvist': return ; case 'expressionist': return ; case 'cubist-atelier': return ; case 'futurist': return ; case 'suprematist': return ; case 'constructivist': return ; case 'dada': return ; case 'surrealist': return ; case 'loft': return ; case 'white-cube': return ; } }