three-low-poly 0.9.27 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.iife.js","names":[],"sources":["../src/animators/cameraClip.ts","../src/animators/CameraPlayback.ts","../src/constants/Easing.ts","../src/animators/cameraClips.ts","../src/constants/Direction.ts","../src/constants/Falloff.ts","../src/brushes/DisplacementBrush.ts","../src/brushes/FlattenBrush.ts","../src/brushes/NoiseBrush.ts","../src/brushes/SmoothBrush.ts","../src/brushes/SpikeBrush.ts","../src/brushes/TwistBrush.ts","../src/constants/Axis.ts","../src/constants/BoxSide.ts","../src/constants/ColorPalette.ts","../src/constants/ParametricCurve.ts","../src/utils/Random.ts","../src/utils/RandomNumberUtils.ts","../src/effects/EffervescenceEffect.ts","../src/effects/FlameFlickerEffect.ts","../src/effects/GroundFogEffect.ts","../src/effects/GlowHalo.ts","../src/effects/EmissivePulseEffect.ts","../src/effects/LightningEffect.ts","../src/geometry/leafs/EllipticLeafGeometry.ts","../src/effects/PetalDriftEffect.ts","../src/effects/RainEffect.ts","../src/effects/WispEffect.ts","../src/shapes/BurstShape.ts","../src/geometry/shapes/BurstGeometry.ts","../src/effects/StarFieldEffect.ts","../src/geometry/books/BookGeometry.ts","../src/factory/BookFactory.ts","../src/shapes/HexagonShape.ts","../src/geometry/shapes/HexagonGeometry.ts","../src/factory/HexagonalTileFactory.ts","../src/geometry/rocks/MossyRockGeometry.ts","../src/utils/VertexUtils.ts","../src/geometry/rocks/RockGeometry.ts","../src/factory/RockFactory.ts","../src/geometry/architecture/diamondLattice.ts","../src/geometry/architecture/ArchedDiamondLatticeWindowGeometry.ts","../src/geometry/architecture/DiamondLatticeWindowGeometry.ts","../src/geometry/architecture/gregorianLattice.ts","../src/geometry/architecture/GregorianLatticeWindowGeometry.ts","../src/geometry/architecture/ringLattice.ts","../src/geometry/architecture/staircaseQuad.ts","../src/geometry/architecture/LShapedStaircaseGeometry.ts","../src/geometry/architecture/SpiralStaircaseGeometry.ts","../src/geometry/architecture/StaircaseGeometry.ts","../src/geometry/bottles/JarGeometry.ts","../src/utils/LineEquations.ts","../src/geometry/bottles/PotionBottleGeometry.ts","../src/geometry/bottles/WineBottleGeometry.ts","../src/geometry/cemetery/CrossHeadstoneGeometry.ts","../src/geometry/cemetery/MausoleumGeometry.ts","../src/geometry/cemetery/ObeliskHeadstoneGeometry.ts","../src/geometry/cemetery/RoundedHeadstoneGeometry.ts","../src/geometry/cemetery/SquareHeadstoneGeometry.ts","../src/geometry/fence/StoneFencePostGeometry.ts","../src/geometry/fence/WroughtIronBarGeometry.ts","../src/geometry/fence/WroughtIronFenceGeometry.ts","../src/geometry/furniture/BookshelfGeometry.ts","../src/geometry/furniture/DeskGeometry.ts","../src/geometry/leafs/LeafGeometry.ts","../src/geometry/lighting/FlameGeometry.ts","../src/geometry/lighting/CandleGeometry.ts","../src/geometry/lighting/LanternGeometry.ts","../src/geometry/lighting/barBetween.ts","../src/geometry/lighting/HangingLanternGeometry.ts","../src/geometry/lighting/WallSconceGeometry.ts","../src/geometry/primitives/ParallelogramBoxGeometry.ts","../src/shapes/GearShape.ts","../src/geometry/shapes/GearGeometry.ts","../src/shapes/HeartShape.ts","../src/geometry/shapes/HeartGeometry.ts","../src/shapes/StarShape.ts","../src/geometry/shapes/StarGeometry.ts","../src/geometry/skeleton/BoneGeometry.ts","../src/geometry/science/ErlenmeyerFlaskGeometry.ts","../src/utils/SphericalGeometryUtils.ts","../src/utils/SphericalCurve.ts","../src/geometry/science/FlorenceFlaskGeometry.ts","../src/geometry/science/MortarGeometry.ts","../src/geometry/science/StandGeometry.ts","../src/geometry/science/TeslaCoilGeometry.ts","../src/geometry/science/TestTubeGeometry.ts","../src/geometry/terrain/HillGeometry.ts","../src/geometry/terrain/MoundGeometry.ts","../src/geometry/trees/TreeGeometry.ts","../src/models/architecture/LShapedStaircase.ts","../src/models/architecture/SpiralStaircase.ts","../src/models/architecture/Staircase.ts","../src/models/architecture/ArchedDiamondLatticeWindow.ts","../src/models/architecture/DiamondLatticeWindow.ts","../src/models/architecture/GregorianLatticeWindow.ts","../src/models/architecture/RingLatticeWindow.ts","../src/models/books/Book.ts","../src/models/bottles/Jar.ts","../src/models/bottles/PotionBottle.ts","../src/models/bottles/WineBottle.ts","../src/models/cemetery/CrossHeadstone.ts","../src/models/cemetery/Mausoleum.ts","../src/models/cemetery/ObeliskHeadstone.ts","../src/models/cemetery/RoundedHeadstone.ts","../src/models/cemetery/SquareHeadstone.ts","../src/models/fence/StoneFencePost.ts","../src/models/fence/WroughtIronBar.ts","../src/models/fence/WroughtIronFence.ts","../src/models/furniture/Bookshelf.ts","../src/models/furniture/Desk.ts","../src/models/leafs/Leaf.ts","../src/models/lighting/Candle.ts","../src/models/lighting/Flame.ts","../src/models/lighting/HangingLantern.ts","../src/models/lighting/WallSconce.ts","../src/models/lighting/Lantern.ts","../src/models/rocks/MossyRock.ts","../src/models/rocks/Rock.ts","../src/models/science/BunsenBurner.ts","../src/models/science/ElectricPanel.ts","../src/models/science/ErlenmeyerFlask.ts","../src/models/science/FlorenceFlask.ts","../src/models/science/LeverPanel.ts","../src/models/science/Microscope.ts","../src/models/science/MortarAndPestle.ts","../src/models/science/Panel.ts","../src/models/science/PanelLight.ts","../src/models/science/SpiralTube.ts","../src/models/science/Stand.ts","../src/models/science/TeslaCoil.ts","../src/models/science/TestTube.ts","../src/models/science/TestTubeRack.ts","../src/models/shapes/Burst.ts","../src/models/shapes/Gear.ts","../src/models/shapes/Heart.ts","../src/models/shapes/Hexagon.ts","../src/models/shapes/Star.ts","../src/models/skeleton/Bone.ts","../src/models/trees/Tree.ts","../src/models/terrain/Hill.ts","../src/models/terrain/Mound.ts","../src/shaders/addInstanceColor.ts","../src/shaders/addWaterDisplacement.ts","../src/shaders/addNoiseDisplacement.ts","../src/shaders/atmosphericShader.ts","../src/shaders/blurTransitionShader.ts","../src/shaders/crossfadeShader.ts","../src/shaders/daySkyShader.ts","../src/shaders/fadeShader.ts","../src/shaders/fadeTransitionSceneShader.ts","../src/shaders/nightSkyShader.ts","../src/skybox/AtmosphericSkybox.ts","../src/skybox/DaySkybox.ts","../src/skybox/NightSkybox.ts","../src/textures/checkerboard.ts","../src/transitions/CameraTransition.ts","../src/transitions/SceneTransition.ts","../src/transitions/SceneTransitionFX.ts","../src/utils/AlignToEdge.ts","../src/utils/AlignToRow.ts","../src/utils/AlignToSurface.ts","../src/utils/Center.ts","../src/utils/ColorUtils.ts","../src/utils/FindClosestPoint.ts","../src/utils/InterpolateCurve.ts","../src/utils/ParametricCurveUtils.ts","../src/utils/QuadUtils.ts","../src/utils/RandomTimer.ts","../src/utils/UVUtils.ts"],"sourcesContent":["import { PerspectiveCamera, Quaternion, Vector3 } from \"three\";\nimport type { OrbitControls } from \"three/addons/controls/OrbitControls.js\";\nimport type { EasingFunction } from \"../constants/Easing\";\n\nexport type ClipPhase = \"running\" | \"complete\";\n\n/** Rest pose captured when playback is constructed or reset. */\nexport interface CameraSnapshot {\n position: Vector3;\n quaternion: Quaternion;\n fov: number;\n target: Vector3;\n}\n\n/** Per-frame mutable state shared with the active clip. */\nexport interface ClipRuntime {\n camera: PerspectiveCamera;\n controls: OrbitControls | null;\n /** Seconds elapsed in the active clip. */\n elapsed: number;\n /** Clip duration in seconds. */\n duration: number;\n /** Look-at point the clip is focused on — synced to OrbitControls on complete. */\n focus: Vector3;\n}\n\nexport interface CameraClip {\n readonly label: string;\n readonly duration: number;\n start(runtime: ClipRuntime): void;\n update(runtime: ClipRuntime, dt: number): ClipPhase;\n /** Called when playback is cancelled mid-clip. */\n cancel?(runtime: ClipRuntime): void;\n}\n\nexport interface CameraClipTiming {\n /** Duration in seconds. */\n duration: number;\n /** Progress easing for normalized time `t` in [0, 1]. Defaults to smoothstep. */\n ease?: EasingFunction;\n}\n\nexport function captureSnapshot(\n camera: PerspectiveCamera,\n controls?: OrbitControls,\n): CameraSnapshot {\n const target = controls?.target.clone() ?? new Vector3();\n if (!controls) {\n const dir = new Vector3();\n camera.getWorldDirection(dir);\n target.copy(camera.position).add(dir);\n }\n return {\n position: camera.position.clone(),\n quaternion: camera.quaternion.clone(),\n fov: camera.fov,\n target,\n };\n}\n\nexport function applySnapshot(\n camera: PerspectiveCamera,\n controls: OrbitControls | undefined,\n snapshot: CameraSnapshot,\n): void {\n camera.position.copy(snapshot.position);\n camera.quaternion.copy(snapshot.quaternion);\n camera.fov = snapshot.fov;\n camera.updateProjectionMatrix();\n if (controls) {\n controls.target.copy(snapshot.target);\n controls.update();\n }\n}\n\nexport function normalizedTime(runtime: ClipRuntime, ease: EasingFunction): number {\n const t = Math.min(1, runtime.elapsed / runtime.duration);\n return ease(t);\n}","import { PerspectiveCamera, Vector3 } from \"three\";\nimport type { OrbitControls } from \"three/addons/controls/OrbitControls.js\";\nimport {\n applySnapshot,\n captureSnapshot,\n type CameraClip,\n type CameraSnapshot,\n type ClipRuntime,\n} from \"./cameraClip\";\n\n/**\n * Single director for camera showcase clips — Unity demo-scene style playback.\n *\n * One active clip at a time, driven by {@link update} with elapsed seconds (`dt`),\n * not nested `requestAnimationFrame` loops. Disables OrbitControls while playing;\n * re-enables and syncs `controls.target` to the clip focus on complete.\n *\n * @example\n * ```ts\n * const playback = new CameraPlayback(camera, controls);\n * playback.setRest(); // snapshot current pose as Reset target\n *\n * onFrame((dt) => {\n * playback.update(dt);\n * controls.update();\n * renderer.render(scene, camera);\n * });\n *\n * playback.play(createOrbitClip({ target, radius: 10, duration: 8 }));\n * ```\n */\nexport class CameraPlayback {\n private active: CameraClip | null = null;\n private elapsed = 0;\n private readonly focus = new Vector3();\n private rest: CameraSnapshot;\n\n constructor(\n private readonly camera: PerspectiveCamera,\n private readonly controls?: OrbitControls,\n ) {\n const snap = captureSnapshot(camera, controls);\n this.focus.copy(snap.target);\n this.rest = snap;\n }\n\n /** Whether a clip is actively playing. */\n get isPlaying(): boolean {\n return this.active !== null;\n }\n\n /** Snapshot the current camera + controls pose as the Reset/rest pose. */\n setRest(): void {\n this.rest = captureSnapshot(this.camera, this.controls);\n }\n\n /** Replace the rest pose without stopping playback. */\n setRestSnapshot(snapshot: CameraSnapshot): void {\n this.rest = {\n position: snapshot.position.clone(),\n quaternion: snapshot.quaternion.clone(),\n fov: snapshot.fov,\n target: snapshot.target.clone(),\n };\n }\n\n /**\n * Begin a clip. Cancels any active clip first.\n * OrbitControls are disabled until the clip completes or {@link stop} is called.\n */\n play(clip: CameraClip): void {\n this.cancelActive();\n applySnapshot(this.camera, this.controls, this.rest);\n this.active = clip;\n this.elapsed = 0;\n if (this.controls) this.controls.enabled = false;\n clip.start(this.runtime());\n }\n\n /** Cancel the active clip and restore the rest pose. */\n stop(): void {\n this.cancelActive();\n applySnapshot(this.camera, this.controls, this.rest);\n if (this.controls) {\n this.controls.enabled = true;\n this.controls.update();\n }\n }\n\n /** Alias for {@link stop} — return to the rest pose. */\n reset(): void {\n this.stop();\n }\n\n /**\n * Advance the active clip. Call from the scene `onFrame` callback each frame.\n * @param dt Elapsed seconds since last frame.\n */\n update(dt: number): void {\n if (!this.active) return;\n\n this.elapsed += dt;\n const phase = this.active.update(this.runtime(), dt);\n\n if (phase === \"complete\") {\n this.active = null;\n this.elapsed = 0;\n if (this.controls) {\n this.controls.target.copy(this.focus);\n this.controls.enabled = true;\n this.controls.update();\n }\n }\n }\n\n /** Release references; call from example dispose. */\n dispose(): void {\n this.stop();\n }\n\n private cancelActive(): void {\n if (!this.active) return;\n this.active.cancel?.(this.runtime());\n this.active = null;\n this.elapsed = 0;\n }\n\n private runtime(): ClipRuntime {\n return {\n camera: this.camera,\n controls: this.controls ?? null,\n elapsed: this.elapsed,\n duration: this.active?.duration ?? 0,\n focus: this.focus,\n };\n }\n}","/**\n * Easing function type for interpolating values over time.\n * @param t - Progress value between 0 and 1\n * @returns Eased value between 0 and 1\n */\nexport type EasingFunction = (t: number) => number;\n\n/**\n * Easing functions for interpolating values over time.\n *\n * Use these functions to create smooth animations and transitions.\n * All easing functions take a value t between 0 and 1 and return an eased value between 0 and 1.\n *\n * @example\n * ```typescript\n * import { Easing } from 'three-low-poly';\n *\n * // Using with transitions (namespace)\n * cameraTransition.transitionTo(camera, {\n * duration: 1000,\n * easing: Easing.cubicInOut // Function reference\n * });\n *\n * // Or using string reference\n * cameraTransition.transitionTo(camera, {\n * duration: 1000,\n * easing: 'cubicInOut' // String reference\n * });\n *\n * // Using the function directly in custom animation\n * const progress = 0.5;\n * const easedValue = Easing.cubicInOut(progress);\n *\n * // Custom animation loop\n * const startValue = 0;\n * const endValue = 100;\n * const t = elapsedTime / duration;\n * const easedT = Easing.sineInOut(t);\n * const currentValue = startValue + (endValue - startValue) * easedT;\n * ```\n */\nexport const Easing = {\n // Sine\n sineIn: (t: number) => 1 - Math.cos((t * Math.PI) / 2),\n sineOut: (t: number) => Math.sin((t * Math.PI) / 2),\n sineInOut: (t: number) => -0.5 * (Math.cos(Math.PI * t) - 1),\n\n // Quadratic\n quadIn: (t: number) => t * t,\n quadOut: (t: number) => 1 - Math.pow(1 - t, 2),\n quadInOut: (t: number) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),\n\n // Cubic\n cubicIn: (t: number) => t * t * t,\n cubicOut: (t: number) => 1 - Math.pow(1 - t, 3),\n cubicInOut: (t: number) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2),\n\n // Quartic\n quartIn: (t: number) => t * t * t * t,\n quartOut: (t: number) => 1 - Math.pow(1 - t, 4),\n quartInOut: (t: number) => (t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2),\n\n // Quintic\n quintIn: (t: number) => t * t * t * t * t,\n quintOut: (t: number) => 1 - Math.pow(1 - t, 5),\n quintInOut: (t: number) => (t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2),\n\n // Exponential\n expoIn: (t: number) => (t === 0 ? 0 : Math.pow(2, 10 * t - 10)),\n expoOut: (t: number) => (t === 1 ? 1 : 1 - Math.pow(2, -10 * t)),\n expoInOut: (t: number) => {\n if (t === 0) return 0;\n if (t === 1) return 1;\n return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;\n },\n\n // Circular\n circIn: (t: number) => 1 - Math.sqrt(1 - Math.pow(t, 2)),\n circOut: (t: number) => Math.sqrt(1 - Math.pow(t - 1, 2)),\n circInOut: (t: number) => t < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2,\n\n // Special\n linear: (t: number) => t,\n smoothstep: (t: number) => t * t * (3 - 2 * t),\n concave: (t: number) => 1 - Math.pow(1 - t, 0.3),\n convex: (t: number) => Math.pow(t, 0.3),\n logarithmic: (t: number) => Math.log(Math.max(0.01, t)) / Math.log(2),\n squareRoot: (t: number) => Math.sqrt(t),\n inverse: (t: number) => 1 - t,\n gaussian: (t: number) => {\n const sigma = 0.5;\n return Math.exp(-Math.pow(t - 0.5, 2) / (2 * sigma));\n },\n};\n","import { MathUtils, Vector3 } from \"three\";\nimport { Easing, type EasingFunction } from \"../constants/Easing\";\nimport {\n normalizedTime,\n type CameraClip,\n type CameraClipTiming,\n type ClipRuntime,\n} from \"./cameraClip\";\n\nconst tmp = new Vector3();\nconst tmp2 = new Vector3();\n\nexport interface OrbitClipOptions extends CameraClipTiming {\n target: Vector3;\n /** Horizontal distance from target. Defaults to current camera distance. */\n radius?: number;\n /** Elevation above target Y in radians. Defaults to current camera elevation. */\n elevation?: number;\n /** Revolutions over the clip. Defaults to `1`. */\n revolutions?: number;\n}\n\n/** Circle the scene — showcase reel orbit. */\nexport function createOrbitClip(options: OrbitClipOptions): CameraClip {\n const {\n target,\n duration,\n ease = Easing.smoothstep,\n revolutions = 1,\n } = options;\n const startAzimuth = { value: 0 };\n const radius = { value: options.radius ?? 10 };\n const elevation = { value: options.elevation ?? 0.4 };\n\n return {\n label: \"Orbit\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n tmp.subVectors(runtime.camera.position, target);\n radius.value = options.radius ?? tmp.length();\n elevation.value = options.elevation ?? Math.asin(MathUtils.clamp(tmp.y / radius.value, -1, 1));\n startAzimuth.value = Math.atan2(tmp.z, tmp.x);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) return \"complete\";\n\n const azimuth = startAzimuth.value + t * Math.PI * 2 * revolutions;\n const horiz = radius.value * Math.cos(elevation.value);\n runtime.camera.position.set(\n target.x + horiz * Math.cos(azimuth),\n target.y + radius.value * Math.sin(elevation.value),\n target.z + horiz * Math.sin(azimuth),\n );\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface PendulumClipOptions extends CameraClipTiming {\n target: Vector3;\n /** Distance from target. Defaults to current camera distance. */\n distance?: number;\n /** Peak azimuth swing in radians — keep small for Ken Burns mood (e.g. `0.12`). */\n azimuthAmplitude?: number;\n /** Slow back-and-forth cycles over the clip. Defaults to `2`. */\n oscillations?: number;\n ease?: EasingFunction;\n}\n\n/**\n * Atmospheric focus drift — slow Ken Burns sway while locked on a subject.\n * Not a full orbit; subtle back-and-forth for mood and screen capture.\n */\nexport function createPendulumClip(options: PendulumClipOptions): CameraClip {\n const {\n target,\n duration,\n azimuthAmplitude = 0.14,\n oscillations = 2,\n ease = Easing.linear,\n } = options;\n const baseAzimuth = { value: 0 };\n const distance = { value: options.distance ?? 8 };\n const elevation = { value: 0.35 };\n\n return {\n label: \"Pendulum\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n tmp.subVectors(runtime.camera.position, target);\n distance.value = options.distance ?? tmp.length();\n elevation.value = Math.asin(MathUtils.clamp(tmp.y / distance.value, -1, 1));\n baseAzimuth.value = Math.atan2(tmp.z, tmp.x);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) return \"complete\";\n\n const sway = Math.sin(t * Math.PI * 2 * oscillations) * azimuthAmplitude;\n const azimuth = baseAzimuth.value + sway;\n const horiz = distance.value * Math.cos(elevation.value);\n runtime.camera.position.set(\n target.x + horiz * Math.cos(azimuth),\n target.y + distance.value * Math.sin(elevation.value),\n target.z + horiz * Math.sin(azimuth),\n );\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface FlythroughClipOptions extends CameraClipTiming {\n waypoints: Vector3[];\n /** Optional look-at points per waypoint; defaults to next waypoint. */\n lookAt?: Vector3[];\n ease?: EasingFunction;\n}\n\n/** Waypoint tour through a sequence of positions. */\nexport function createFlythroughClip(options: FlythroughClipOptions): CameraClip {\n const { waypoints, duration, ease = Easing.cubicInOut } = options;\n if (waypoints.length < 2) throw new Error(\"Flythrough clip requires at least two waypoints\");\n\n const lookAt = options.lookAt ?? waypoints.slice(1).concat(waypoints[waypoints.length - 1]!);\n const segments = waypoints.length - 1;\n\n return {\n label: \"Flythrough\",\n duration,\n start(runtime) {\n runtime.focus.copy(lookAt[0] ?? waypoints[0]!);\n runtime.camera.position.copy(waypoints[0]!);\n runtime.camera.lookAt(runtime.focus);\n },\n update(runtime) {\n const t = normalizedTime(runtime, Easing.linear);\n if (t >= 1) {\n runtime.camera.position.copy(waypoints[waypoints.length - 1]!);\n runtime.focus.copy(lookAt[lookAt.length - 1] ?? waypoints[waypoints.length - 1]!);\n runtime.camera.lookAt(runtime.focus);\n return \"complete\";\n }\n\n const scaled = t * segments;\n const seg = Math.min(segments - 1, Math.floor(scaled));\n const localT = ease(scaled - seg);\n\n runtime.camera.position.lerpVectors(waypoints[seg]!, waypoints[seg + 1]!, localT);\n const lookFrom = lookAt[seg] ?? waypoints[seg + 1]!;\n const lookTo = lookAt[seg + 1] ?? waypoints[seg + 1]!;\n runtime.focus.lerpVectors(lookFrom, lookTo, localT);\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface DollyClipOptions extends CameraClipTiming {\n /** Distance along view axis — positive pulls back, negative pushes in. */\n distance: number;\n ease?: EasingFunction;\n}\n\n/** Dolly in or out along the current view direction. */\nexport function createDollyClip(options: DollyClipOptions): CameraClip {\n const { distance, duration, ease = Easing.cubicInOut } = options;\n const startPos = new Vector3();\n const endPos = new Vector3();\n const viewDir = new Vector3();\n\n return {\n label: \"Dolly\",\n duration,\n start(runtime) {\n startPos.copy(runtime.camera.position);\n runtime.camera.getWorldDirection(viewDir);\n endPos.copy(startPos).addScaledVector(viewDir, distance);\n runtime.focus.copy(runtime.controls?.target ?? startPos).addScaledVector(viewDir, 10);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) {\n runtime.camera.position.copy(endPos);\n return \"complete\";\n }\n runtime.camera.position.lerpVectors(startPos, endPos, t);\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface SpiralClipOptions extends CameraClipTiming {\n /** Ground point to look down at (typically scene center, `y = 0`). */\n target: Vector3;\n /** Orbit radius at the start of the clip. */\n radius: number;\n /** Optional wider radius at the end — pulls back as you rise. Defaults to `radius`. */\n endRadius?: number;\n /** Total vertical rise over the clip. */\n height: number;\n revolutions: number;\n ease?: EasingFunction;\n}\n\n/**\n * Scene-transition spiral — orbit upward while looking down at the scene.\n * Camera rises and optionally widens its orbit; `lookAt` stays on the ground\n * target so the view pitches into a bird's-eye survey (not a horizontal orbit).\n */\nexport function createSpiralClip(options: SpiralClipOptions): CameraClip {\n const {\n target,\n radius,\n endRadius = radius,\n height,\n revolutions,\n duration,\n ease = Easing.smoothstep,\n } = options;\n const startY = { value: 0 };\n const startAzimuth = { value: 0 };\n\n return {\n label: \"Spiral\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n startY.value = runtime.camera.position.y;\n tmp.subVectors(runtime.camera.position, target);\n startAzimuth.value = Math.atan2(tmp.z, tmp.x);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) return \"complete\";\n\n const angle = startAzimuth.value + t * Math.PI * 2 * revolutions;\n const orbitRadius = MathUtils.lerp(radius, endRadius, t);\n runtime.camera.position.set(\n target.x + orbitRadius * Math.cos(angle),\n startY.value + height * t,\n target.z + orbitRadius * Math.sin(angle),\n );\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface ZoomClipOptions extends CameraClipTiming {\n target: Vector3;\n /** Narrower FOV at the end of the clip (e.g. `35` from `75`). */\n endFov: number;\n ease?: EasingFunction;\n}\n\n/** Focus punch — smooth FOV narrow toward a target. Restores FOV on cancel; keeps end FOV on complete. */\nexport function createZoomClip(options: ZoomClipOptions): CameraClip {\n const { target, endFov, duration, ease = Easing.cubicInOut } = options;\n const startFov = { value: 75 };\n\n return {\n label: \"Zoom\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n startFov.value = runtime.camera.fov;\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n runtime.camera.fov = MathUtils.lerp(startFov.value, endFov, Math.min(1, t));\n runtime.camera.updateProjectionMatrix();\n runtime.camera.lookAt(runtime.focus);\n return t >= 1 ? \"complete\" : \"running\";\n },\n cancel(runtime) {\n runtime.camera.fov = startFov.value;\n runtime.camera.updateProjectionMatrix();\n },\n };\n}\n\nexport interface WobbleClipOptions extends CameraClipTiming {\n /** Peak positional shake in world units. */\n intensity: number;\n ease?: EasingFunction;\n}\n\n/**\n * Impact wobble — short head-shake / recovery shake (gameplay feedback).\n * Decaying sinusoidal offset, not random noise. For showcase orbit rigs use\n * {@link createPendulumClip} instead.\n */\nexport function createWobbleClip(options: WobbleClipOptions): CameraClip {\n const { intensity, duration, ease = Easing.linear } = options;\n const origin = new Vector3();\n const seed = { value: 0 };\n\n return {\n label: \"Wobble\",\n duration,\n start(runtime) {\n origin.copy(runtime.camera.position);\n seed.value = runtime.camera.position.x * 17.3 + runtime.camera.position.z * 9.1;\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) {\n runtime.camera.position.copy(origin);\n return \"complete\";\n }\n\n const decay = 1 - t;\n const w = runtime.elapsed * 28 + seed.value;\n runtime.camera.position.set(\n origin.x + Math.sin(w * 1.7) * intensity * decay,\n origin.y + Math.sin(w * 2.3) * intensity * 0.6 * decay,\n origin.z + Math.cos(w * 1.9) * intensity * decay,\n );\n return \"running\";\n },\n cancel(runtime) {\n runtime.camera.position.copy(origin);\n },\n };\n}","import { Vector3 } from \"three\";\n\n/**\n * Movement or orientation in a specific direction.\n *\n * Example usages:\n *\n * Moving an Object Along a Direction\n * ```\n * const speed = 1; // Movement speed\n * const direction = Direction.FORWARD; // Choose a direction\n *\n * object.position.add(direction.clone().multiplyScalar(speed * deltaTime));\n * ```\n *\n * Snapping Positions to a Direction\n * ```\n * const targetPosition = new Vector3(5, 0, 3);\n * const snapDirection = Direction.UP; // Align upwards\n *\n * object.position.copy(targetPosition.clone().add(snapDirection.clone().multiplyScalar(10)));\n * ```\n *\n * Animating Along a Direction\n * ```\n * const distance = 10; // Total distance to travel\n * const duration = 2; // Animation duration in seconds\n * const startPosition = object.position.clone();\n * const targetPosition = startPosition.clone().add(Direction.BACKWARD.clone().multiplyScalar(distance));\n *\n * let elapsed = 0;\n * function animate(deltaTime) {\n * elapsed += deltaTime;\n * const t = Math.min(elapsed / duration, 1); // Normalize time to [0, 1]\n * object.position.lerpVectors(startPosition, targetPosition, t);\n * }\n * ```\n *\n * Shader Uniforms\n * ```\n * material.uniforms.uDirection.value = Direction.FORWARD; // Use as light or flow direction\n * ```\n *\n * Particle Systems\n * ```\n * particles.forEach(particle => {\n * particle.velocity.add(Direction.FORWARD.clone().multiplyScalar(0.1));\n * });\n * ```\n *\n * Directional Raycasting\n * ```\n * const rayOrigin = new Vector3(0, 0, 0);\n * const rayDirection = Direction.FORWARD;\n * const raycaster = new THREE.Raycaster(rayOrigin, rayDirection);\n *\n * // Find intersected objects\n * const intersects = raycaster.intersectObjects(scene.children);\n * ```\n *\n * Physics Forces\n * ```\n * const forceDirection = Direction.UP; // Push upwards\n * const forceMagnitude = 50;\n *\n * rigidBody.applyForce(forceDirection.clone().multiplyScalar(forceMagnitude));\n * ```\n */\nexport const Direction = {\n UP: new Vector3(0, 1, 0),\n DOWN: new Vector3(0, -1, 0),\n LEFT: new Vector3(-1, 0, 0),\n RIGHT: new Vector3(1, 0, 0),\n FORWARD: new Vector3(0, 0, 1),\n BACKWARD: new Vector3(0, 0, -1),\n};\n","export type FalloffFunction = (distance: number, radius: number) => number;\n\nexport const Falloff = {\n linear: (distance: number, radius: number): number => 1 - distance / radius,\n quadratic: (distance: number, radius: number): number => Math.pow(1 - distance / radius, 2),\n squareRoot: (distance: number, radius: number): number => Math.pow(1 - distance / radius, 0.5),\n logarithmic: (distance: number, radius: number): number => Math.log(1 + (radius - distance)) / Math.log(1 + radius),\n sine: (distance: number, radius: number): number => Math.cos(((distance / radius) * Math.PI) / 2),\n exponential: (distance: number, radius: number): number => Math.exp(-distance / radius),\n cubic: (distance: number, radius: number): number => Math.pow(1 - distance / radius, 3),\n gaussian: (distance: number, radius: number): number => Math.exp(-Math.pow(distance, 2) / (2 * Math.pow(radius / 3, 2))),\n inverse: (distance: number, radius: number): number => radius / (radius + distance),\n smoothstep: (distance: number, radius: number): number => {\n const t = Math.max(0, Math.min(1, 1 - distance / radius));\n return t * t * (3 - 2 * t);\n },\n};\n","import { BufferGeometry, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Moves vertices within a specified radius around a target position along a given direction\n */\nexport const displacementBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear,\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n // Calculate falloff\n const falloff = falloffFn(distance, radius);\n const influence = falloff * strength;\n\n // Apply the effect (e.g., pulling the vertex upwards)\n vertex.add(direction.clone().multiplyScalar(influence));\n\n // Update the vertex position\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Flattens vertices to a given plane defined by a target height or normal direction.\n */\nexport const flattenBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n targetHeight: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n const falloff = falloffFn(distance, radius);\n const influence = falloff * strength;\n\n // Project vertex onto flatten plane\n const projectedHeight = vertex.dot(direction.normalize());\n const delta = targetHeight - projectedHeight;\n\n vertex.add(direction.clone().multiplyScalar(delta * influence));\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, MathUtils, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Adds random noise to the vertices within the specified radius to create a more rugged or natural look.\n */\nexport const noiseBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n const falloff = falloffFn(distance, radius);\n const noiseStrength = strength * falloff;\n\n // Generate random noise in the direction specified\n const noise = direction.clone().normalize();\n vertex.x += MathUtils.randFloatSpread(noiseStrength) * noise.x;\n vertex.y += MathUtils.randFloatSpread(noiseStrength) * noise.y;\n vertex.z += MathUtils.randFloatSpread(noiseStrength) * noise.z;\n\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Vector3 } from \"three\";\n\n/**\n * Smooths out the vertices by averaging their positions with neighboring vertices within a given radius.\n */\nexport const smoothBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number\n): void => {\n const positions = geometry.attributes.position;\n const tempPosition = new Vector3();\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n let averagePosition = new Vector3();\n let count = 0;\n\n // Average position of nearby vertices\n for (let j = 0; j < positions.count; j++) {\n tempPosition.fromBufferAttribute(positions, j);\n if (tempPosition.distanceTo(vertex) < radius) {\n averagePosition.add(tempPosition);\n count++;\n }\n }\n\n if (count > 0) {\n averagePosition.divideScalar(count);\n vertex.lerp(averagePosition, strength); // Blend between current and average\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Vector3 } from \"three\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Creates spikes or depressions centered on the target position, pushing vertices away or pulling them towards the center.\n */\nexport const spikeBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n inward: boolean = false,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n // Calculate falloff\n const falloff = falloffFn(distance, radius);\n const influence = falloff * strength * (inward ? -1 : 1);\n\n // Move the vertex along the direction from the center\n const direction = vertex.clone().sub(position).normalize();\n vertex.add(direction.multiplyScalar(influence));\n\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Quaternion, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Applies a twisting force to the vertices, rotating them around the direction defined by the target position.\n */\nexport const twistBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n const quaternion = new Quaternion();\n\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n // Calculate falloff and rotation angle\n const falloff = falloffFn(distance, radius);\n const angle = falloff * strength;\n\n // Create quaternion for rotation around the axis\n quaternion.setFromAxisAngle(direction, angle);\n\n // Apply twist rotation\n vertex.sub(position).applyQuaternion(quaternion).add(position);\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { Vector3 } from \"three\";\n\n/**\n * Geometric and mathematical role of the vectors as axes in 3D space.\n *\n * Example usages:\n *\n * Defining a geometry's up vector:\n * ```\n * const upVector = Axis.Z; // Set the Z-axis as the \"up\" direction\n * object.up.copy(upVector);\n * ```\n *\n * Rotating or Orienting an Object\n * ```\n * const axis = Axis.XY; // Diagonal upward\n * object.lookAt(object.position.clone().add(axis));\n * ```\n *\n * Rotate around axis:\n * ```\n * const angle = Math.PI / 4; // 45-degree rotation\n * const rotationAxis = Axis.Y; // Rotate around the Y-axis\n *\n * object.rotateOnAxis(rotationAxis, angle);\n * ```\n *\n * Scaling along an axis:\n * ```\n * const scalingAxis = Axis.XZ; // Scale equally along X and Z\n * const scaleFactor = 2;\n *\n * object.scale.multiply(scalingAxis.clone().multiplyScalar(scaleFactor));\n * ```\n *\n * Aligning a Camera\n * ```\n * const cameraAxis = Axis.XZ; // Align the camera diagonally on the XZ plane\n *\n * camera.lookAt(camera.position.clone().add(cameraAxis));\n * ```\n *\n * Directional lighting\n * ```\n * const lightDirection = Axis.YZ; // Diagonal light along Y and Z axes\n * directionalLight.position.copy(lightDirection.clone().multiplyScalar(10));\n * ```\n *\n * Aligning an Object\n * ```\n * const axis = Axis.X; // Align object to the X-axis\n * object.lookAt(object.position.clone().add(axis));\n * ```\n *\n * Spawning objects along an axis\n * ```\n * const spawnAxis = Axis.XZ; // Arrange objects diagonally on XZ\n * const count = 10;\n * const spacing = 5;\n *\n * for (let i = 0; i < count; i++) {\n * const position = spawnAxis.clone().multiplyScalar(i * spacing);\n * const newObject = object.clone();\n * newObject.position.copy(position);\n * scene.add(newObject);\n * }\n * ```\n *\n * Vector projections\n * ```\n * const vector = new Vector3(3, 5, 7);\n * const projectionAxis = Axis.Z; // Project the vector onto the Z-axis\n *\n * const projection = vector.clone().projectOnVector(projectionAxis);\n * ```\n *\n * Plane definitions\n * ```\n * const normal = Axis.Y; // Y-axis is the normal for a horizontal plane\n * const distanceFromOrigin = 5;\n *\n * const plane = new THREE.Plane(normal, distanceFromOrigin);\n * ```\n *\n * Plane intersections\n * ```\n * const planeNormal = Axis.Y; // Define a plane normal (horizontal plane)\n * const plane = new THREE.Plane(planeNormal);\n *\n * const rayDirection = Axis.Z; // Ray pointing along Z-axis\n * const rayOrigin = new Vector3(0, 5, 0);\n * const ray = new THREE.Ray(rayOrigin, rayDirection);\n *\n * // Find intersection point\n * const intersectionPoint = new Vector3();\n * plane.intersectLine(new THREE.Line3(rayOrigin, rayOrigin.clone().add(rayDirection)), intersectionPoint);\n * ```\n *\n * Defining bounds\n * ```\n * const boundsAxis = Axis.XY; // Restrict an object’s movement within XY bounds\n * const maxBounds = 10;\n *\n * object.position.clamp(\n * new Vector3(-maxBounds, -maxBounds, -Infinity),\n * new Vector3(maxBounds, maxBounds, Infinity)\n * );\n * ```\n *\n * Procedural Geometry\n * ```\n * const vertex = new Vector3(0, 0, 0);\n * const axis = Axis.XZ; // Diagonal axis on XZ plane\n *\n * const offset = axis.clone().multiplyScalar(5);\n * vertex.add(offset); // Move vertex in axis\n * geometry.vertices.push(vertex);\n * ```\n */\nexport const Axis = {\n X: new Vector3(1, 0, 0),\n Y: new Vector3(0, 1, 0),\n Z: new Vector3(0, 0, 1),\n XY: new Vector3(1, 1, 0).normalize(),\n XZ: new Vector3(1, 0, 1).normalize(),\n YZ: new Vector3(0, 1, 1).normalize(),\n XYZ: new Vector3(1, 1, 1).normalize(),\n};\n","export enum BoxSide {\n LEFT = \"left\",\n RIGHT = \"right\",\n TOP = \"top\",\n BOTTOM = \"bottom\",\n FRONT = \"front\",\n BACK = \"back\",\n}\n","export const ColorPalette = {\n // Red\n CADMIUM_RED: 0xe60026, // Cadmium Red or Bright Red. Vivid, bold red shade with warm undertones.\n CARDINAL_RED: 0xc61416, // Bright Crimson or Cardinal Red. It’s a vivid, bold red shade with warm undertones.\n CHERRY_RED: 0xd82424, // Bold red with slightly warm undertones.\n CRIMSON: 0xc62828, // Crimson Red or Firebrick Red. It’s a bold, deep red with a slightly cool undertone.\n ALIZARIN_CRIMSON: 0xb22222, // Deep, rich red with cool undertones.\n DARK_RED: 0x8b0000, // Dark Red. It’s a deep, rich red shade resembling the color of garnets or dried blood.\n RUST: 0xc2452d, // Red clay or Brick Red. It’s a warm, earthy red-orange shade, often associated with weathered metal, autumn leaves, or natural clay tones.\n\n // Orange\n CORAL_ORANGE: 0xff5733, // Bold red-orange hue.\n TANGERINE: 0xff5500, // Tangerine or Bright Orange-Red. It’s a vibrant, warm shade of orange with red undertones with a tropical feel.\n ORANGE_PEEL: 0xff6600, // Orange Peel or Bright Orange. It’s a vivid, energetic orange.\n CADMIUM_ORANGE: 0xff7f24, // warm orange with strong red undertones, giving it a slightly richer and darker appearance.\n ORANGE: 0xffa500, // Bright, vibrant hue associated with sunsets, citrus fruits, and autumn tones.\n\n // Yellow\n AMBER: 0xffaa00, // Bright Orange. It’s a warm, vibrant shade of orange with golden-yellow undertones, associated with autumn hues.\n CADMIUM_YELLOW: 0xffd700, // Bright golden yellow with warm undertones.\n GOLD: 0xffd700, // Rich, vibrant yellow with warm undertones, resembling the color of metallic gold.\n YELLOW: 0xffff00, // Bright, pure yellow shade.\n\n // Green\n LIME_GREEN: 0xa4c400, // Lime Green or Bright Chartreuse. It’s a vivid, energetic yellow-green shade\n SPRING_GREEN: 0x88cc55, // Fresh, vibrant appearance, resembling new leaves or spring foliage\n MOSS_GREEN: 0x88aa33, // Medium-light shade of green with yellow undertones, often seen in natural foliage.\n FERN_GREEN: 0x4b8b3b, // It's a natural, medium-dark green with slightly muted tones, resembling the lush greenery of ferns or foliage.\n FOREST_GREEN: 0x228b22, // Rich, deep green shade, often associated with dense woodland and nature.\n SAP_GREEN: 0x507d2a, // Natural green with a muted tone.\n OLIVE_DRAB: 0x556b2f, // Muted earthy green with brownish undertones.\n VIRIDIAN_GREEN: 0x00a86b, // Vibrant cool green.\n MINT_GREEN: 0x88ccaa, // Mint Green or Light Jade. It’s a soft, pastel green with subtle blue undertones.\n AQUAMARINE: 0x00ffaa, // Aquamarine or Mint Green. It’s a bright, vibrant turquoise shade that blends green and blue.\n\n // Blue\n PHTHALO_BLUE: 0x000f89, // Phthalo Blue or Bright Navy. Intense, rich blue with a slightly greenish cool undertone.\n AETHER_BLUE: 0x3498db, // Bright and vivid shade of blue, sitting between the airy Sky Blue and rich Cerulean.\n SKY_BLUE: 0x88ccff, // Sky Blue or Baby Blue. It’s a light, cheerful shade of blue with a slightly soft and pastel tone.\n CERULEAN_BLUE: 0x5dade2, // Cerulean Blue or Sky Blue. It’s a bright, vivid shade of blue with a slightly cool undertone.\n AZURE: 0x0077ff, // Azure Blue or Bright Blue. It’s a vibrant, rich shade of blue with a cool undertone.\n OCEAN_BLUE: 0x0077be, // Ocean Blue or Azure Blue. It’s a vibrant medium blue shade with a slight teal undertone.\n ROYAL_BLUE: 0x5555ff, // Royal Blue or Bright Indigo. It’s a vibrant medium blue shade with a slightly cool and saturated tone.\n MIDNIGHT_BLUE: 0x000033, // A very deep, dark blue shade that evokes the feeling of a starless night sky or deep ocean depths, with subtle blue undertones.\n ULTRAMARINE_BLUE: 0x3f51b5, // Deep, rich blue with a slightly cool undertone.\n\n // Purple\n COBALT_VIOLET: 0x6a0dad, // Soft, purple tone.\n DEEP_VIOLET: 0xaa00ff, // Electric Purple or Deep Violet. It’s a bright, vibrant shade of purple with a strong blue undertone.\n CORAL_PINK: 0xff3366, // Bright Rose or Coral Pink. It’s a vivid, bold pinkish-red shade with warm undertones.\n VIVID_MAGENTA: 0xff22ff, // It's an intense, electric shade of pink with equal parts red and blue.\n MAGENTA: 0xff00ff, // Bright, vivid hue that is a mix of equal parts red and blue, sometimes called Fuchsia.\n HOT_PINK: 0xff00aa, // Hot Pink or Fuchsia Rose. It’s a vivid and bold pink with a magenta undertone.\n PINK_SHERBET: 0xff99cc, // Pink Sherbet or Light Pink. It’s a soft, playful pink shade with a hint of warmth.\n SOFT_PINK: 0xffc7c7, // Blush Pink or Soft Pink. It’s a pale, delicate pink with warm undertones.\n\n // Brown\n BURNT_SIENNA: 0xe97451, // warm, earthy brown with reddish undertones.\n BURNT_UMBER: 0x8a3324, // Dark brown with red undertones.\n SIENNA: 0x8b5a2b, // Dark Goldenrod Brown. It’s a warm, earthy brown with reddish and golden undertones, often associated with natural clay or autumn leaves.\n SADDLE_BROWN: 0x8b4513, // Rich, earthy brown with reddish undertones, often associated with leather, wood, or other natural materials.\n COFFEE_BROWN: 0x5c4033, // Rich, earthy tone with hints of red and gray, resembling the color of natural wood or dark leather.\n DARK_UMBER: 0x4b3621, // Coffee Brown or Dark Umber. It’s a deep, rich brown with warm, earthy undertones, often resembling dark wood or roasted coffee beans.\n RAW_UMBER: 0x826644, // Cool, muted brown.\n YELLOW_OCHRE: 0xc5a16f, // Warm, muted yellow-brown\n RAW_SIENNA: 0xd2b48c, // Light, golden brown.\n TAUPE: 0x8b7d7b, // Rosy Brown or Taupe Gray. It’s a muted, earthy tone with a mix of brown and gray.\n\n // Gray\n ONYX: 0x030303, // Extremely deep, almost black shade with a neutral tone.\n CARBON: 0x2e2e2e, // Deep, neutral gray.\n CHARCOAL: 0x333333, // Rich, neutral gray.\n SLATE_GRAY: 0x404040, // Medium-dark shade of gray\n ASH_GRAY: 0x444444, // Ash Gray or Dark Slate Gray.\n GRAPHITE: 0x505050, // Medium-dark, neutral Graphite Gray or Smoky Gray shadowy muted depth.\n STEEL_GRAY: 0x555555, // Medium Gray or Steel Gray.\n DIM_GRAY: 0x696969, // Medium-dark neutral gray with a muted, balanced tone\n IRON: 0x777777, // It’s a medium gray neutral.\n GRAY: 0x808080, // It is a neutral, medium-gray tone that sits exactly halfway between black and white.\n STONE: 0x888888, // It’s a medium-light neutral.\n SILVER: 0xaaaaaa, // Light Gray. It’s a soft, pale gray shade with a slightly metallic undertone.\n LIGHT_GRAY: 0xcccccc, // Light, neutral Gray, sits between medium grays and white.\n PALE_GRAY: 0xeeeeee, // Very Light Gray or Soft Gray. It’s a pale, almost white shade of gray.\n WHITE_SMOKE: 0xf5f5f5, // White Smoke or Light Gray. It’s a soft, pale gray shade with a hint of warmth.\n TITANIUM_WHITE: 0xffffff, // Pure white, the brightest color possible.\n };\n","export const ParametricCurve = {\n cubic: (t: number, p0: number, p1: number, p2: number, p3: number): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n const oneMinusT = 1 - clampedT;\n return (\n oneMinusT * oneMinusT * oneMinusT * p0 +\n 3 * oneMinusT * oneMinusT * clampedT * p1 +\n 3 * oneMinusT * clampedT * clampedT * p2 +\n clampedT * clampedT * clampedT * p3\n );\n },\n damped: (t: number, damping: number = 1): number => {\n const clampedDamping = Math.max(0.001, damping); // Avoid zero or negative damping\n return (1 - Math.exp(-clampedDamping * t)) / (1 - Math.exp(-clampedDamping));\n },\n exponential: (t: number, base: number = 1, factor: number = 1): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n return base * Math.pow(clampedT, factor);\n },\n logarithmic: (t: number, base: number = 1, factor: number = 1): number => {\n const clampedT = Math.max(0.001, Math.min(1, t)); // Avoid log(0)\n return base * Math.log(factor * clampedT + 1);\n },\n parabolic: (t: number, a: number = 1, b: number = 0, c: number = 0): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n return a * clampedT * clampedT + b * clampedT + c;\n },\n quadratic: (t: number, p0: number, p1: number, p2: number): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n const oneMinusT = 1 - clampedT;\n return oneMinusT * oneMinusT * p0 + 2 * oneMinusT * clampedT * p1 + clampedT * clampedT * p2;\n },\n sigmoid: (t: number, a: number = 10): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n return 1 / (1 + Math.exp(-a * (clampedT - 0.5)));\n },\n sinusoidal: (t: number): number => {\n return Math.sin(t * Math.PI * 0.5);\n },\n};\n","/**\n * Randomness for procedural generation — unseeded by default, reproducible on demand.\n *\n * ---\n *\n * ### Layer 1 — stream primitive (portfolio parity)\n *\n * - {@link mulberry32} — fast seeded PRNG; returns a `() => number` closure yielding\n * floats in `[0, 1)`. Same algorithm as Gotham/Water on the portfolio site.\n *\n * ### Seed mixing\n *\n * - {@link splitmix32} — mixer only, **not** a stream. Maps one 32-bit value to another.\n * - {@link deriveSubSeed} — `splitmix32(masterSeed ^ salt)`. Fan one user-facing master\n * seed into independent sub-streams per subsystem. Use stable hex salts per domain\n * (`0x101` books, `0x202` fog, `0x303` windows, …) instead of `seed + n` offsets.\n *\n * ### Layer 2 — library ergonomics\n *\n * - {@link createRandom} — **no seed** → wraps `Math.random()`, unique every runtime\n * (showcase default). **With seed** → {@link mulberry32} stream, same seed ⇒ same sequence.\n * - Returns a {@link RandomSource}: `next`, `float`, `int`, `pick`, `boolean`, `skewMax`, `skewMin`.\n * - {@link Random} namespace — grouped exports, same API as standalone functions (like {@link Easing}).\n *\n * ### Layer 3 — {@link RandomNumberUtils}\n *\n * Existing helpers (`randomFloat`, `logarithmicRandomMax`, …) accept an optional\n * {@link RandomSource} as their last argument. Omit it for unseeded default behavior.\n *\n * ---\n *\n * @example Unique runtime (default)\n * ```ts\n * const rng = createRandom();\n * rng.float(0, 10); // different every page load\n * ```\n *\n * @example Reproducible layout with sub-seeds\n * ```ts\n * const master = 1337;\n * const books = createRandom(deriveSubSeed(master, 0x101));\n * const fog = createRandom(deriveSubSeed(master, 0x202));\n * ```\n *\n * @example Namespace import\n * ```ts\n * const rng = Random.create(deriveSubSeed(1337, 0x101));\n * ```\n */\n\n/** Callable stream returning floats in [0, 1). */\nexport type RandomStream = () => number;\n\n/**\n * Random source — a stream plus distribution helpers.\n * Returned by {@link createRandom}; also accepted by {@link RandomNumberUtils}.\n */\nexport interface RandomSource {\n /** `true` when backed by {@link mulberry32}; `false` when using `Math.random()`. */\n readonly seeded: boolean;\n /** Next float in [0, 1). */\n next(): number;\n /** Float in [min, max). */\n float(min?: number, max?: number): number;\n /** Integer in [min, max] (inclusive). */\n int(min?: number, max?: number): number;\n /** Uniform element from a non-empty array. */\n pick<T>(arr: readonly T[]): T;\n /** `true` with given probability (default 0.5). */\n boolean(probability?: number): boolean;\n /**\n * Skew toward `max`. Lower `exponent` = stronger bias.\n * Mirrors {@link logarithmicRandomMax}.\n */\n skewMax(exponent?: number, min?: number, max?: number): number;\n /**\n * Skew toward `min`. Lower `exponent` = stronger bias.\n * Mirrors {@link logarithmicRandomMin}.\n */\n skewMin(exponent?: number, min?: number, max?: number): number;\n}\n\n/**\n * Fast seeded PRNG — portfolio Gotham/Water parity.\n * Returns a closure yielding floats in [0, 1).\n */\nexport function mulberry32(seed: number): RandomStream {\n let a = seed >>> 0;\n return () => {\n a |= 0;\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/**\n * Seed mixer — maps one 32-bit value to another well-distributed value.\n * Use with {@link deriveSubSeed}, not as a drop-in stream replacement for\n * {@link mulberry32}.\n */\nexport function splitmix32(seed: number): number {\n let z = (seed >>> 0) + 0x9e3779b9;\n z = Math.imul(z ^ (z >>> 16), 0x85ebca6b);\n z ^= z >>> 13;\n z = Math.imul(z ^ (z >>> 16), 0xc2b2ae35);\n return (z ^ (z >>> 16)) >>> 0;\n}\n\n/**\n * Derive an independent sub-stream seed from a master seed and domain salt.\n *\n * XOR the salt before mixing so each subsystem gets its own mulberry32 stream\n * without sequential `seed + 1` collision risk. Use stable hex constants per\n * domain (`0x101` books, `0x202` fog, `0x303` windows, …).\n *\n * @example\n * ```ts\n * const master = 1337;\n * const bookRng = createRandom(deriveSubSeed(master, 0x101));\n * const fogRng = createRandom(deriveSubSeed(master, 0x202));\n * ```\n */\nexport function deriveSubSeed(masterSeed: number, salt: number): number {\n return splitmix32((masterSeed >>> 0) ^ (salt >>> 0));\n}\n\nfunction buildSource(stream: RandomStream, seeded: boolean): RandomSource {\n return {\n seeded,\n next: stream,\n float(min = 0, max = 1) {\n return min + (max - min) * stream();\n },\n int(min = 0, max = 1) {\n return Math.floor(this.float(min, max + 1));\n },\n pick<T>(arr: readonly T[]): T {\n if (!arr.length) throw new Error(\"RandomSource.pick() requires a non-empty array\");\n return arr[this.int(0, arr.length - 1)]!;\n },\n boolean(probability = 0.5) {\n return stream() < probability;\n },\n skewMax(exponent = 0.5, min = 0, max = 1) {\n return min + (max - min) * Math.pow(stream(), exponent);\n },\n skewMin(exponent = 0.5, min = 0, max = 1) {\n return min + (max - min) * Math.pow(1 - stream(), exponent);\n },\n };\n}\n\n/**\n * Create a random source.\n *\n * - **No seed** — wraps `Math.random()`. Unique every runtime; default for examples.\n * - **With seed** — {@link mulberry32} stream. Same seed ⇒ same sequence.\n */\nexport function createRandom(seed?: number): RandomSource {\n if (seed === undefined) return buildSource(Math.random, false);\n return buildSource(mulberry32(seed >>> 0), true);\n}\n\n/** Float in [min, max) from any stream — website `range()` parity. */\nexport function randomRange(stream: RandomStream, min: number, max: number): number {\n return min + (max - min) * stream();\n}\n\n/** Pick from a non-empty array using any stream — website `pick()` parity. */\nexport function randomPick<T>(stream: RandomStream, arr: readonly T[]): T {\n if (!arr.length) throw new Error(\"randomPick() requires a non-empty array\");\n return arr[Math.floor(stream() * arr.length)]!;\n}\n\n/**\n * Grouped exports — same function API, namespace import like {@link Easing}.\n *\n * @example\n * ```ts\n * import { Random } from \"three-low-poly\";\n * const rng = Random.create(deriveSubSeed(1337, 0x101));\n * ```\n */\nexport const Random = {\n create: createRandom,\n mulberry32,\n splitmix32,\n deriveSubSeed,\n range: randomRange,\n pick: randomPick,\n} as const;","import { createRandom, type RandomSource } from \"./Random\";\n\n/** Unseeded default — unique each runtime. Pass a {@link RandomSource} to override. */\nconst defaultSource = createRandom();\n\n/**\n * Generates a random number between `min` and `max`.\n */\nexport function randomFloat(min = 0, max = 1, source: RandomSource = defaultSource) {\n return source.float(min, max);\n}\n\n/**\n * Generates a random integer between `min` and `max`.\n */\nexport function randomInteger(min = 0, max = 1, source: RandomSource = defaultSource) {\n return source.int(min, max);\n}\n\n/**\n * Generates a random number skewed towards the maximum value.\n *\n * @param {number} [exponent=0.5] - Controls the skew of the distribution.\n * A smaller value (e.g., 0.3) skews the values towards the max.\n * A larger value (e.g., 0.8) creates a more even distribution.\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards `max`.\n */\nexport function logarithmicRandomMax(\n exponent = 0.5,\n min = 0,\n max = 1,\n source: RandomSource = defaultSource,\n) {\n return source.skewMax(exponent, min, max);\n}\n\n/**\n * Generates a random number skewed towards the minimum value.\n *\n * @param {number} [exponent=0.5] - Controls the skew of the distribution.\n * A smaller value (e.g., 0.3) skews the values towards the min.\n * A larger value (e.g., 0.8) creates a more even distribution.\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards `min`.\n */\nexport function logarithmicRandomMin(\n exponent = 0.5,\n min = 0,\n max = 1,\n source: RandomSource = defaultSource,\n) {\n return source.skewMin(exponent, min, max);\n}\n\n/**\n * Generates a random number with an inverse logarithmic distribution, biased towards the maximum value.\n *\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards the maximum.\n */\n\nfunction inverseLogarithmicRandomMax(min = 0, max = 1, source: RandomSource = defaultSource) {\n const randomValue = 1 - Math.log(1 - source.next()) / Math.log(2);\n return min + (max - min) * randomValue;\n}\n\n/**\n * Generates a random number with an inverse logarithmic distribution, biased towards the minimum value.\n *\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards the minimum.\n */\nfunction inverseLogarithmicRandomMin(min = 0, max = 1, source: RandomSource = defaultSource) {\n const randomValue = Math.log(1 - source.next()) / Math.log(2);\n const adjustedValue = -randomValue;\n const clampedValue = Math.min(Math.max(adjustedValue, 0), 1);\n return min + (max - min) * clampedValue;\n}","import {\n BufferGeometry,\n ColorRepresentation,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n MeshStandardMaterial,\n Object3D,\n SphereGeometry,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface EffervescenceEffectOptions {\n /** Override bubble geometry. Defaults to a small `SphereGeometry`. */\n geometry?: BufferGeometry;\n /** Override the default bubble material. */\n material?: Material;\n /** Number of bubble instances. Defaults to `24`. */\n count?: number;\n /** Horizontal spread (world units). Defaults to `1.5`. */\n width?: number;\n /** Vertical column height (world units). Defaults to `3`. */\n height?: number;\n /** Depth spread (world units). Defaults to `1.5`. */\n depth?: number;\n /**\n * Horizontal spawn inset (0–1). Scales width/depth spawn area inward so a\n * square volume fits round vessels. `1` = full box; `0.88` (default) trims corners.\n */\n spread?: number;\n /** World Y where bubbles spawn when they recycle. Defaults to `0`. */\n baseY?: number;\n /** Minimum rise speed (units/s). Defaults to `0.35`. */\n speedMin?: number;\n /** Maximum rise speed (units/s). Defaults to `0.85`. */\n speedMax?: number;\n /** Bubble tint when using the default material. Defaults to `0xffffff`. */\n color?: ColorRepresentation;\n /** Default material opacity. Defaults to `0.6`. */\n opacity?: number;\n /** Default material emissive intensity. Defaults to `0`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Carbonation bubbles rising through a bounded volume — seltzer, soda, or\n * brewing liquid. Each instance drifts upward at its own speed and respawns\n * near {@link EffervescenceEffectOptions.baseY} after reaching the top.\n *\n * Spawn positions use a square footprint (`width` × `depth`). {@link EffervescenceEffectOptions.spread}\n * pulls that box inward so round jars do not get occasional corner outliers.\n * Position and scale the effect to sit inside a jar, flask, or panel viewport.\n * Call {@link EffervescenceEffect.update} each frame with elapsed time in seconds.\n *\n * @example\n * ```typescript\n * const fizz = new EffervescenceEffect({ width: 1.2, height: 2.5, count: 30 });\n * fizz.position.set(0, 1.2, 0);\n * scene.add(fizz);\n *\n * onFrame((dt) => fizz.update(dt));\n * ```\n */\nexport class EffervescenceEffect extends InstancedMesh {\n private readonly width: number;\n private readonly height: number;\n private readonly depth: number;\n private readonly baseY: number;\n private readonly spread: number;\n private readonly px: Float32Array;\n private readonly py: Float32Array;\n private readonly pz: Float32Array;\n private readonly speed: Float32Array;\n private readonly dummy = new Object3D();\n\n constructor(options: EffervescenceEffectOptions = {}) {\n const {\n count = 24,\n width = 1.5,\n height = 3,\n depth = 1.5,\n spread = 0.88,\n baseY = 0,\n speedMin = 0.35,\n speedMax = 0.85,\n color = 0xffffff,\n opacity = 0.6,\n emissiveIntensity = 0,\n geometry = new SphereGeometry(0.08, 6, 6),\n material,\n } = options;\n\n const bubbleMaterial =\n material ??\n new MeshStandardMaterial({\n color,\n emissive: color,\n emissiveIntensity,\n transparent: true,\n opacity,\n roughness: 0.3,\n metalness: 0.1,\n });\n\n super(geometry, bubbleMaterial, count);\n this.instanceMatrix.setUsage(DynamicDrawUsage);\n this.frustumCulled = false;\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.baseY = baseY;\n this.spread = Math.min(1, Math.max(0, spread));\n\n this.px = new Float32Array(count);\n this.py = new Float32Array(count);\n this.pz = new Float32Array(count);\n this.speed = new Float32Array(count);\n\n for (let i = 0; i < count; i++) {\n this.respawn(i, true);\n this.speed[i] = randomFloat(speedMin, speedMax);\n }\n\n this.writeMatrices();\n }\n\n /**\n * Advance bubble positions. Pass elapsed frame time in seconds (e.g. from\n * `createScene`'s `onFrame` callback).\n */\n update(dt: number): void {\n const ceiling = this.baseY + this.height;\n for (let i = 0; i < this.count; i++) {\n this.py[i] += this.speed[i] * dt;\n if (this.py[i] > ceiling) this.respawn(i, false);\n }\n this.writeMatrices();\n }\n\n /** Release geometry and materials held by the field. */\n dispose(): this {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n return this;\n }\n\n private respawn(index: number, randomHeight: boolean): void {\n const halfX = this.width * 0.5 * this.spread;\n const halfZ = this.depth * 0.5 * this.spread;\n this.px[index] = randomFloat(-halfX, halfX);\n this.pz[index] = randomFloat(-halfZ, halfZ);\n this.py[index] = randomHeight\n ? this.baseY + Math.random() * this.height\n : this.baseY + randomFloat(0, this.height * 0.15);\n }\n\n private writeMatrices(): void {\n const d = this.dummy;\n for (let i = 0; i < this.count; i++) {\n d.position.set(this.px[i], this.py[i], this.pz[i]);\n d.updateMatrix();\n this.setMatrixAt(i, d.matrix);\n }\n this.instanceMatrix.needsUpdate = true;\n }\n}","import { Color, ColorRepresentation, MeshBasicMaterial, PointLight, Vector3 } from \"three\";\nimport { GlowHalo } from \"./GlowHalo\";\n\nexport interface FlameFlickerEffectOptions {\n /**\n * Desyncs multiple instances. Defaults to `Math.random() * 100`.\n */\n seed?: number;\n /** Optional real light — use sparingly; casts on geometry but counts against light limits. */\n light?: PointLight;\n /** Base intensity when `light` is set. Defaults to `4`. */\n lightIntensity?: number;\n /** Optional flame core material (e.g. `MeshBasicMaterial` on a small sphere). */\n flame?: MeshBasicMaterial;\n /** Flame tint when `flame` is set. Defaults to `0xffaa44`. */\n flameColor?: ColorRepresentation;\n /** Optional {@link GlowHalo}; opacity scales with the flicker factor. */\n halo?: GlowHalo;\n /** Halo opacity multiplier at flicker peak. Defaults to `0.75`. */\n haloOpacity?: number;\n}\n\n/**\n * Calm flame flicker from detuned sines — drives optional real lights, flame\n * materials, and {@link GlowHalo} opacity in sync. Time-based (`update(dt)`).\n *\n * Use without a `light` for mass candlefields (halo + bloom only). Add a\n * `light` for hero sconces that must cast on walls and props.\n */\nexport class FlameFlickerEffect {\n public readonly seed: number;\n public light?: PointLight;\n public lightIntensity: number;\n public flame?: MeshBasicMaterial;\n public halo?: GlowHalo;\n public haloOpacity: number;\n\n private readonly flameColor = new Color();\n private elapsed = 0;\n\n constructor({\n seed = Math.random() * 100,\n light,\n lightIntensity = 4,\n flame,\n flameColor = 0xffaa44,\n halo,\n haloOpacity = 0.75,\n }: FlameFlickerEffectOptions = {}) {\n this.seed = seed;\n this.light = light;\n this.lightIntensity = lightIntensity;\n this.flame = flame;\n this.flameColor.set(flameColor);\n this.halo = halo;\n this.haloOpacity = haloOpacity;\n }\n\n /**\n * Flicker factor at elapsed time — lazy sum of detuned sines (~0.5–1.1).\n */\n static factor(elapsed: number, seed: number): number {\n return 0.8 + 0.2 * Math.sin(elapsed * 9 + seed) + 0.08 * Math.sin(elapsed * 23 + seed * 2);\n }\n\n /** Current flicker factor after the last `update`. */\n get level(): number {\n return FlameFlickerEffect.factor(this.elapsed, this.seed);\n }\n\n update(dt: number): void {\n this.elapsed += dt;\n const f = FlameFlickerEffect.factor(this.elapsed, this.seed);\n\n if (this.light) {\n this.light.intensity = this.lightIntensity * f;\n }\n\n if (this.flame) {\n this.flame.color.copy(this.flameColor).multiplyScalar(0.8 + 0.4 * f);\n }\n\n if (this.halo) {\n this.halo.setOpacity(this.haloOpacity * f);\n }\n }\n\n /** Billboard linked halo toward the eye, if present. */\n faceCamera(eye: Vector3): void {\n this.halo?.faceCamera(eye);\n }\n}","import {\n CanvasTexture,\n Color,\n ColorRepresentation,\n Mesh,\n MeshBasicMaterial,\n Object3D,\n PlaneGeometry,\n SRGBColorSpace,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\ntype Edge = \"n\" | \"s\" | \"e\" | \"w\";\n\ninterface FogPatch {\n mesh: Mesh<PlaneGeometry, MeshBasicMaterial>;\n driftX: number;\n driftZ: number;\n spin: number;\n baseOpacity: number;\n phase: number;\n perimeter?: {\n edge: Edge;\n plotHalf: number;\n terrainHalf: number;\n };\n}\n\nexport interface GroundFogEffectOptions {\n /** Interior mist cards scattered across the plot. Defaults to `14`. */\n count?: number;\n /** Half-extent of the interior scatter (world units). Defaults to `16`. */\n area?: number;\n /**\n * Large cards hugging the plot perimeter — softens terrain cutoffs on the\n * horizons opposite the camera. Defaults to `0` (interior only).\n */\n perimeterCount?: number;\n /** Half-extent of the inner bounded plot (fence, wall, scene edge, etc.). Defaults to `12`. */\n plotHalf?: number;\n /** Terrain half-extent; perimeter cards spill outward toward this edge. Defaults to `16`. */\n terrainHalf?: number;\n /**\n * Horizontal direction from plot center toward the camera. Perimeter patches\n * concentrate on the opposite edges. Defaults to `{ x: 1, z: 1 }`.\n */\n cameraFacing?: { x: number; z: number };\n /** Mist tint. Defaults to `#9fb0c8`. */\n color?: ColorRepresentation;\n /**\n * Sample ground height at world (x, z). Defaults to flat `y = 0`.\n * Portfolio graveyard uses undulating terrain via the same callback.\n */\n heightAt?: (x: number, z: number) => number;\n}\n\n/**\n * Creeping ground mist — soft horizontal cards drifting above the floor.\n * Interior patches wrap toroidally within `area`; optional perimeter patches\n * sit on/outside the fence on edges opposite the camera. One texture, one\n * `update(dt)` — perimeter is placement logic, not a separate effect.\n */\nexport class GroundFogEffect extends Object3D {\n private readonly patches: FogPatch[] = [];\n private readonly area: number;\n private readonly heightAt: (x: number, z: number) => number;\n private readonly texture: CanvasTexture;\n private elapsed = 0;\n\n constructor({\n count = 14,\n area = 16,\n perimeterCount = 0,\n plotHalf = 12,\n terrainHalf = 16,\n cameraFacing = { x: 1, z: 1 },\n color = \"#9fb0c8\",\n heightAt = () => 0,\n }: GroundFogEffectOptions = {}) {\n super();\n\n this.area = area;\n this.heightAt = heightAt;\n this.texture = createFogTexture(color);\n const focus = focusEdges(cameraFacing);\n\n for (let i = 0; i < count; i++) {\n this.patches.push(this.makeInteriorPatch());\n }\n for (let i = 0; i < perimeterCount; i++) {\n this.patches.push(this.makePerimeterPatch(plotHalf, terrainHalf, focus));\n }\n }\n\n update(dt: number): void {\n this.elapsed += dt;\n\n for (const patch of this.patches) {\n const mesh = patch.mesh;\n mesh.position.x += patch.driftX * dt;\n mesh.position.z += patch.driftZ * dt;\n mesh.rotation.z += patch.spin * dt;\n\n if (patch.perimeter) {\n constrainPerimeter(mesh, patch.perimeter.edge, patch.perimeter.plotHalf, patch.perimeter.terrainHalf);\n mesh.position.y =\n this.heightAt(mesh.position.x, mesh.position.z) +\n 0.15 +\n 0.35 * (0.5 + 0.5 * Math.sin(this.elapsed * 0.22 + patch.phase));\n } else {\n if (mesh.position.x > this.area) mesh.position.x -= this.area * 2;\n if (mesh.position.x < -this.area) mesh.position.x += this.area * 2;\n if (mesh.position.z > this.area) mesh.position.z -= this.area * 2;\n if (mesh.position.z < -this.area) mesh.position.z += this.area * 2;\n }\n\n mesh.material.opacity = patch.baseOpacity * (0.6 + 0.4 * Math.sin(this.elapsed * 0.3 + patch.phase));\n }\n }\n\n dispose(): void {\n this.texture.dispose();\n for (const patch of this.patches) {\n patch.mesh.geometry.dispose();\n patch.mesh.material.dispose();\n }\n this.patches.length = 0;\n this.clear();\n }\n\n private makeInteriorPatch(): FogPatch {\n const size = randomFloat(8, 16);\n const baseOpacity = randomFloat(0.05, 0.16);\n const x = randomFloat(-this.area, this.area);\n const z = randomFloat(-this.area, this.area);\n const mesh = this.makeMesh(size, baseOpacity);\n mesh.position.set(x, this.heightAt(x, z) + randomFloat(0.3, 1.2), z);\n this.add(mesh);\n\n return {\n mesh,\n driftX: randomFloat(-0.15, 0.15),\n driftZ: randomFloat(-0.15, 0.15),\n spin: randomFloat(-0.03, 0.03),\n baseOpacity,\n phase: randomFloat(0, Math.PI * 2),\n };\n }\n\n private makePerimeterPatch(plotHalf: number, terrainHalf: number, focus: Edge[]): FogPatch {\n const edge = pickEdge(focus);\n const { x, z, driftX, driftZ } = placeOnPerimeter(edge, plotHalf, terrainHalf);\n const size = randomFloat(18, 30);\n const baseOpacity = randomFloat(0.1, 0.26);\n const mesh = this.makeMesh(size, baseOpacity);\n mesh.position.set(x, this.heightAt(x, z) + randomFloat(0.15, 0.55), z);\n this.add(mesh);\n\n return {\n mesh,\n driftX,\n driftZ,\n spin: randomFloat(-0.012, 0.012),\n baseOpacity,\n phase: randomFloat(0, Math.PI * 2),\n perimeter: { edge, plotHalf, terrainHalf },\n };\n }\n\n private makeMesh(size: number, baseOpacity: number): Mesh<PlaneGeometry, MeshBasicMaterial> {\n const mesh = new Mesh(\n new PlaneGeometry(size, size),\n new MeshBasicMaterial({\n map: this.texture,\n transparent: true,\n depthWrite: false,\n opacity: baseOpacity,\n toneMapped: false,\n }),\n );\n mesh.rotation.x = -Math.PI / 2;\n mesh.rotation.z = randomFloat(0, Math.PI * 2);\n return mesh;\n }\n}\n\nfunction createFogTexture(color: ColorRepresentation): CanvasTexture {\n const hex = `#${new Color(color).getHexString()}`;\n const canvas = document.createElement(\"canvas\");\n canvas.width = canvas.height = 256;\n const ctx = canvas.getContext(\"2d\")!;\n const gradient = ctx.createRadialGradient(128, 128, 8, 128, 128, 128);\n gradient.addColorStop(0, `${hex}dd`);\n gradient.addColorStop(0.45, `${hex}66`);\n gradient.addColorStop(1, `${hex}00`);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, 256, 256);\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\nfunction focusEdges(facing: { x: number; z: number }): Edge[] {\n const edges: Edge[] = [];\n if (facing.z > 0) edges.push(\"n\");\n if (facing.z < 0) edges.push(\"s\");\n if (facing.x > 0) edges.push(\"w\");\n if (facing.x < 0) edges.push(\"e\");\n return edges.length ? edges : [\"n\", \"w\"];\n}\n\nfunction pickEdge(focus: Edge[]): Edge {\n if (focus.length === 1) return focus[0]!;\n const r = Math.random();\n const hasN = focus.includes(\"n\");\n const hasW = focus.includes(\"w\");\n if (hasN && hasW) return r < 0.58 ? \"n\" : \"w\";\n return focus[Math.floor(Math.random() * focus.length)]!;\n}\n\nfunction placeOnPerimeter(\n edge: Edge,\n plotHalf: number,\n terrainHalf: number,\n): { x: number; z: number; driftX: number; driftZ: number } {\n const spill = randomFloat(0.6, terrainHalf - plotHalf - 1.5);\n const along = randomFloat(-terrainHalf + 3, terrainHalf - 3);\n const alongSpeed = randomFloat(0.03, 0.09) * (Math.random() < 0.5 ? -1 : 1);\n const outwardSpeed = randomFloat(0.01, 0.04);\n\n switch (edge) {\n case \"n\":\n return { x: along, z: -plotHalf - spill, driftX: alongSpeed, driftZ: -outwardSpeed };\n case \"s\":\n return { x: along, z: plotHalf + spill, driftX: -alongSpeed, driftZ: outwardSpeed };\n case \"e\":\n return { x: plotHalf + spill, z: along, driftX: outwardSpeed, driftZ: -alongSpeed };\n case \"w\":\n return { x: -plotHalf - spill, z: along, driftX: -outwardSpeed, driftZ: alongSpeed };\n }\n}\n\nfunction constrainPerimeter(mesh: Mesh, edge: Edge, plotHalf: number, terrainHalf: number): void {\n const margin = 3;\n const maxSpill = terrainHalf - 1;\n const { x, z } = mesh.position;\n\n switch (edge) {\n case \"n\": {\n mesh.position.z = clamp(z, -maxSpill, -plotHalf + 0.8);\n if (x < -maxSpill + margin) mesh.position.x = maxSpill - margin;\n if (x > maxSpill - margin) mesh.position.x = -maxSpill + margin;\n break;\n }\n case \"s\": {\n mesh.position.z = clamp(z, plotHalf - 0.8, maxSpill);\n if (x < -maxSpill + margin) mesh.position.x = maxSpill - margin;\n if (x > maxSpill - margin) mesh.position.x = -maxSpill + margin;\n break;\n }\n case \"e\": {\n mesh.position.x = clamp(x, plotHalf - 0.8, maxSpill);\n if (z < -maxSpill + margin) mesh.position.z = maxSpill - margin;\n if (z > maxSpill - margin) mesh.position.z = -maxSpill + margin;\n break;\n }\n case \"w\": {\n mesh.position.x = clamp(x, -maxSpill, -plotHalf + 0.8);\n if (z < -maxSpill + margin) mesh.position.z = maxSpill - margin;\n if (z > maxSpill - margin) mesh.position.z = -maxSpill + margin;\n break;\n }\n }\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, v));\n}","import {\n AdditiveBlending,\n CanvasTexture,\n Color,\n ColorRepresentation,\n Mesh,\n MeshBasicMaterial,\n Object3D,\n PlaneGeometry,\n SRGBColorSpace,\n Vector3,\n} from \"three\";\n\nexport interface GlowHaloOptions {\n /** Warm glow tint. Defaults to `0xffaa44`. */\n color?: ColorRepresentation;\n /** Billboard plane edge length in world units. Defaults to `1.2`. */\n size?: number;\n /** Base opacity before flicker scaling. Defaults to `0.75`. */\n opacity?: number;\n}\n\nfunction createGlowTexture(color: Color): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = canvas.height = 128;\n const ctx = canvas.getContext(\"2d\")!;\n const hex = `#${color.getHexString()}`;\n const gradient = ctx.createRadialGradient(64, 64, 2, 64, 64, 64);\n gradient.addColorStop(0, `${hex}ff`);\n gradient.addColorStop(0.25, `${hex}aa`);\n gradient.addColorStop(1, `${hex}00`);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, 128, 128);\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\n/**\n * Soft additive glow billboard — reads as light without a {@link PointLight}.\n * Pair with {@link FlameFlickerEffect} for organic pulse, or use alone for\n * cheap mass lighting (many halos + bloom, no light-count limit).\n *\n * Call `faceCamera(camera.position)` each frame so the card faces the eye.\n */\nexport class GlowHalo extends Object3D {\n public readonly mesh: Mesh<PlaneGeometry, MeshBasicMaterial>;\n private texture: CanvasTexture;\n private readonly baseColor: Color;\n\n constructor({\n color = 0xffaa44,\n size = 1.2,\n opacity = 0.75,\n }: GlowHaloOptions = {}) {\n super();\n\n this.baseColor = new Color(color);\n this.texture = createGlowTexture(this.baseColor);\n const material = new MeshBasicMaterial({\n map: this.texture,\n color: this.baseColor,\n transparent: true,\n opacity,\n blending: AdditiveBlending,\n depthWrite: false,\n toneMapped: false,\n });\n\n this.mesh = new Mesh(new PlaneGeometry(size, size), material);\n this.add(this.mesh);\n }\n\n /** Billboard toward the camera (or any eye position). */\n faceCamera(eye: Vector3): void {\n this.mesh.lookAt(eye);\n }\n\n /** Set halo opacity (e.g. scaled each frame by {@link FlameFlickerEffect}). */\n setOpacity(opacity: number): void {\n this.mesh.material.opacity = opacity;\n }\n\n get opacity(): number {\n return this.mesh.material.opacity;\n }\n\n setColor(color: ColorRepresentation): void {\n this.baseColor.set(color);\n this.mesh.material.color.copy(this.baseColor);\n this.texture.dispose();\n this.texture = createGlowTexture(this.baseColor);\n this.mesh.material.map = this.texture;\n }\n\n dispose(): void {\n this.mesh.geometry.dispose();\n this.mesh.material.dispose();\n this.texture.dispose();\n }\n}","import { MeshLambertMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial } from \"three\";\n\nexport type EmissivePulseMaterial =\n | MeshStandardMaterial\n | MeshPhysicalMaterial\n | MeshLambertMaterial\n | MeshPhongMaterial;\n\nexport interface EmissivePulseEffectOptions {\n /** Material whose `emissiveIntensity` will oscillate. Must have emissive set. */\n material: EmissivePulseMaterial;\n /**\n * Pulse frequency in radians per second (`abs(sin(elapsed * speed))`).\n * Defaults to `2`. Primary differentiator when many LEDs share one color.\n */\n speed?: number;\n /** Lower bound of the pulse. Defaults to `0.2`. */\n minIntensity?: number;\n /** Upper bound of the pulse. Defaults to `0.8`. */\n maxIntensity?: number;\n}\n\n/**\n * Smooth emissive pulse for fake LEDs — animates `emissiveIntensity` on an existing\n * mesh material without adding geometry or scene lights.\n *\n * Pair with a prefab such as {@link PanelLight}: place the mesh, pass its material\n * here, call `update(dt)` each frame. For a bank of same-color LEDs, give each\n * instance a different `speed` so they breathe out of sync.\n *\n * @example\n * ```ts\n * const led = new PanelLight({ emissive: 0xff0000 });\n * scene.add(led);\n *\n * const pulse = new EmissivePulseEffect({\n * material: led.material,\n * speed: 1.4,\n * minIntensity: 0.05,\n * maxIntensity: 2,\n * });\n *\n * onFrame((dt) => pulse.update(dt));\n * ```\n */\nexport class EmissivePulseEffect {\n public speed: number;\n public minIntensity: number;\n public maxIntensity: number;\n public readonly material: EmissivePulseMaterial;\n\n private elapsed = 0;\n\n constructor({\n material,\n speed = 2,\n maxIntensity = 0.8,\n minIntensity = 0.2,\n }: EmissivePulseEffectOptions) {\n this.material = material;\n this.speed = speed;\n this.maxIntensity = maxIntensity;\n this.minIntensity = minIntensity;\n }\n\n /** Advance the pulse by `dt` seconds (elapsed time, not frame index). */\n update(dt: number): void {\n this.elapsed += dt;\n const t = Math.abs(Math.sin(this.elapsed * this.speed));\n this.material.emissiveIntensity = this.minIntensity + t * (this.maxIntensity - this.minIntensity);\n }\n}","import { DirectionalLight } from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface LightningEffectOptions {\n /** Directional light driven by lightning flashes. Start at intensity `0`. */\n light: DirectionalLight;\n /** Peak light intensity at full flash. Defaults to `12`. */\n peak?: number;\n /** Minimum seconds between strikes. Defaults to `3`. */\n minGap?: number;\n /** Maximum seconds between strikes. Defaults to `9`. */\n maxGap?: number;\n}\n\n/**\n * Thunderstorm lightning that drives a {@link DirectionalLight} each frame.\n *\n * Rather than scheduling timeouts (which need careful teardown), each strike\n * enqueues two or three decaying intensity spikes a few frames apart — the\n * characteristic stutter of real lightning. Read {@link LightningEffect.level}\n * after {@link LightningEffect.update} to sync fog, sky, rain, or emissive\n * surfaces with the flash.\n *\n * @example\n * ```typescript\n * const bolt = new DirectionalLight(0xcdd8ff, 0);\n * bolt.position.set(5, 12, -8);\n * bolt.target.position.set(0, 0, 0);\n * scene.add(bolt, bolt.target);\n *\n * const storm = new LightningEffect({ light: bolt, peak: 12, minGap: 3, maxGap: 9 });\n *\n * function animate(delta: number) {\n * storm.update(delta);\n * const flash = storm.level; // 0..~1.2\n * renderer.render(scene, camera);\n * }\n * ```\n */\nexport class LightningEffect {\n /** Current flash level, 0 = dark. Read after each {@link LightningEffect.update}. */\n level = 0;\n\n private readonly light: DirectionalLight;\n private readonly peak: number;\n private readonly minGap: number;\n private readonly maxGap: number;\n private readonly spikes: { at: number; amp: number }[] = [];\n private clock = 0;\n private nextStrike: number;\n\n constructor({ light, peak = 12, minGap = 3, maxGap = 9 }: LightningEffectOptions) {\n this.light = light;\n this.peak = peak;\n this.minGap = minGap;\n this.maxGap = maxGap;\n this.nextStrike = randomFloat(minGap * 0.3, maxGap);\n }\n\n /**\n * Advance the strike schedule and update the driven light intensity. Pass\n * elapsed frame time in seconds.\n */\n update(dt: number): void {\n this.clock += dt;\n if (this.clock >= this.nextStrike) this.strike();\n\n let level = 0;\n for (let i = this.spikes.length - 1; i >= 0; i--) {\n const spike = this.spikes[i];\n const age = this.clock - spike.at;\n if (age < 0) continue;\n const value = spike.amp * Math.exp(-age * 9);\n if (value < 0.002 && age > 0) {\n this.spikes.splice(i, 1);\n } else {\n level += value;\n }\n }\n\n this.level = Math.min(1.2, level);\n this.light.intensity = this.level * this.peak;\n }\n\n /** Force the driven light dark, e.g. when lightning is toggled off. */\n quiet(): void {\n this.level = 0;\n this.light.intensity = 0;\n }\n\n private strike(): void {\n const bursts = Math.random() < 0.5 ? 2 : 3;\n for (let i = 0; i < bursts; i++) {\n this.spikes.push({\n at: this.clock + i * randomFloat(0.04, 0.12),\n amp: randomFloat(0.5, 1),\n });\n }\n this.nextStrike = this.clock + randomFloat(this.minGap, this.maxGap);\n }\n}","import { BufferGeometry, Float32BufferAttribute } from \"three\";\n\nexport class EllipticLeafGeometry extends BufferGeometry {\n constructor(size = 0.1) {\n super();\n\n const vertices = [];\n const indices = [];\n\n // Define vertices to approximate a simple, elongated, oval leaf shape\n const leafPoints = [\n [0, 1], // Top point\n [0.5, 0.75], // Right upper middle\n [0.75, 0.25], // Right lower middle\n [0.5, -0.5], // Right bottom middle\n [0, -1], // Bottom point\n [-0.5, -0.5], // Left bottom middle\n [-0.75, 0.25], // Left lower middle\n [-0.5, 0.75], // Left upper middle\n ];\n\n // Add vertices to the geometry, scaling them with the `size` parameter\n for (let i = 0; i < leafPoints.length; i++) {\n const [x, y] = leafPoints[i];\n vertices.push(x * size, y * size, 0);\n }\n\n // Define indices to form triangular faces of the leaf\n // Create a fan-like structure connecting the top vertex (index 0) to other neighboring vertices\n for (let i = 1; i < leafPoints.length - 1; i++) {\n indices.push(0, i, i + 1);\n }\n // Close the fan with the last triangle\n indices.push(0, leafPoints.length - 1, 1);\n\n // Convert the vertices and indices to buffer attributes\n const positionAttribute = new Float32BufferAttribute(vertices, 3);\n this.setAttribute('position', positionAttribute);\n this.setIndex(indices);\n\n this.computeVertexNormals();\n }\n}\n","import {\n BufferGeometry,\n Color,\n ColorRepresentation,\n DoubleSide,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n MeshStandardMaterial,\n Object3D,\n} from \"three\";\nimport { EllipticLeafGeometry } from \"../geometry/leafs/EllipticLeafGeometry\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface PetalDriftEffectOptions {\n /** Override petal geometry. Defaults to {@link EllipticLeafGeometry}. */\n geometry?: BufferGeometry;\n /** Override the default petal material. */\n material?: Material;\n /** Number of petal instances. Defaults to `120`. */\n count?: number;\n /** Horizontal spread (world units). Defaults to `16`. */\n width?: number;\n /** Vertical spawn span (world units). Defaults to `8`. */\n height?: number;\n /** Depth spread (world units). Defaults to `16`. */\n depth?: number;\n /** World Y where petals respawn after drifting below the floor. Defaults to `0`. */\n floorY?: number;\n /** Minimum fall speed (units/s). Defaults to `0.12`. */\n fallSpeedMin?: number;\n /** Maximum fall speed (units/s). Defaults to `0.28`. */\n fallSpeedMax?: number;\n /** Minimum horizontal drift speed (units/s). Defaults to `0.04`. */\n driftMin?: number;\n /** Maximum horizontal drift speed (units/s). Defaults to `0.14`. */\n driftMax?: number;\n /**\n * Flutter strength (radians). Subtle rotation sway as each petal falls.\n * Defaults to `0.35`.\n */\n flutter?: number;\n /** Single petal color or palette; multiple entries pick a random color per petal. */\n color?: ColorRepresentation | ColorRepresentation[];\n}\n\n/**\n * Soft, slow-drifting petals (or leaves) falling through a bounded volume —\n * cherry-blossom float rather than stiff tumble. Each instance drifts downward\n * with gentle horizontal wander and a light sinusoidal flutter.\n *\n * Call {@link PetalDriftEffect.update} each frame with elapsed time in seconds.\n *\n * @example\n * ```typescript\n * const petals = new PetalDriftEffect({\n * count: 80,\n * color: [0xffd6f0, 0xfff0f8, 0xf8c8e0],\n * flutter: 0.3,\n * });\n * scene.add(petals);\n *\n * onFrame((dt) => petals.update(dt));\n * ```\n */\nexport class PetalDriftEffect extends InstancedMesh {\n private readonly width: number;\n private readonly height: number;\n private readonly depth: number;\n private readonly floorY: number;\n private readonly flutter: number;\n private readonly px: Float32Array;\n private readonly py: Float32Array;\n private readonly pz: Float32Array;\n private readonly fallSpeed: Float32Array;\n private readonly driftX: Float32Array;\n private readonly driftZ: Float32Array;\n private readonly rotX: Float32Array;\n private readonly rotY: Float32Array;\n private readonly rotZ: Float32Array;\n private readonly phase: Float32Array;\n private readonly dummy = new Object3D();\n private clock = 0;\n\n constructor(options: PetalDriftEffectOptions = {}) {\n const {\n count = 120,\n width = 16,\n height = 8,\n depth = 16,\n floorY = 0,\n fallSpeedMin = 0.12,\n fallSpeedMax = 0.28,\n driftMin = 0.04,\n driftMax = 0.14,\n flutter = 0.35,\n color = [0xffd6f0, 0xfff5fa, 0xf0b8d0],\n geometry = new EllipticLeafGeometry(),\n material,\n } = options;\n\n const palette = (Array.isArray(color) ? color : [color]).map((entry) => new Color(entry));\n const petalMaterial =\n material ??\n new MeshStandardMaterial({\n color: palette.length === 1 ? palette[0].getHex() : 0xffffff,\n metalness: 0.05,\n roughness: 0.85,\n flatShading: true,\n side: DoubleSide,\n });\n\n super(geometry, petalMaterial, count);\n this.instanceMatrix.setUsage(DynamicDrawUsage);\n this.frustumCulled = false;\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.floorY = floorY;\n this.flutter = flutter;\n\n this.px = new Float32Array(count);\n this.py = new Float32Array(count);\n this.pz = new Float32Array(count);\n this.fallSpeed = new Float32Array(count);\n this.driftX = new Float32Array(count);\n this.driftZ = new Float32Array(count);\n this.rotX = new Float32Array(count);\n this.rotY = new Float32Array(count);\n this.rotZ = new Float32Array(count);\n this.phase = new Float32Array(count);\n\n for (let i = 0; i < count; i++) {\n this.respawn(i, true);\n this.fallSpeed[i] = randomFloat(fallSpeedMin, fallSpeedMax);\n const drift = randomFloat(driftMin, driftMax);\n const angle = randomFloat(0, Math.PI * 2);\n this.driftX[i] = Math.cos(angle) * drift;\n this.driftZ[i] = Math.sin(angle) * drift;\n this.phase[i] = randomFloat(0, Math.PI * 2);\n\n if (palette.length > 1) {\n this.setColorAt(i, palette[Math.floor(Math.random() * palette.length)]);\n }\n }\n\n if (this.instanceColor) this.instanceColor.needsUpdate = true;\n this.writeMatrices();\n }\n\n /**\n * Advance petal positions and flutter. Pass elapsed frame time in seconds.\n */\n update(dt: number): void {\n this.clock += dt;\n\n for (let i = 0; i < this.count; i++) {\n const sway = Math.sin(this.clock * 1.6 + this.phase[i]) * this.flutter * 0.12;\n this.px[i] += (this.driftX[i] + sway) * dt;\n this.py[i] -= this.fallSpeed[i] * dt;\n this.pz[i] += (this.driftZ[i] + Math.cos(this.clock * 1.3 + this.phase[i]) * this.flutter * 0.08) * dt;\n\n if (this.py[i] < this.floorY) this.respawn(i, false);\n }\n\n this.writeMatrices();\n }\n\n /** Release geometry and materials held by the field. */\n dispose(): this {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n return this;\n }\n\n private respawn(index: number, randomHeight: boolean): void {\n this.px[index] = randomFloat(-this.width * 0.5, this.width * 0.5);\n this.pz[index] = randomFloat(-this.depth * 0.5, this.depth * 0.5);\n this.py[index] = randomHeight\n ? this.floorY + randomFloat(this.height * 0.35, this.height)\n : this.floorY + this.height + randomFloat(0, this.height * 0.25);\n this.rotX[index] = randomFloat(-0.6, 0.6);\n this.rotY[index] = randomFloat(-Math.PI, Math.PI);\n this.rotZ[index] = randomFloat(-0.8, 0.8);\n }\n\n private writeMatrices(): void {\n const d = this.dummy;\n for (let i = 0; i < this.count; i++) {\n const flutterX = Math.sin(this.clock * 2.1 + this.phase[i]) * this.flutter;\n const flutterZ = Math.cos(this.clock * 1.7 + this.phase[i]) * this.flutter * 0.6;\n d.position.set(this.px[i], this.py[i], this.pz[i]);\n d.rotation.set(this.rotX[i] + flutterX, this.rotY[i], this.rotZ[i] + flutterZ);\n d.updateMatrix();\n this.setMatrixAt(i, d.matrix);\n }\n this.instanceMatrix.needsUpdate = true;\n }\n}","import {\n BufferGeometry,\n CanvasTexture,\n Color,\n ColorRepresentation,\n DoubleSide,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n MeshBasicMaterial,\n Object3D,\n PlaneGeometry,\n Quaternion,\n SRGBColorSpace,\n Vector3,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface RainEffectOptions {\n /** Override the streak quad geometry. Defaults to a thin `PlaneGeometry`. */\n geometry?: BufferGeometry;\n /** Override the default streak material. */\n material?: Material;\n /** Maximum number of streak instances. Defaults to `1400`. */\n count?: number;\n /** Horizontal half-extent of the rainfall area (square centered on the origin). Defaults to `26`. */\n area?: number;\n /** Vertical span above `groundY`. Defaults to `22`. */\n height?: number;\n /** World Y where streaks recycle. Defaults to `0`. */\n groundY?: number;\n /** Streak quad width. Defaults to `0.009`. */\n width?: number;\n /** Streak color. Defaults to `#aebfd6`. */\n color?: ColorRepresentation;\n /** Base material opacity at full intensity. Defaults to `0.16`. */\n opacity?: number;\n /** Minimum streak length. Defaults to `0.18`. */\n lengthMin?: number;\n /** Maximum streak length. Defaults to `0.42`. */\n lengthMax?: number;\n /** Minimum fall speed (units/s). Defaults to `11`. */\n speedMin?: number;\n /** Maximum fall speed (units/s). Defaults to `19`. */\n speedMax?: number;\n /**\n * Horizontal compass direction the wind blows (radians, 0 = +X, π/2 = +Z).\n * Only used when {@link RainEffectOptions.windStrength} is greater than zero.\n * Defaults to `0`.\n */\n windDirection?: number;\n /**\n * How much rain tilts and drifts from vertical, as `tan(angleFromVertical)`.\n * `0` = straight down (default). `0.15` ≈ 8.5° lean with matching horizontal drift.\n */\n windStrength?: number;\n /**\n * Rainfall strength (0–1). Scales visible instance count, fall speed, and opacity.\n * Defaults to `0.5`.\n */\n intensity?: number;\n}\n\nfunction createStreakTexture(): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = 8;\n canvas.height = 64;\n const ctx = canvas.getContext(\"2d\")!;\n const gradient = ctx.createLinearGradient(0, 0, 0, 64);\n gradient.addColorStop(0, \"rgba(255,255,255,0)\");\n gradient.addColorStop(0.42, \"rgba(255,255,255,0.55)\");\n gradient.addColorStop(0.58, \"rgba(255,255,255,0.55)\");\n gradient.addColorStop(1, \"rgba(255,255,255,0)\");\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, 8, 64);\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\n/**\n * Misty rainfall as instanced vertical streaks.\n *\n * Each streak is a thin, gradient-textured quad animated through a bounded\n * volume. By default streaks fall straight down with no rotation. Optional\n * {@link RainEffectOptions.windDirection} / {@link RainEffectOptions.windStrength}\n * tilt streaks **and** drift them horizontally together, so motion matches the\n * visual angle. Streak materials use `DoubleSide` so thin quads stay visible\n * from any camera angle. Scene fog dissolves distant streaks when the material's\n * `fog` flag is enabled.\n *\n * **`intensity`** (0–1) scales how many instances draw, how fast they fall, and\n * their opacity — useful for storm ramps or lightning flashes.\n *\n * @example\n * ```typescript\n * const rain = new RainEffect({ area: 12, height: 16, intensity: 0.4 });\n * scene.add(rain);\n * scene.fog = new Fog(0x0a0a12, 4, 28);\n *\n * function animate(delta: number) {\n * rain.update(delta);\n * renderer.render(scene, camera);\n * }\n * ```\n */\nexport class RainEffect extends InstancedMesh {\n /** Rainfall strength (0–1). Adjust at runtime for storm variation. */\n intensity: number;\n\n private readonly maxCount: number;\n private readonly area: number;\n private readonly height: number;\n private readonly groundY: number;\n private readonly baseOpacity: number;\n private readonly windDirection: number;\n private readonly windStrength: number;\n private readonly fallDirection = new Vector3(0, -1, 0);\n private readonly streakOrientation = new Quaternion();\n private readonly sx: Float32Array;\n private readonly sz: Float32Array;\n private readonly topY: Float32Array;\n private readonly len: Float32Array;\n private readonly speed: Float32Array;\n private readonly streakTexture?: CanvasTexture;\n private readonly dummy = new Object3D();\n private clock = 0;\n\n constructor(options: RainEffectOptions = {}) {\n const {\n count = 1400,\n area = 26,\n height = 22,\n groundY = 0,\n width = 0.009,\n color = \"#aebfd6\",\n opacity = 0.16,\n lengthMin = 0.18,\n lengthMax = 0.42,\n speedMin = 11,\n speedMax = 19,\n windDirection = 0,\n windStrength = 0,\n intensity = 0.5,\n geometry = new PlaneGeometry(width, 1),\n material,\n } = options;\n\n const streakTexture = material ? undefined : createStreakTexture();\n const rainMaterial =\n material ??\n new MeshBasicMaterial({\n color: new Color(color),\n map: streakTexture,\n transparent: true,\n opacity,\n depthWrite: false,\n toneMapped: false,\n fog: true,\n side: DoubleSide,\n });\n\n super(geometry, rainMaterial, count);\n this.instanceMatrix.setUsage(DynamicDrawUsage);\n this.frustumCulled = false;\n\n this.maxCount = count;\n this.area = area;\n this.height = height;\n this.groundY = groundY;\n this.baseOpacity = opacity;\n this.windDirection = windDirection;\n this.windStrength = Math.max(0, windStrength);\n this.updateFallDirection(0);\n this.intensity = intensity;\n this.streakTexture = streakTexture;\n\n this.sx = new Float32Array(count);\n this.sz = new Float32Array(count);\n this.topY = new Float32Array(count);\n this.len = new Float32Array(count);\n this.speed = new Float32Array(count);\n\n for (let i = 0; i < count; i++) {\n this.sx[i] = randomFloat(-area, area);\n this.sz[i] = randomFloat(-area, area);\n this.topY[i] = randomFloat(groundY, groundY + height);\n this.len[i] = randomFloat(lengthMin, lengthMax);\n this.speed[i] = randomFloat(speedMin, speedMax);\n }\n\n this.writeMatrices();\n this.applyIntensity();\n }\n\n /**\n * Advance streak positions and refresh instance transforms. Pass elapsed frame\n * time in seconds (e.g. from `createScene`'s `onFrame` callback).\n */\n update(dt: number): void {\n this.clock += dt;\n\n const gust =\n this.windStrength > 0 ? Math.sin(this.clock * 0.18) * 0.04 * this.windStrength : 0;\n this.updateFallDirection(gust);\n\n const fall = 0.85 + this.intensity * 0.7;\n const top = this.groundY + this.height;\n const driftX = this.fallDirection.x;\n const driftZ = this.fallDirection.z;\n const fallY = -this.fallDirection.y;\n\n for (let i = 0; i < this.maxCount; i++) {\n const travel = this.speed[i] * fall * dt;\n this.sx[i] += driftX * travel;\n this.sz[i] += driftZ * travel;\n this.topY[i] -= fallY * travel;\n\n if (this.topY[i] < this.groundY - this.len[i]) this.topY[i] += this.height;\n if (this.topY[i] > top) this.topY[i] -= this.height;\n\n if (this.sx[i] < -this.area) this.sx[i] += this.area * 2;\n else if (this.sx[i] > this.area) this.sx[i] -= this.area * 2;\n if (this.sz[i] < -this.area) this.sz[i] += this.area * 2;\n else if (this.sz[i] > this.area) this.sz[i] -= this.area * 2;\n }\n\n this.writeMatrices();\n this.applyIntensity();\n }\n\n /** Release geometry, materials, and the procedural streak texture. */\n dispose(): this {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n this.streakTexture?.dispose();\n return this;\n }\n\n private applyIntensity(): void {\n // Light drizzle still reads at low rainfall.\n this.count = Math.round(this.maxCount * Math.min(1, Math.max(0, 0.38 + this.intensity * 0.62)));\n\n const mat = this.material as MeshBasicMaterial;\n mat.opacity = this.baseOpacity * (0.55 + 0.65 * this.intensity);\n }\n\n private updateFallDirection(gust: number): void {\n const lean = this.windStrength + gust;\n if (lean <= 0) {\n this.fallDirection.set(0, -1, 0);\n this.streakOrientation.identity();\n return;\n }\n\n const horizontal = lean;\n const vertical = 1;\n const invLength = 1 / Math.hypot(horizontal, vertical);\n this.fallDirection.set(\n Math.cos(this.windDirection) * horizontal * invLength,\n -vertical * invLength,\n Math.sin(this.windDirection) * horizontal * invLength,\n );\n this.streakOrientation.setFromUnitVectors(new Vector3(0, 1, 0), this.fallDirection);\n }\n\n private writeMatrices(): void {\n const d = this.dummy;\n for (let i = 0; i < this.maxCount; i++) {\n const length = this.len[i];\n d.position.set(this.sx[i], this.topY[i] - length / 2, this.sz[i]);\n d.quaternion.copy(this.streakOrientation);\n d.scale.set(1, length, 1);\n d.updateMatrix();\n this.setMatrixAt(i, d.matrix);\n }\n this.instanceMatrix.needsUpdate = true;\n }\n}","import {\n Color,\n ColorRepresentation,\n Mesh,\n MeshBasicMaterial,\n Object3D,\n PointLight,\n SphereGeometry,\n Vector3,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface WispEffectOptions {\n /** Number of drifting wisps. Defaults to `3`. */\n count?: number;\n /** Horizontal spawn extent (world units, centered on the effect). Defaults to `16`. */\n width?: number;\n /** Depth spawn maximum (world units, from z = 0). Defaults to `8`. */\n depth?: number;\n /** Minimum spawn height. Defaults to `1`. */\n heightMin?: number;\n /** Maximum spawn height. Defaults to `2`. */\n heightMax?: number;\n /** Wisp tint. Defaults to `0x6dffb0` (portfolio graveyard). */\n color?: ColorRepresentation;\n /** Orb radius. Defaults to `0.08`. */\n orbRadius?: number;\n /** Horizontal drift radius (X). Defaults to `1.6`. */\n driftX?: number;\n /** Vertical drift radius (Y). Defaults to `0.3`. */\n driftY?: number;\n /** Depth drift radius (Z). Defaults to `1.6`. */\n driftZ?: number;\n /** Minimum motion speed multiplier. Defaults to `0.3`. */\n speedMin?: number;\n /** Maximum motion speed multiplier. Defaults to `0.7`. */\n speedMax?: number;\n /**\n * Attach a {@link PointLight} per wisp (keep `count` low).\n * Defaults to `true` to match the portfolio graveyard.\n */\n castLight?: boolean;\n /** Point light distance when `castLight`. Defaults to `6`. */\n lightDistance?: number;\n /** Point light decay when `castLight`. Defaults to `2`. */\n lightDecay?: number;\n /**\n * Light intensity = `lightIntensity + sin(t * lightPulseSpeed) * lightPulseAmplitude`.\n * Defaults to `2.5`.\n */\n lightIntensity?: number;\n /** Defaults to `1.2`. */\n lightPulseAmplitude?: number;\n /** Defaults to `3`. */\n lightPulseSpeed?: number;\n}\n\ninterface WispInstance {\n orb: Mesh<SphereGeometry, MeshBasicMaterial>;\n home: Vector3;\n phase: number;\n speed: number;\n light?: PointLight;\n}\n\n/**\n * Will-o'-the-wisps drifting through a bounded volume — eerie green orbs that\n * bob around spawn points with a pulsing point light. Ported from the portfolio\n * graveyard scene.\n *\n * @example\n * ```ts\n * const wisps = new WispEffect({ count: 3 });\n * scene.add(wisps);\n * onFrame((dt) => wisps.update(dt));\n * ```\n */\nexport class WispEffect extends Object3D {\n private readonly wisps: WispInstance[] = [];\n private readonly orbGeometry: SphereGeometry;\n private readonly orbMaterial: MeshBasicMaterial;\n private readonly halfWidth: number;\n private readonly depth: number;\n private readonly heightMin: number;\n private readonly heightMax: number;\n private readonly driftX: number;\n private readonly driftY: number;\n private readonly driftZ: number;\n private readonly speedMin: number;\n private readonly speedMax: number;\n private readonly castLight: boolean;\n private readonly lightDistance: number;\n private readonly lightDecay: number;\n private readonly lightIntensity: number;\n private readonly lightPulseAmplitude: number;\n private readonly lightPulseSpeed: number;\n\n private elapsed = 0;\n\n constructor({\n count = 3,\n width = 16,\n depth = 8,\n heightMin = 1,\n heightMax = 2,\n color = 0x6dffb0,\n orbRadius = 0.08,\n driftX = 1.6,\n driftY = 0.3,\n driftZ = 1.6,\n speedMin = 0.3,\n speedMax = 0.7,\n castLight = true,\n lightDistance = 6,\n lightDecay = 2,\n lightIntensity = 2.5,\n lightPulseAmplitude = 1.2,\n lightPulseSpeed = 3,\n }: WispEffectOptions = {}) {\n super();\n\n this.halfWidth = width / 2;\n this.depth = depth;\n this.heightMin = heightMin;\n this.heightMax = heightMax;\n this.driftX = driftX;\n this.driftY = driftY;\n this.driftZ = driftZ;\n this.speedMin = speedMin;\n this.speedMax = speedMax;\n this.castLight = castLight;\n this.lightDistance = lightDistance;\n this.lightDecay = lightDecay;\n this.lightIntensity = lightIntensity;\n this.lightPulseAmplitude = lightPulseAmplitude;\n this.lightPulseSpeed = lightPulseSpeed;\n\n this.orbGeometry = new SphereGeometry(orbRadius, 8, 8);\n this.orbMaterial = new MeshBasicMaterial({ color: new Color(color), toneMapped: false });\n\n for (let i = 0; i < count; i++) {\n const home = new Vector3(\n randomFloat(-this.halfWidth, this.halfWidth),\n randomFloat(this.heightMin, this.heightMax),\n randomFloat(0, this.depth),\n );\n\n const orb = new Mesh(this.orbGeometry, this.orbMaterial);\n orb.position.copy(home);\n this.add(orb);\n\n let light: PointLight | undefined;\n if (castLight) {\n light = new PointLight(color, 3, this.lightDistance, this.lightDecay);\n orb.add(light);\n }\n\n this.wisps.push({\n orb,\n home,\n phase: randomFloat(0, Math.PI * 2),\n speed: randomFloat(this.speedMin, this.speedMax),\n light,\n });\n }\n }\n\n update(dt: number): void {\n this.elapsed += dt;\n\n for (const wisp of this.wisps) {\n const t = this.elapsed * wisp.speed + wisp.phase;\n wisp.orb.position.set(\n wisp.home.x + Math.sin(t) * this.driftX,\n wisp.home.y + Math.sin(t * 1.7) * this.driftY,\n wisp.home.z + Math.cos(t * 0.8) * this.driftZ,\n );\n\n if (wisp.light) {\n wisp.light.intensity =\n this.lightIntensity + Math.sin(t * this.lightPulseSpeed) * this.lightPulseAmplitude;\n }\n }\n }\n\n dispose(): void {\n this.orbGeometry.dispose();\n this.orbMaterial.dispose();\n for (const wisp of this.wisps) {\n wisp.light?.dispose();\n }\n this.clear();\n this.wisps.length = 0;\n }\n}","import { Shape } from \"three\";\n\nexport class BurstShape extends Shape {\n constructor(sides = 5, innerRadius = 0.5, outerRadius = 1.0) {\n super();\n\n const step = (Math.PI * 2) / sides;\n const halfStep = step / 2;\n const qtrStep = step / 4;\n\n this.moveTo(Math.cos(0) * outerRadius, -Math.sin(0) * outerRadius);\n\n for (let n = 1; n <= sides; ++n) {\n let cx = Math.cos(step * n - qtrStep * 3) * (innerRadius / Math.cos(qtrStep));\n let cy = -Math.sin(step * n - qtrStep * 3) * (innerRadius / Math.cos(qtrStep));\n let dx = Math.cos(step * n - halfStep) * innerRadius;\n let dy = -Math.sin(step * n - halfStep) * innerRadius;\n this.quadraticCurveTo(cx, cy, dx, dy);\n cx = Math.cos(step * n - qtrStep) * (innerRadius / Math.cos(qtrStep));\n cy = -Math.sin(step * n - qtrStep) * (innerRadius / Math.cos(qtrStep));\n dx = Math.cos(step * n) * outerRadius;\n dy = -Math.sin(step * n) * outerRadius;\n this.quadraticCurveTo(cx, cy, dx, dy);\n }\n\n this.closePath();\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { BurstShape } from \"../../shapes/BurstShape\";\n\nexport interface BurstGeometryOptions {\n /** Number of burst rays. Defaults to `5`. */\n sides?: number;\n /** Inner vertex radius. Defaults to `0.5`. */\n innerRadius?: number;\n /** Outer vertex radius. Defaults to `1`. */\n outerRadius?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded burst / starburst prism.\n */\nexport class BurstGeometry extends ExtrudeGeometry {\n constructor({\n sides = 5,\n innerRadius = 0.5,\n outerRadius = 1.0,\n depth = 0.25,\n }: BurstGeometryOptions = {}) {\n super(new BurstShape(sides, innerRadius, outerRadius), { depth, bevelEnabled: false });\n }\n}","import {\n BufferAttribute,\n BufferGeometry,\n CanvasTexture,\n Color,\n ColorRepresentation,\n DoubleSide,\n InstancedMesh,\n Material,\n Matrix4,\n MeshBasicMaterial,\n Object3D,\n Points,\n PointsMaterial,\n Quaternion,\n Vector3,\n} from \"three\";\nimport { BurstGeometry } from \"../geometry/shapes/BurstGeometry\";\n\nexport interface StarBurstShapeOptions {\n /** Burst ray count. Defaults to `4`. */\n sides?: number;\n innerRadius?: number;\n outerRadius?: number;\n /** Extrusion depth; keep small for flat starbursts. Defaults to `0.05`. */\n depth?: number;\n}\n\nexport interface StarFieldEffectOptions {\n /**\n * Rendering style.\n *\n * - `points` (default) — billboard sprites with a procedural starburst texture\n * (not the default square `Points` marker).\n * - `burst` — instanced {@link BurstGeometry} meshes oriented toward the shell center.\n */\n style?: \"points\" | \"burst\";\n /** Shape parameters for both styles; `burst` uses them for geometry, `points` for the sprite. */\n burst?: StarBurstShapeOptions;\n /** Override the burst mesh geometry (`style: \"burst\"` only). */\n geometry?: BufferGeometry;\n /** Override the default field material. */\n material?: Material;\n /** Number of stars. Defaults to `1500`. */\n count?: number;\n /** Shell radius when `minRadius` / `maxRadius` are omitted. Defaults to `500`. */\n radius?: number;\n /** Inner shell radius. Defaults to `radius`. */\n minRadius?: number;\n /** Outer shell radius. Defaults to `radius`. */\n maxRadius?: number;\n /**\n * Minimum angular size (radians at 1 unit distance). Scaled by each star's shell distance\n * so apparent size stays consistent. Defaults to `0.008`.\n */\n sizeMin?: number;\n /** Maximum angular size. Defaults to `0.025`. */\n sizeMax?: number;\n /** Single color or palette; multiple entries pick a random color per star. */\n color?: ColorRepresentation | ColorRepresentation[];\n /** Enable pulsing brightness; call {@link StarFieldEffect.update} each frame when `true`. */\n twinkle?: boolean;\n}\n\nconst SHELL_CENTER = new Vector3(0, 0, 0);\n\n/** Canvas sprite matching the burst profile (inner/outer star polygon). */\nfunction createStarSpriteTexture(\n sides: number,\n innerRadius: number,\n outerRadius: number,\n size = 128,\n): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n const ctx = canvas.getContext(\"2d\")!;\n const outer = size * 0.46;\n const inner = outer * (innerRadius / outerRadius);\n\n ctx.translate(size / 2, size / 2);\n ctx.fillStyle = \"#ffffff\";\n ctx.beginPath();\n for (let i = 0; i < sides * 2; i++) {\n const radius = i % 2 === 0 ? outer : inner;\n const angle = (i / (sides * 2)) * Math.PI * 2 - Math.PI / 2;\n const x = Math.cos(angle) * radius;\n const y = Math.sin(angle) * radius;\n if (i === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.closePath();\n ctx.fill();\n\n const texture = new CanvasTexture(canvas);\n texture.needsUpdate = true;\n return texture;\n}\n\nfunction randomUnitVector(target: Vector3): Vector3 {\n const u = Math.random();\n const v = Math.random();\n const theta = Math.PI * 2 * u;\n const phi = Math.acos(2 * v - 1);\n const sinPhi = Math.sin(phi);\n return target.set(sinPhi * Math.cos(theta), Math.cos(phi), sinPhi * Math.sin(theta));\n}\n\nfunction resolvePalette(color: ColorRepresentation | ColorRepresentation[]): Color[] {\n return (Array.isArray(color) ? color : [color]).map((entry) => new Color(entry));\n}\n\n/**\n * Procedural star field distributed on a spherical shell — intended as an infinite sky dome.\n *\n * Stars are placed in world space around the origin. To keep the shell centered on the\n * viewer, add this object to the **scene** (not the camera) and copy the camera position\n * every frame. Parenting to the camera is not supported: Three.js does not render\n * objects attached to the active camera.\n *\n * **Styles**\n *\n * - `points` — lightweight `Points` sprites using a canvas starburst texture.\n * - `burst` — instanced 3D starbursts ({@link BurstGeometry}) that face the shell center.\n * Uses `DoubleSide` so stars remain visible when the camera sits inside the shell.\n *\n * **Sizing** — `sizeMin` / `sizeMax` are angular extents (radians at unit distance),\n * multiplied by each star's distance from the origin so stars look similar regardless\n * of shell depth (`minRadius`–`maxRadius`).\n *\n * **Rendering** — `frustumCulled` is disabled and materials use `depthWrite: false` so\n * the field draws reliably as a background layer. For per-star color variation in burst\n * mode, colors are written via `InstancedMesh.setColorAt`, not `vertexColors` on the\n * base material.\n *\n * @example\n * ```typescript\n * const stars = new StarFieldEffect({\n * style: \"burst\",\n * count: 2500,\n * radius: 480,\n * twinkle: true,\n * });\n *\n * scene.add(stars);\n *\n * function animate() {\n * stars.position.copy(camera.position); // sky dome follows the viewer\n * stars.update(); // no-op when twinkle is false\n * renderer.render(scene, camera);\n * }\n * ```\n *\n * Call {@link dispose} when removing the effect to free geometry, materials, and the\n * points sprite texture.\n */\nexport class StarFieldEffect extends Object3D {\n readonly style: \"points\" | \"burst\";\n\n private readonly field: Points | InstancedMesh;\n private readonly twinkle: boolean;\n private readonly baseSize: number;\n private readonly baseScales?: Float32Array;\n private readonly twinklePhases?: Float32Array;\n private spriteTexture?: CanvasTexture;\n private readonly dummy = new Object3D();\n\n constructor(options: StarFieldEffectOptions = {}) {\n super();\n\n this.style = options.style ?? \"points\";\n const {\n count = 1500,\n radius = 500,\n minRadius = radius,\n maxRadius = radius,\n sizeMin = 0.008,\n sizeMax = 0.025,\n color = [0xffffff, 0xcad7ff, 0xfff4e0],\n twinkle = false,\n material,\n burst = {},\n geometry,\n } = options;\n\n this.frustumCulled = false;\n this.twinkle = twinkle;\n const shellSpan = Math.max(maxRadius - minRadius, 0);\n const meanRadius = minRadius + shellSpan * 0.5;\n const meanAngular = (sizeMin + sizeMax) * 0.5;\n this.baseSize = meanRadius * meanAngular;\n\n const burstShape = {\n sides: burst.sides ?? 4,\n innerRadius: burst.innerRadius ?? 0.6,\n outerRadius: burst.outerRadius ?? 1.9,\n depth: burst.depth ?? 0.05,\n };\n\n if (this.style === \"burst\") {\n if (twinkle) {\n this.baseScales = new Float32Array(count);\n this.twinklePhases = new Float32Array(count);\n }\n const burstGeometry =\n geometry ??\n new BurstGeometry({\n sides: burstShape.sides,\n innerRadius: burstShape.innerRadius,\n outerRadius: burstShape.outerRadius,\n depth: burstShape.depth,\n });\n this.field = this.createBurstField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n geometry: burstGeometry,\n });\n } else {\n this.field = this.createPointsField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n burstShape,\n });\n }\n\n this.add(this.field);\n }\n\n get drawable(): Points | InstancedMesh {\n return this.field;\n }\n\n get geometry(): BufferGeometry {\n return this.field.geometry;\n }\n\n get material(): Material | Material[] {\n return this.field.material;\n }\n\n /** Release GPU resources held by the field (and sprite texture, if any). */\n dispose(): void {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n this.spriteTexture?.dispose();\n }\n\n /**\n * Animate twinkling. No-op when `twinkle` is `false`.\n *\n * Points style modulates sprite size; burst style pulses each instance scale with\n * a per-star phase offset. Pass elapsed time in seconds (defaults to `performance.now()`).\n */\n update(elapsed = performance.now() * 0.001): void {\n if (!this.twinkle) return;\n\n if (this.field instanceof Points) {\n (this.field.material as PointsMaterial).size =\n this.baseSize * (0.8 + 0.2 * Math.sin(elapsed * 2.5));\n return;\n }\n\n if (!this.baseScales || !this.twinklePhases) return;\n\n const matrix = new Matrix4();\n const position = new Vector3();\n const quaternion = new Quaternion();\n const scale = new Vector3();\n\n for (let i = 0; i < this.field.count; i++) {\n this.field.getMatrixAt(i, matrix);\n matrix.decompose(position, quaternion, scale);\n\n const pulse = 0.75 + 0.25 * Math.sin(elapsed * 2.5 + this.twinklePhases[i]);\n const s = this.baseScales[i] * pulse;\n this.dummy.position.copy(position);\n this.dummy.quaternion.copy(quaternion);\n this.dummy.scale.setScalar(s);\n this.dummy.updateMatrix();\n this.field.setMatrixAt(i, this.dummy.matrix);\n }\n\n this.field.instanceMatrix.needsUpdate = true;\n }\n\n private createPointsField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n burstShape,\n }: {\n count: number;\n minRadius: number;\n maxRadius: number;\n sizeMin: number;\n sizeMax: number;\n color: ColorRepresentation | ColorRepresentation[];\n material?: Material;\n burstShape: Required<StarBurstShapeOptions>;\n }): Points {\n const palette = resolvePalette(color);\n const direction = new Vector3();\n const shellSpan = Math.max(maxRadius - minRadius, 0);\n const meanRadius = minRadius + shellSpan * 0.5;\n const meanAngular = (sizeMin + sizeMax) / 2;\n const pointSize = meanRadius * meanAngular;\n\n const positions = new Float32Array(count * 3);\n const colors = palette.length > 1 ? new Float32Array(count * 3) : null;\n\n for (let i = 0; i < count; i++) {\n const distance = minRadius + Math.random() * shellSpan;\n randomUnitVector(direction).multiplyScalar(distance);\n positions[i * 3] = direction.x;\n positions[i * 3 + 1] = direction.y;\n positions[i * 3 + 2] = direction.z;\n\n if (colors) {\n const starColor = palette[Math.floor(Math.random() * palette.length)];\n colors[i * 3] = starColor.r;\n colors[i * 3 + 1] = starColor.g;\n colors[i * 3 + 2] = starColor.b;\n }\n }\n\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new BufferAttribute(positions, 3));\n if (colors) geometry.setAttribute(\"color\", new BufferAttribute(colors, 3));\n\n this.spriteTexture = createStarSpriteTexture(\n burstShape.sides!,\n burstShape.innerRadius!,\n burstShape.outerRadius!,\n );\n\n const starMaterial =\n material ??\n new PointsMaterial({\n map: this.spriteTexture,\n color: palette.length === 1 ? palette[0].getHex() : 0xffffff,\n size: pointSize,\n sizeAttenuation: true,\n transparent: true,\n alphaTest: 0.05,\n vertexColors: colors !== null,\n depthWrite: false,\n toneMapped: false,\n });\n\n const points = new Points(geometry, starMaterial);\n points.frustumCulled = false;\n points.renderOrder = 1;\n return points;\n }\n\n private createBurstField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n geometry,\n }: {\n count: number;\n minRadius: number;\n maxRadius: number;\n sizeMin: number;\n sizeMax: number;\n color: ColorRepresentation | ColorRepresentation[];\n material?: Material;\n geometry: BufferGeometry;\n }): InstancedMesh {\n const palette = resolvePalette(color);\n const direction = new Vector3();\n const shellSpan = Math.max(maxRadius - minRadius, 0);\n\n const centered = geometry.clone();\n centered.center();\n centered.computeBoundingSphere();\n const meshRadius = centered.boundingSphere?.radius ?? 1;\n\n const starMaterial =\n material ??\n new MeshBasicMaterial({\n color: palette.length === 1 ? palette[0].getHex() : 0xffffff,\n side: DoubleSide,\n depthWrite: false,\n toneMapped: false,\n });\n\n const mesh = new InstancedMesh(centered, starMaterial, count);\n mesh.frustumCulled = false;\n mesh.renderOrder = 1;\n\n for (let i = 0; i < count; i++) {\n const distance = minRadius + Math.random() * shellSpan;\n randomUnitVector(direction).multiplyScalar(distance);\n\n const angular = sizeMin + Math.random() * (sizeMax - sizeMin);\n const scale = (distance * angular) / meshRadius;\n if (this.baseScales) this.baseScales[i] = scale;\n if (this.twinklePhases) this.twinklePhases[i] = Math.random() * Math.PI * 2;\n\n this.dummy.position.copy(direction);\n this.dummy.lookAt(SHELL_CENTER);\n this.dummy.rotateZ(Math.random() * Math.PI * 2);\n this.dummy.scale.setScalar(scale);\n this.dummy.updateMatrix();\n mesh.setMatrixAt(i, this.dummy.matrix);\n\n if (palette.length > 1) {\n mesh.setColorAt(i, palette[Math.floor(Math.random() * palette.length)]);\n }\n }\n\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;\n\n return mesh;\n }\n}","import { BoxGeometry, BufferAttribute, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface BookGeometryOptions {\n /** Cover width (spine to fore-edge). Defaults to `1`. */\n width?: number;\n /** Cover height. Defaults to `1.5`. */\n height?: number;\n /** Spine depth (cover to cover). Defaults to `0.5`. */\n depth?: number;\n /** Cover board thickness. Defaults to `0.05`. */\n coverThickness?: number;\n /** Inset of the page block from the cover edges. Defaults to `0.05`. */\n pageIndent?: number;\n}\n\n/**\n * Closed book — cover shell (group 0) and page block (group 1).\n *\n * Local frame: spine at X=0, fore-edge at +X, sits on the Y=0 plane.\n */\nexport class BookGeometry extends BufferGeometry {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n readonly coverThickness: number;\n readonly pageIndent: number;\n\n constructor({\n width = 1,\n height = 1.5,\n depth = 0.5,\n coverThickness = 0.05,\n pageIndent = 0.05,\n }: BookGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.coverThickness = coverThickness;\n this.pageIndent = pageIndent;\n\n const w = width;\n const h = height;\n const d = depth;\n const t = coverThickness;\n const i = pageIndent;\n\n const vertices = [\n // Front cover\n 0, 0, 0,\n w, 0, 0,\n w, h, 0,\n 0, h, 0,\n\n // Back cover\n w, 0, -d,\n 0, 0, -d,\n 0, h, -d,\n w, h, -d,\n\n // Spine\n 0, 0, -d,\n 0, 0, 0,\n 0, h, 0,\n 0, h, -d,\n\n // Inside front cover\n w, 0, -t,\n t, 0, -t,\n t, h, -t,\n w, h, -t,\n\n // Inside back cover\n t, 0, -d + t,\n w, 0, -d + t,\n w, h, -d + t,\n t, h, -d + t,\n\n // Inside spine\n t, 0, -t,\n t, 0, -d + t,\n t, h, -d + t,\n t, h, -t,\n\n // Front cover top\n 0, h, 0,\n w, h, 0,\n w, h, -t,\n t, h, -t,\n\n // Back cover top\n 0, h, -d,\n t, h, -d + t,\n w, h, -d + t,\n w, h, -d,\n\n // Spine cover top\n 0, h, 0,\n t, h, -t,\n t, h, -d + t,\n 0, h, -d,\n\n // Front cover bottom\n 0, 0, 0,\n t, 0, -t,\n w, 0, -t,\n w, 0, 0,\n\n // Back cover bottom\n 0, 0, -d,\n w, 0, -d,\n w, 0, -d + t,\n t, 0, -d + t,\n\n // Spine cover bottom\n 0, 0, 0,\n 0, 0, -d,\n t, 0, -d + t,\n t, 0, -t,\n\n // Front cover edge\n w, 0, 0,\n w, 0, -t,\n w, h, -t,\n w, h, 0,\n\n // Back cover edge\n w, 0, -d,\n w, h, -d,\n w, h, -d + t,\n w, 0, -d + t,\n ];\n\n\n\n const normals = [\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Front cover\n 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, // Back cover\n -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // Spine\n 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, // Inside front cover\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Inside back cover\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Inside spine\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Front cover top\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Back cover top\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Spine cover top\n 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // Front cover bottom\n 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // Back cover bottom\n 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // Spine cover bottom\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Front cover edge\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Back cover edge\n ];\n\n const u1 = width / ((width * 2) + depth);\n const u2 = (width + depth) / ((width * 2) + depth);\n\n const uvs = [\n u2,0, 1,0, 1,1, u2,1, // Front cover\n 0,0, u1,0, u1,1, 0,1, // Back cover\n u1,0, u2,0, u2,1, u1,1, // Spine\n 1,0, u2,0, u2,1, 1,1, // Inside front cover\n u1,0, 0,0, 0,1, u1,1, // Inside back cover\n u2,0, u1,0, u1,1, u2,1, // Inside spine\n u2,0, 1,0, 1,1, u2,1, // Front cover top\n 0,0, 1,0, 1,1, 0,1, // Back cover top\n 0,0, 1,0, 1,1, 0,1, // Spine cover top\n 0,0, 1,0, 1,1, 0,1, // Front cover bottom\n 0,0, 1,0, 1,1, 0,1, // Back cover bottom\n 0,0, 1,0, 1,1, 0,1, // Spine cover bottom\n 0,0, 1,0, 1,1, 0,1, // Front cover edge\n 0,0, 1,0, 1,1, 0,1, // Back cover edge\n ];\n\n const indices = [\n 0, 1, 2, 0, 2, 3, // Front cover face\n 4, 5, 6, 4, 6, 7, // Back cover face\n 8, 9, 10, 8, 10, 11, // Spine face\n 12, 13, 14, 12, 14, 15, // Inside front cover\n 16, 17, 18, 16, 18, 19, // Inside back cover\n 20, 21, 22, 20, 22, 23, // Inside spine\n 24, 25, 26, 24, 26, 27, // Front cover top\n 28, 29, 30, 28, 30, 31, // Back cover top\n 32, 33, 34, 32, 34, 35, // Spine cover top\n 36, 37, 38, 36, 38, 39, // Front cover bottom\n 40, 41, 42, 40, 42, 43, // Back cover bottom\n 44, 45, 46, 44, 46, 47, // Spine cover bottom\n 48, 49, 50, 48, 50, 51, // Front cover edge\n 52, 53, 54, 52, 54, 55, // Back cover edge\n ];\n\n const positions = new Float32Array(vertices);\n const normalArray = new Float32Array(normals);\n const uvArray = new Float32Array(uvs);\n const indexArray = new Uint16Array(indices);\n\n const coverGeometry = new BufferGeometry();\n coverGeometry.setAttribute('position', new BufferAttribute(positions, 3));\n coverGeometry.setAttribute('normal', new BufferAttribute(normalArray, 3));\n coverGeometry.setAttribute('uv', new BufferAttribute(uvArray, 2));\n coverGeometry.setIndex(new BufferAttribute(indexArray, 1));\n\n const pagesGeometry = new BoxGeometry(width - t - i, h - i * 2, d - t * 2);\n pagesGeometry.translate((width - t - i) / 2 + t, h / 2, -d / 2 );\n this.copy(mergeGeometries([coverGeometry, pagesGeometry], true) as BufferGeometry);\n }\n}\n","import { BookGeometry } from \"../geometry/books/BookGeometry\";\nimport { InstancedMesh, Matrix4, Material, Quaternion, Vector3 } from \"three\";\nimport { createRandom, type RandomSource } from \"../utils/Random\";\nimport { logarithmicRandomMax, logarithmicRandomMin, randomFloat } from \"../utils/RandomNumberUtils\";\n\n/** Default {@link BookGeometry} spine depth — stack layer height when books lay flat. */\nconst BOOK_UNIT_DEPTH = 0.5;\n\n/** Lay a book flat on its cover (+90° X) so spine depth becomes stack height (Y+). */\nconst LAY_FLAT_X = Math.PI / 2;\n\ninterface RandomScaleOptions {\n scaleXMin?: number;\n scaleXMax?: number;\n scaleYMin?: number;\n scaleYMax?: number;\n scaleZMin?: number;\n scaleZMax?: number;\n source: RandomSource;\n}\n\n// Define a generic interface for book row options using scales\ninterface RowOfBooksByScalesOptions<T extends Material = Material> {\n coverMaterial: T;\n pagesMaterial: T;\n scales: Vector3[];\n /** Shared stream for shelf jitter — must be the same source that built `scales`. */\n source: RandomSource;\n}\n\nexport interface RowOfBooksOptions<T extends Material = Material> {\n coverMaterial: T;\n pagesMaterial: T;\n count?: number;\n length?: number;\n scaleXMin?: number;\n scaleXMax?: number;\n scaleYMin?: number;\n scaleYMax?: number;\n scaleZMin?: number;\n scaleZMax?: number;\n /** Optional seed for reproducible layout. Omit for unique runtime. */\n seed?: number;\n}\n\nexport interface StackOfBooksOptions<T extends Material = Material> {\n coverMaterial: T;\n pagesMaterial: T;\n /** Number of books in the stack. Defaults to `6`. */\n count?: number;\n scaleXMin?: number;\n scaleXMax?: number;\n scaleYMin?: number;\n scaleYMax?: number;\n scaleZMin?: number;\n scaleZMax?: number;\n /**\n * Max in-plane spin (world Y, radians) once the book is laid flat — a lazy\n * turn on the floor, not a tilt. Defaults to `0.55` (~31°).\n */\n yawMax?: number;\n /** Max horizontal drift per layer on X/Z. Defaults to `0.06`. */\n offsetMax?: number;\n /** Optional seed for reproducible layout. Omit for unique runtime. */\n seed?: number;\n}\n\nfunction randomScale({\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n source,\n}: RandomScaleOptions): Vector3 {\n return new Vector3(\n randomFloat(scaleXMin, scaleXMax, source),\n logarithmicRandomMax(0.25, scaleYMin, scaleYMax, source),\n logarithmicRandomMin(0.8, scaleZMin, scaleZMax, source),\n );\n}\n\n/**\n * Creates a row of books from the scales array of Vector3.\n */\nexport function rowOfBooksByScales<T extends Material>({\n coverMaterial,\n pagesMaterial,\n scales,\n source,\n}: RowOfBooksByScalesOptions<T>): InstancedMesh {\n const geometry = new BookGeometry();\n const row = new InstancedMesh(geometry, [coverMaterial, pagesMaterial], scales.length);\n const matrix = new Matrix4();\n let currentZ = 0;\n\n for (let i = 0; i < scales.length; i++) {\n const scale = scales[i];\n const scaleMatrix = new Matrix4();\n scaleMatrix.makeScale(scale.x, scale.y, scale.z);\n matrix.identity();\n matrix.multiply(scaleMatrix);\n matrix.setPosition(0.01 + source.float(0, 0.1), 0, currentZ + scale.z * 0.5);\n row.setMatrixAt(i, matrix);\n currentZ += scale.z * 0.5;\n }\n return row;\n}\n\n/**\n * Creates a row of books with a given count.\n */\nexport function rowOfBooksByCount<T extends Material>({\n coverMaterial,\n pagesMaterial,\n count = 10,\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n seed,\n}: RowOfBooksOptions<T>): InstancedMesh {\n const source = createRandom(seed);\n const scales = Array.from({ length: count }, () =>\n randomScale({ scaleXMin, scaleXMax, scaleYMin, scaleYMax, scaleZMin, scaleZMax, source }),\n );\n\n return rowOfBooksByScales({ coverMaterial, pagesMaterial, scales, source });\n}\n\n/**\n * Creates a row of books with a total length.\n */\nexport function rowOfBooksByLength<T extends Material>({\n coverMaterial,\n pagesMaterial,\n length = 10,\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n seed,\n}: RowOfBooksOptions<T>): InstancedMesh {\n const source = createRandom(seed);\n const scales: Vector3[] = [];\n let remainingZ = length;\n while (remainingZ > 0) {\n const scale = randomScale({ scaleXMin, scaleXMax, scaleYMin, scaleYMax, scaleZMin, scaleZMax, source });\n scale.z = Math.min(scale.z, remainingZ);\n scales.push(scale);\n remainingZ -= scale.z;\n }\n\n return rowOfBooksByScales({ coverMaterial, pagesMaterial, scales, source });\n}\n\n/**\n * Stack of books on the floor — each book lays flat on its cover; count sets stack height.\n * Each layer is laid flat (+90° X), then given a small in-plane spin (world Y)\n * around the book's geometric center — not the spine corner.\n *\n * Local frame: bottom of the stack at Y=0, centered on X/Z.\n *\n * @example\n * ```ts\n * const stack = stackOfBooks({\n * coverMaterial,\n * pagesMaterial,\n * count: 8,\n * yawMax: 0.6,\n * seed: 1337,\n * });\n * scene.add(stack);\n * ```\n */\nexport function stackOfBooks<T extends Material>({\n coverMaterial,\n pagesMaterial,\n count = 6,\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n yawMax = 0.55,\n offsetMax = 0.06,\n seed,\n}: StackOfBooksOptions<T>): InstancedMesh {\n const source = createRandom(seed);\n const geometry = new BookGeometry();\n const stack = new InstancedMesh(geometry, [coverMaterial, pagesMaterial], count);\n\n const matrix = new Matrix4();\n const position = new Vector3();\n const quaternion = new Quaternion();\n const layFlatQuat = new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), LAY_FLAT_X);\n const spinQuat = new Quaternion();\n const scale = new Vector3();\n /** Upright geometry center — spin pivots here, not the bottom-front-spine corner. */\n const localCenter = new Vector3(\n geometry.width * 0.5,\n geometry.height * 0.5,\n -geometry.depth * 0.5,\n );\n const scaledCenter = new Vector3();\n const centerOffset = new Vector3();\n\n let currentY = 0;\n\n for (let i = 0; i < count; i++) {\n const layerScale = randomScale({\n scaleXMin,\n scaleXMax,\n scaleYMin,\n scaleYMax,\n scaleZMin,\n scaleZMax,\n source,\n });\n\n scale.copy(layerScale);\n const layerHeight = BOOK_UNIT_DEPTH * layerScale.z;\n\n spinQuat.setFromAxisAngle(new Vector3(0, 1, 0), source.float(-yawMax, yawMax));\n quaternion.copy(layFlatQuat).premultiply(spinQuat);\n\n scaledCenter.copy(localCenter).multiply(scale);\n centerOffset.copy(scaledCenter).applyQuaternion(quaternion);\n\n position.set(\n source.float(-offsetMax, offsetMax),\n currentY + layerHeight * 0.5,\n source.float(-offsetMax, offsetMax),\n );\n position.sub(centerOffset);\n\n matrix.compose(position, quaternion, scale);\n stack.setMatrixAt(i, matrix);\n\n currentY += layerHeight;\n }\n\n stack.instanceMatrix.needsUpdate = true;\n return stack;\n}\n","import { Shape } from \"three\";\n\nexport class HexagonShape extends Shape {\n constructor(radius = 1) {\n super();\n\n for (let i = 0; i < 6; i++) {\n const angle = (Math.PI / 3) * i; // 60-degree increments\n const x = Math.cos(angle) * radius;\n const y = Math.sin(angle) * radius;\n\n if (i === 0) this.moveTo(x, y);\n else this.lineTo(x, y);\n }\n this.closePath();\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { HexagonShape } from \"../../shapes/HexagonShape\";\n\nexport interface HexagonGeometryOptions {\n /** Hex circumradius. Defaults to `1`. */\n radius?: number;\n /** Extrusion depth. Defaults to `0.01`. */\n depth?: number;\n}\n\n/**\n * Extruded regular hexagon prism.\n */\nexport class HexagonGeometry extends ExtrudeGeometry {\n readonly radius: number;\n readonly depth: number;\n\n constructor({ radius = 1, depth = 0.01 }: HexagonGeometryOptions = {}) {\n super(new HexagonShape(radius), { depth, bevelEnabled: false });\n\n this.radius = radius;\n this.depth = depth;\n }\n}","import { InstancedMesh, Material, MeshStandardMaterial, Object3D } from \"three\";\nimport { HexagonGeometry } from \"../geometry/shapes/HexagonGeometry\";\n\nexport interface HexagonalTileCountOptions {\n width: number; // Total area width to fill (x-axis)\n depth: number; // Total area depth to fill (z-axis)\n height: number; // Height of each tile (y-axis)\n count: number; // Number of tiles along the x-axis\n gap: number; // Gap spacing between tiles\n material?: Material; // Optional custom material\n}\n\n/**\n * Hexagonal tile pattern factory with density control.\n *\n * Example usage:\n * ```ts\n * const hexTile = createHexagonalTilesByCount({\n * width: 10,\n * depth: 10,\n * height: 0.01,\n * count: 10, // 10 tiles along the x-axis\n * gap: 0.01,\n * material: new THREE.MeshStandardMaterial({ color: 0xffffff }),\n * });\n *\n * scene.add(hexTile);\n * ```\n */\nexport function createHexagonalTilesByCount(options: HexagonalTileCountOptions): InstancedMesh {\n const { width, depth, height, count, gap, material } = options;\n\n const tileMaterial = material || new MeshStandardMaterial({ color: 0xffffff });\n\n // Calculate the radius based on the x-axis count and area width\n const spacingX = width / count; // Horizontal spacing including gap\n const radius = ((spacingX - gap) * 2) / 3; // Adjusted for hexagonal geometry\n\n // Effective spacing between hexagon centers\n const effectiveSpacingZ = Math.sqrt(3) * radius + gap;\n\n // Calculate the number of tiles that fit along the z-axis\n const countZ = Math.floor(depth / effectiveSpacingZ);\n\n const hexTileCount = count * countZ;\n\n // Create a hexagonal prism geometry\n const geometry = new HexagonGeometry({ radius, depth: height });\n\n // Rotate geometry so tiles lay flat\n geometry.rotateX(-Math.PI / 2);\n\n // Create the instanced mesh\n const instancedMesh = new InstancedMesh(geometry, tileMaterial, hexTileCount);\n\n const dummy = new Object3D();\n let index = 0;\n\n for (let x = 0; x < count; x++) {\n for (let z = 0; z < countZ; z++) {\n // Calculate the staggered row offset\n const offsetX = x * spacingX;\n const offsetZ = z * effectiveSpacingZ + (x % 2) * (effectiveSpacingZ / 2); // Stagger odd rows by half a tile\n\n // Center the grid\n const positionX = offsetX - (count * spacingX) / 2 + spacingX / 2;\n const positionZ = offsetZ - (countZ * effectiveSpacingZ) / 2 + effectiveSpacingZ / 2;\n\n dummy.position.set(positionX, 0, positionZ);\n dummy.updateMatrix();\n instancedMesh.setMatrixAt(index++, dummy.matrix);\n }\n }\n\n instancedMesh.instanceMatrix.needsUpdate = true;\n\n return instancedMesh;\n}\n\nexport interface HexagonalTileRadiusOptions {\n width: number; // Total area width to fill (x-axis)\n depth: number; // Total area depth to fill (z-axis)\n height: number; // Height of each tile (y-axis)\n radius: number; // Radius of each hexagonal tile\n gap: number; // Gap spacing between tiles\n material?: Material; // Optional custom material\n}\n\n/**\n * Hexagonal tile pattern factory.\n *\n * Example usage:\n * ```ts\n * const hexTile = createHexagonalTilesByRadius({\n * width: 10,\n * depth: 10,\n * height: 0.01,\n * radius: 0.1,\n * gap: 0.01,\n * material: new THREE.MeshStandardMaterial({ color: 0xffffff }),\n * });\n *\n * scene.add(hexTile);\n * ```\n */\nexport function createHexagonalTilesByRadius(options: HexagonalTileRadiusOptions): InstancedMesh {\n const { width, depth, height, radius, gap, material } = options;\n\n const tileMaterial = material || new MeshStandardMaterial({ color: 0xffffff });\n\n // Effective spacing between hexagon centers, including the gap\n const spacingX = (radius * 3) / 2 + gap; // Horizontal distance between hex centers\n const spacingZ = Math.sqrt(3) * radius + gap; // Vertical distance between hex centers\n\n // Calculate the number of tiles that fit within the area\n const hexTileCountX = Math.floor(width / spacingX);\n const hexTileCountZ = Math.floor(depth / spacingZ);\n\n const hexTileCount = hexTileCountX * hexTileCountZ;\n\n // Create a hexagonal prism geometry\n const geometry = new HexagonGeometry({ radius, depth: height });\n\n // Rotate geometry so tiles lay flat\n geometry.rotateX(-Math.PI / 2);\n\n // Create the instanced mesh\n const instancedMesh = new InstancedMesh(geometry, tileMaterial, hexTileCount);\n\n const dummy = new Object3D();\n let index = 0;\n\n for (let x = 0; x < hexTileCountX; x++) {\n for (let z = 0; z < hexTileCountZ; z++) {\n // Calculate the staggered row offset\n const offsetX = x * spacingX;\n const offsetZ = z * spacingZ + (x % 2) * (spacingZ / 2); // Stagger odd rows by half a tile\n\n // Center the grid\n const positionX = offsetX - (hexTileCountX * spacingX) / 2 + spacingX / 2;\n const positionZ = offsetZ - (hexTileCountZ * spacingZ) / 2 + spacingZ / 2;\n\n dummy.position.set(positionX, 0, positionZ);\n dummy.updateMatrix();\n instancedMesh.setMatrixAt(index++, dummy.matrix);\n }\n }\n\n instancedMesh.instanceMatrix.needsUpdate = true;\n\n return instancedMesh;\n}\n","import { BufferGeometry, DodecahedronGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface MossyRockGeometryOptions {\n /** Rock dodecahedron radius. Defaults to `1`. */\n radius?: number;\n /** Dodecahedron detail level. Defaults to `0`. */\n detail?: number;\n /** Moss horizontal scale relative to the rock. Defaults to `0.9`. */\n mossScaleXZ?: number;\n /** Moss vertical scale relative to the rock. Defaults to `0.5`. */\n mossScaleY?: number;\n /** Moss center offset above the rock origin. Defaults to `0.3`. */\n mossOffsetY?: number;\n}\n\n/**\n * Mossy rock — dodecahedron body with a smaller, flatter moss shell (group 1).\n *\n * Material groups: `0` rock, `1` moss.\n *\n * Local frame: centered on the rock body.\n */\nexport class MossyRockGeometry extends BufferGeometry {\n readonly radius: number;\n readonly detail: number;\n\n constructor({\n radius = 1,\n detail = 0,\n mossScaleXZ = 0.9,\n mossScaleY = 0.5,\n mossOffsetY = 0.3,\n }: MossyRockGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.detail = detail;\n\n const rock = new DodecahedronGeometry(radius, detail);\n\n const moss = new DodecahedronGeometry(radius, detail);\n moss.scale(mossScaleXZ, mossScaleY, mossScaleXZ);\n moss.translate(0, mossOffsetY, 0);\n\n this.copy(mergeGeometries([rock, moss], true) as BufferGeometry);\n this.computeVertexNormals();\n }\n}","import { Axis } from \"../constants/Axis\";\nimport { BufferGeometry, Vector3 } from \"three\";\nimport { mergeVertices } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport function randomTransformVertices<T extends BufferGeometry>(geometry:T, axis = Axis.XYZ, minScale = 0.5, maxScale = 2.0) {\n // Delete unnecessary attributes\n geometry.deleteAttribute(\"uv\");\n geometry.deleteAttribute(\"normal\");\n geometry = mergeVertices(geometry) as T;\n geometry.computeVertexNormals();\n\n // Get position attribute\n const positionAttribute = geometry.getAttribute(\"position\");\n\n // Loop through each vertex\n for (let i = 0; i < positionAttribute.count; i++) {\n const vertex = new Vector3().fromBufferAttribute(positionAttribute, i);\n\n // Randomly scale the displacement along the given axis\n const randomScale = Math.random() * (maxScale - minScale) + minScale;\n const displacement = axis.clone().multiplyScalar(randomScale);\n\n // Apply the displacement to the vertex\n vertex.add(displacement);\n positionAttribute.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n\n // Notify Three.js that the position attribute has been updated\n positionAttribute.needsUpdate = true;\n geometry.computeVertexNormals();\n\n return geometry;\n}\n","import { BufferGeometry, SphereGeometry } from \"three\";\nimport { Axis } from \"../../constants/Axis\";\nimport { randomTransformVertices } from \"../../utils/VertexUtils\";\n\nexport interface RockGeometryOptions {\n /** Base sphere radius before vertex noise. Defaults to `1`. */\n radius?: number;\n /** Horizontal segments. Defaults to `4`. */\n widthSegments?: number;\n /** Vertical segments. Defaults to `4`. */\n heightSegments?: number;\n}\n\n/**\n * Low-poly rock — sphere with randomized vertex offsets, then centered.\n */\nexport class RockGeometry extends BufferGeometry {\n readonly radius: number;\n readonly widthSegments: number;\n readonly heightSegments: number;\n\n constructor({\n radius = 1,\n widthSegments = 4,\n heightSegments = 4,\n }: RockGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.widthSegments = widthSegments;\n this.heightSegments = heightSegments;\n\n const sphere = new SphereGeometry(radius, widthSegments, heightSegments);\n this.copy(randomTransformVertices(sphere, Axis.XYZ, 0.5, 1.0));\n this.computeVertexNormals();\n this.center();\n }\n}","import {\n Color,\n ColorRepresentation,\n Euler,\n InstancedMesh,\n Material,\n Matrix4,\n MeshStandardMaterial,\n Quaternion,\n Vector3,\n} from \"three\";\nimport { MossyRockGeometry } from \"../geometry/rocks/MossyRockGeometry\";\nimport { RockGeometry } from \"../geometry/rocks/RockGeometry\";\nimport { createRandom } from \"../utils/Random\";\n\nexport interface RockScatterBounds {\n /** Scatter extent along X (centered on origin). Defaults to `4`. */\n width?: number;\n /** Scatter extent along Z (centered on origin). Defaults to `4`. */\n depth?: number;\n /** Max random Y offset above the ground plane. Defaults to `0`. */\n heightJitter?: number;\n}\n\nexport interface RockScatterPlacementOptions extends RockScatterBounds {\n /** Number of instances. Defaults to `5`. */\n count?: number;\n /** Min per-axis instance scale. Defaults to `0.8`. */\n scaleMin?: number;\n /** Max per-axis instance scale. Defaults to `1.2`. */\n scaleMax?: number;\n /** Optional seed for reproducible scatter. Omit for unique runtime. */\n seed?: number;\n}\n\nexport interface ScatterRocksOptions extends RockScatterPlacementOptions {\n /** Base sphere radius for each instance geometry. Defaults to `1`. */\n radius?: number;\n widthSegments?: number;\n heightSegments?: number;\n material?: Material;\n /** Stone tint when `material` is omitted. Defaults to `#808080`. */\n color?: ColorRepresentation;\n}\n\nexport interface ScatterMossyRocksOptions extends RockScatterPlacementOptions {\n /** Dodecahedron radius for each instance geometry. Defaults to `1`. */\n radius?: number;\n detail?: number;\n mossScaleXZ?: number;\n mossScaleY?: number;\n mossOffsetY?: number;\n rockMaterial?: Material;\n mossMaterial?: Material;\n /** Rock tint when `rockMaterial` is omitted. Defaults to `#808080`. */\n rockColor?: ColorRepresentation;\n /** Moss tint when `mossMaterial` is omitted. Defaults to `#4b8b3b`. */\n mossColor?: ColorRepresentation;\n /** Moss opacity when `mossMaterial` is omitted. Defaults to `0.8`. */\n mossOpacity?: number;\n}\n\nfunction placeInstances(\n mesh: InstancedMesh,\n {\n count = 5,\n width = 4,\n depth = 4,\n heightJitter = 0,\n scaleMin = 0.8,\n scaleMax = 1.2,\n seed,\n }: RockScatterPlacementOptions,\n): void {\n const source = createRandom(seed);\n const matrix = new Matrix4();\n const position = new Vector3();\n const quaternion = new Quaternion();\n const scale = new Vector3();\n const rotation = new Euler();\n\n for (let i = 0; i < count; i++) {\n scale.set(\n source.float(scaleMin, scaleMax),\n source.float(scaleMin, scaleMax),\n source.float(scaleMin, scaleMax),\n );\n rotation.set(source.float(0, Math.PI), source.float(0, Math.PI), source.float(0, Math.PI));\n quaternion.setFromEuler(rotation);\n position.set(\n source.float(-width / 2, width / 2),\n source.float(0, heightJitter),\n source.float(-depth / 2, depth / 2),\n );\n matrix.compose(position, quaternion, scale);\n mesh.setMatrixAt(i, matrix);\n }\n\n mesh.instanceMatrix.needsUpdate = true;\n}\n\n/**\n * Scatter instanced rocks inside a horizontal bounds region.\n *\n * @example\n * ```ts\n * const rocks = scatterRocks({ count: 12, width: 8, depth: 8, seed: 1337 });\n * scene.add(rocks);\n * ```\n */\nexport function scatterRocks({\n count = 5,\n width = 4,\n depth = 4,\n heightJitter = 0,\n scaleMin = 0.8,\n scaleMax = 1.2,\n seed,\n radius = 1,\n widthSegments = 4,\n heightSegments = 4,\n material,\n color = \"#808080\",\n}: ScatterRocksOptions = {}): InstancedMesh {\n const rockMaterial =\n material ??\n new MeshStandardMaterial({ color: new Color(color), flatShading: true });\n\n const geometry = new RockGeometry({ radius, widthSegments, heightSegments });\n const mesh = new InstancedMesh(geometry, rockMaterial, count);\n\n placeInstances(mesh, { count, width, depth, heightJitter, scaleMin, scaleMax, seed });\n return mesh;\n}\n\n/**\n * Scatter instanced mossy rocks inside a horizontal bounds region.\n *\n * Uses two material groups (rock + moss) on a shared {@link InstancedMesh}.\n */\nexport function scatterMossyRocks({\n count = 5,\n width = 4,\n depth = 4,\n heightJitter = 0,\n scaleMin = 0.8,\n scaleMax = 1.2,\n seed,\n radius = 1,\n detail = 0,\n mossScaleXZ = 0.9,\n mossScaleY = 0.5,\n mossOffsetY = 0.3,\n rockMaterial,\n mossMaterial,\n rockColor = \"#808080\",\n mossColor = \"#4b8b3b\",\n mossOpacity = 0.8,\n}: ScatterMossyRocksOptions = {}): InstancedMesh {\n const materials: Material[] = [\n rockMaterial ??\n new MeshStandardMaterial({ color: new Color(rockColor), flatShading: true }),\n mossMaterial ??\n new MeshStandardMaterial({\n color: new Color(mossColor),\n flatShading: true,\n opacity: mossOpacity,\n transparent: mossOpacity < 1,\n }),\n ];\n\n const geometry = new MossyRockGeometry({ radius, detail, mossScaleXZ, mossScaleY, mossOffsetY });\n const mesh = new InstancedMesh(geometry, materials, count);\n\n placeInstances(mesh, { count, width, depth, heightJitter, scaleMin, scaleMax, seed });\n return mesh;\n}","import { BoxGeometry, ExtrudeGeometry, Path, Shape } from \"three\";\n\n/**\n * Axis-aligned diamond lattice\n */\nexport interface DiamondLatticeGrid {\n /** Horizontal half-diagonal of each quarrel (east–west point spacing). */\n a: number;\n /** Vertical half-diagonal of each quarrel (north–south point spacing). */\n b: number;\n /**\n * Came angle from +X; the two families run at `+angle` and `−angle`.\n * Equals 45° only when `a === b`.\n */\n angle: number;\n /** Shared perpendicular spacing for both came families. */\n spacing: number;\n}\n\n/**\n * Perpendicular distance from the window center to a corner along the diamond\n * grid axis (45° families share this spacing when square).\n */\nexport function diamondLatticeCornerSpan(width: number, height: number): number {\n return (width / 2 + height / 2) / Math.SQRT2;\n}\n\n/**\n * Build an axis-aligned diamond grid from cell counts.\n *\n * `cellsX` quarrels span the width (east–west); `cellsY` span the height.\n * Equal counts on a square opening yield square diamonds; `5×10` elongates them\n * vertically while keeping north/south tips on the same vertical axis.\n */\nexport function diamondLatticeGridFromCells(\n width: number,\n height: number,\n cellsX: number,\n cellsY: number,\n): DiamondLatticeGrid {\n const cx = Math.max(1, Math.round(cellsX));\n const cy = Math.max(1, Math.round(cellsY));\n const a = width / (2 * cx);\n const b = height / (2 * cy);\n return {\n a,\n b,\n angle: Math.atan2(b, a),\n spacing: (2 * a * b) / Math.hypot(a, b),\n };\n}\n\n/**\n * Snap cell size so diagonal cames align symmetrically at all four frame edges.\n * Legacy single-spacing helper — prefer {@link diamondLatticeGridFromCells}.\n */\nexport function fitDiamondLatticeCell(width: number, height: number, preferredCell: number): number {\n const span = diamondLatticeCornerSpan(width, height);\n const count = Math.max(2, Math.round(span / preferredCell));\n return span / count;\n}\n\n/** Derive uniform cell size from center-to-corner periods. Legacy — prefer grid counts. */\nexport function diamondLatticeCellFromCount(width: number, height: number, cellsAcross: number): number {\n const span = diamondLatticeCornerSpan(width, height);\n return span / Math.max(2, cellsAcross);\n}\n\nexport interface DiamondLatticePartOptions {\n width: number;\n height: number;\n /** Center Y of the opening in local space. Defaults to `0`. */\n centerY?: number;\n grid: DiamondLatticeGrid;\n leadThickness: number;\n leadDepth: number;\n}\n\n/**\n * Build merged box geometries for the outer frame and diagonal lead cames.\n * Diagonal bars are trimmed to the rectangular opening (segment clip, not stencil).\n */\nexport function buildDiamondLatticeParts({\n width,\n height,\n centerY = 0,\n grid,\n leadThickness: barT,\n leadDepth: barD,\n}: DiamondLatticePartOptions): BoxGeometry[] {\n const hw = width / 2;\n const hh = height / 2;\n const parts: BoxGeometry[] = [\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY - hh, 0),\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY + hh, 0),\n new BoxGeometry(barT, height + barT, barD).translate(-hw, centerY, 0),\n new BoxGeometry(barT, height + barT, barD).translate(hw, centerY, 0),\n ];\n\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, grid.angle);\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, -grid.angle);\n return parts;\n}\n\n/** Diagonal cames only — no outer frame (for stencil-masked openings). */\nexport function buildDiamondLatticeCameParts(options: DiamondLatticePartOptions): BoxGeometry[] {\n const { width, height, centerY = 0, grid, leadThickness: barT, leadDepth: barD } = options;\n const parts: BoxGeometry[] = [];\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, grid.angle);\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, -grid.angle);\n return parts;\n}\n\nfunction addDiagonalFamily(\n parts: BoxGeometry[],\n winW: number,\n winH: number,\n winY: number,\n spacing: number,\n barT: number,\n barD: number,\n angle: number,\n): void {\n const hw = winW / 2;\n const hh = winH / 2;\n const minX = -hw;\n const maxX = hw;\n const minY = winY - hh;\n const maxY = winY + hh;\n const len = Math.hypot(winW, winH) + barT;\n const perpX = -Math.sin(angle);\n const perpY = Math.cos(angle);\n const count = Math.ceil(Math.hypot(winW, winH) / spacing) + 2;\n\n for (let i = -count; i <= count; i++) {\n const cx = perpX * i * spacing;\n const cy = winY + perpY * i * spacing;\n const dx = Math.cos(angle) * len * 0.5;\n const dy = Math.sin(angle) * len * 0.5;\n const clipped = clipSegmentToAabb(cx - dx, cy - dy, cx + dx, cy + dy, minX, minY, maxX, maxY);\n if (!clipped) continue;\n\n const [x1, y1, x2, y2] = clipped;\n const clippedLen = Math.hypot(x2 - x1, y2 - y1);\n if (clippedLen < 1e-6) continue;\n\n const geo = new BoxGeometry(clippedLen, barT, barD);\n geo.rotateZ(angle);\n geo.translate((x1 + x2) / 2, (y1 + y2) / 2, 0);\n parts.push(geo);\n }\n}\n\n/** Clip a segment to an axis-aligned rectangle; returns endpoints inside the opening. */\nexport function clipSegmentToAabb(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): [number, number, number, number] | null {\n const dx = x2 - x1;\n const dy = y2 - y1;\n let tmin = 0;\n let tmax = 1;\n\n const axes: [number, number, number, number][] = [\n [x1, dx, minX, maxX],\n [y1, dy, minY, maxY],\n ];\n\n for (const [p, dp, min, max] of axes) {\n if (Math.abs(dp) < 1e-9) {\n if (p < min || p > max) return null;\n } else {\n const a = (min - p) / dp;\n const b = (max - p) / dp;\n tmin = Math.max(tmin, Math.min(a, b));\n tmax = Math.min(tmax, Math.max(a, b));\n if (tmin > tmax) return null;\n }\n }\n\n return [x1 + dx * tmin, y1 + dy * tmin, x1 + dx * tmax, y1 + dy * tmax];\n}\n\n/** Rectangular lower section plus circular arch head. */\nexport interface ArchedOpeningBounds {\n width: number;\n /** Height of the straight-sided lower section. */\n rectHeight: number;\n /** Arch rise from the spring line to the apex. Defaults to `width / 2` (semicircle). */\n archHeight?: number;\n /** Vertical center of the full opening. Defaults to `0`. */\n centerY?: number;\n}\n\nexport interface ArchedOpeningMetrics {\n hw: number;\n ymin: number;\n ymax: number;\n rectTopY: number;\n /** Circle center Y — lies on or below the spring line. */\n archCy: number;\n /** Circular arc radius derived from `width` and `archHeight`. */\n archRadius: number;\n archHeight: number;\n totalHeight: number;\n centerY: number;\n}\n\n/**\n * Circular arc through `(-width/2, springY)` and `(width/2, springY)` with rise\n * `archHeight`. Frame, glass, and lattice clip all use this same arc.\n */\nexport function archedOpeningMetrics({\n width,\n rectHeight,\n archHeight = width / 2,\n centerY = 0,\n}: ArchedOpeningBounds): ArchedOpeningMetrics {\n const rise = Math.max(archHeight, 1e-6);\n const archRadius = (width * width + 4 * rise * rise) / (8 * rise);\n const totalHeight = rectHeight + rise;\n const ymin = centerY - totalHeight / 2;\n const rectTopY = ymin + rectHeight;\n // Center sits `archRadius − rise` below the spring line (on it for a semicircle,\n // where radius === rise). Getting this sign right is what makes the apex land at\n // `rectTopY + rise` for shallow and tall arches, not just the semicircle case.\n const archCy = rectTopY + rise - archRadius;\n return {\n hw: width / 2,\n ymin,\n ymax: rectTopY + rise,\n rectTopY,\n archCy,\n archRadius,\n archHeight: rise,\n totalHeight,\n centerY,\n };\n}\n\ninterface ArchedOutlineTarget {\n moveTo(x: number, y: number): unknown;\n lineTo(x: number, y: number): unknown;\n absarc(\n x: number,\n y: number,\n radius: number,\n startAngle: number,\n endAngle: number,\n clockwise: boolean,\n ): unknown;\n closePath(): unknown;\n}\n\n/** Trace the shared rect-plus-arch outline (glass, stencil mask, frame outer edge). */\nexport function traceArchedOpeningOutline(\n target: ArchedOutlineTarget,\n metrics: ArchedOpeningMetrics,\n { hole = false }: { hole?: boolean } = {},\n): void {\n const { hw, ymin, rectTopY, archCy, archRadius } = metrics;\n const angleLeft = Math.atan2(rectTopY - archCy, -hw);\n const angleRight = Math.atan2(rectTopY - archCy, hw);\n\n if (!hole) {\n target.moveTo(-hw, ymin);\n target.lineTo(hw, ymin);\n target.lineTo(hw, rectTopY);\n // Upper bulge: right spring → left spring, counter-clockwise along the top arc.\n target.absarc(0, archCy, archRadius, angleRight, angleLeft, false);\n target.lineTo(-hw, rectTopY);\n target.closePath();\n return;\n }\n\n target.moveTo(-hw, ymin);\n target.lineTo(-hw, rectTopY);\n // Hole winds opposite the outer contour — clockwise along the inner top arc.\n target.absarc(0, archCy, archRadius, angleLeft, angleRight, true);\n target.lineTo(hw, rectTopY);\n target.lineTo(hw, ymin);\n target.closePath();\n}\n\n/** Inset opening for frame ring inner edge (uniform `inset` wall thickness). */\nexport function insetArchedOpeningMetrics(\n outer: ArchedOpeningMetrics,\n inset: number,\n): ArchedOpeningMetrics {\n const hw = Math.max(outer.hw - inset, inset);\n const ymin = outer.ymin + inset;\n const rectTopY = outer.rectTopY - inset;\n const archHeight = Math.max(outer.archHeight - inset, inset);\n const archRadius = (hw * hw + archHeight * archHeight) / (2 * archHeight);\n const archCy = rectTopY + archHeight - archRadius;\n const ymax = rectTopY + archHeight;\n return {\n hw,\n ymin,\n ymax,\n rectTopY,\n archCy,\n archRadius,\n archHeight,\n totalHeight: ymax - ymin,\n centerY: (ymin + ymax) / 2,\n };\n}\n\nconst ARCHED_SHAPE_CURVE_SEGMENTS = 48;\n\n/** Extruded frame ring following the arched opening perimeter. */\nexport function buildArchedDiamondLatticeFrameGeometry(\n metrics: ArchedOpeningMetrics,\n barThickness: number,\n barDepth: number,\n): ExtrudeGeometry {\n const outer = new Shape();\n traceArchedOpeningOutline(outer, metrics);\n\n const inner = new Path();\n traceArchedOpeningOutline(inner, insetArchedOpeningMetrics(metrics, barThickness), { hole: true });\n outer.holes.push(inner);\n\n const geo = new ExtrudeGeometry(outer, {\n depth: barDepth,\n bevelEnabled: false,\n curveSegments: ARCHED_SHAPE_CURVE_SEGMENTS,\n });\n geo.translate(0, 0, -barDepth / 2);\n return geo;\n}\n\n/** Spring-to-apex Y shift that snaps the lattice phase to the rect/arch junction. */\nexport function diamondLatticeSpringPhaseShift(\n ymin: number,\n rectTopY: number,\n grid: DiamondLatticeGrid,\n): number {\n const period = 2 * grid.b;\n const springFromYmin = rectTopY - ymin;\n const snapped = Math.round(springFromYmin / period) * period;\n return snapped - springFromYmin;\n}\n\nfunction pointInsideArchedOpening(\n x: number,\n y: number,\n { hw, ymin, ymax, rectTopY, archCy, archRadius }: ArchedOpeningMetrics,\n eps = 1e-6,\n): boolean {\n if (y < ymin - eps || y > ymax + eps) return false;\n if (y <= rectTopY + eps) return Math.abs(x) <= hw + eps;\n const dx = x;\n const dy = y - archCy;\n return dx * dx + dy * dy <= archRadius * archRadius + eps;\n}\n\nfunction collectLineParameterSplits(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n metrics: ArchedOpeningMetrics,\n): number[] {\n const ts = new Set<number>([0, 1]);\n const dx = x2 - x1;\n const dy = y2 - y1;\n const { hw, ymin, ymax, rectTopY, archCy, archRadius } = metrics;\n\n const addIfInterior = (t: number) => {\n if (t > 1e-9 && t < 1 - 1e-9) ts.add(t);\n };\n\n if (Math.abs(dx) > 1e-9) {\n addIfInterior((-hw - x1) / dx);\n addIfInterior((hw - x1) / dx);\n }\n if (Math.abs(dy) > 1e-9) {\n addIfInterior((ymin - y1) / dy);\n addIfInterior((rectTopY - y1) / dy);\n addIfInterior((ymax - y1) / dy);\n }\n\n const ax = x1;\n const ay = y1 - archCy;\n const a = dx * dx + dy * dy;\n const b = 2 * (ax * dx + ay * dy);\n const c = ax * ax + ay * ay - archRadius * archRadius;\n const disc = b * b - 4 * a * c;\n if (disc >= 0 && a > 1e-12) {\n const sqrtDisc = Math.sqrt(disc);\n addIfInterior((-b - sqrtDisc) / (2 * a));\n addIfInterior((-b + sqrtDisc) / (2 * a));\n }\n\n return [...ts].sort((left, right) => left - right);\n}\n\n/**\n * Clip a segment to a rect-plus-semicircle opening (analytic, same family as\n * {@link clipSegmentToAabb}).\n */\nexport function clipSegmentToArchedOpening(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n bounds: ArchedOpeningBounds,\n): [number, number, number, number] | null {\n const metrics = archedOpeningMetrics(bounds);\n const splits = collectLineParameterSplits(x1, y1, x2, y2, metrics);\n const dx = x2 - x1;\n const dy = y2 - y1;\n\n // The circle's lower half dips into the rectangular section, so a single line\n // can be split at a circle crossing that isn't a real boundary there. Both\n // sides stay inside, so merge adjacent interior intervals into runs and keep\n // the longest run rather than a single sub-interval (which would truncate the\n // came at the phantom crossing).\n const runs: [number, number][] = [];\n let runStart: number | null = null;\n let runEnd = 0;\n for (let i = 0; i < splits.length - 1; i++) {\n const t0 = splits[i];\n const t1 = splits[i + 1];\n const tm = (t0 + t1) * 0.5;\n const mx = x1 + dx * tm;\n const my = y1 + dy * tm;\n if (pointInsideArchedOpening(mx, my, metrics)) {\n if (runStart === null) runStart = t0;\n runEnd = t1;\n } else if (runStart !== null) {\n runs.push([runStart, runEnd]);\n runStart = null;\n }\n }\n if (runStart !== null) runs.push([runStart, runEnd]);\n\n let best: [number, number] | null = null;\n let bestLen = 0;\n for (const run of runs) {\n const len = run[1] - run[0];\n if (len > bestLen) {\n bestLen = len;\n best = run;\n }\n }\n\n if (!best || bestLen < 1e-9) return null;\n const [t0, t1] = best;\n return [x1 + dx * t0, y1 + dy * t0, x1 + dx * t1, y1 + dy * t1];\n}\n\nexport interface ArchedDiamondLatticePartOptions {\n width: number;\n rectHeight: number;\n archHeight?: number;\n centerY?: number;\n grid: DiamondLatticeGrid;\n leadThickness: number;\n leadDepth: number;\n /**\n * Shrink the opening the cames are clipped to (positioning stays on the full\n * grid). Set to the frame thickness so came ends tuck under the frame ring\n * instead of poking past the outer silhouette. Defaults to `0`.\n */\n clipInset?: number;\n}\n\n/** Recover the rect-plus-arch bounds from a metrics object (inverse of {@link archedOpeningMetrics}). */\nfunction boundsFromMetrics(m: ArchedOpeningMetrics): ArchedOpeningBounds {\n return {\n width: 2 * m.hw,\n rectHeight: m.rectTopY - m.ymin,\n archHeight: m.archHeight,\n centerY: m.centerY,\n };\n}\n\nfunction appendArchedFrameHead(\n parts: BoxGeometry[],\n metrics: ArchedOpeningMetrics,\n barT: number,\n barD: number,\n): void {\n const { hw, rectTopY, archCy, archRadius: radius } = metrics;\n const angleLeft = Math.atan2(rectTopY - archCy, -hw);\n const angleRight = Math.atan2(rectTopY - archCy, hw);\n const sweep = angleRight - angleLeft;\n const segments = Math.max(12, Math.ceil((Math.abs(sweep) * radius) / (barT * 1.8)));\n\n for (let i = 0; i < segments; i++) {\n const t0 = i / segments;\n const t1 = (i + 1) / segments;\n const a0 = angleLeft + sweep * t0;\n const a1 = angleLeft + sweep * t1;\n const mid = (a0 + a1) / 2;\n const chord = 2 * radius * Math.sin((a1 - a0) / 2);\n const geo = new BoxGeometry(chord, barT, barD);\n geo.rotateZ(mid - Math.PI / 2);\n geo.translate(radius * Math.cos(mid), archCy + radius * Math.sin(mid), 0);\n parts.push(geo);\n }\n}\n\n/**\n * Diagonal cames only, each segment analytically clipped to the rect-plus-arch\n * opening — no outer frame, no stencil. Bar ends land as real vertices on the\n * arc, so the merged geometry casts a correct shadow and matches any collider.\n */\nexport function buildArchedDiamondLatticeCameParts({\n width,\n rectHeight,\n archHeight,\n centerY = 0,\n grid,\n leadThickness: barT,\n leadDepth: barD,\n clipInset = 0,\n}: ArchedDiamondLatticePartOptions): BoxGeometry[] {\n const bounds: ArchedOpeningBounds = { width, rectHeight, archHeight, centerY };\n const metrics = archedOpeningMetrics(bounds);\n // Positioning (grid phase, line count) follows the full opening so diamonds\n // stay registered; only the clip boundary shrinks so ends land under the frame.\n const clipBounds =\n clipInset > 0 ? boundsFromMetrics(insetArchedOpeningMetrics(metrics, clipInset)) : bounds;\n const parts: BoxGeometry[] = [];\n\n const phaseShiftY = diamondLatticeSpringPhaseShift(metrics.ymin, metrics.rectTopY, grid);\n addArchedDiagonalFamily(parts, clipBounds, metrics, grid, phaseShiftY, barT, barD, grid.angle);\n addArchedDiagonalFamily(parts, clipBounds, metrics, grid, phaseShiftY, barT, barD, -grid.angle);\n return parts;\n}\n\n/** Outer frame (rect sides + circular arch head) and clipped diagonal cames. */\nexport function buildArchedDiamondLatticeParts(\n options: ArchedDiamondLatticePartOptions,\n): BoxGeometry[] {\n const { width, rectHeight, archHeight, centerY = 0, leadThickness: barT, leadDepth: barD } = options;\n const bounds: ArchedOpeningBounds = { width, rectHeight, archHeight, centerY };\n const metrics = archedOpeningMetrics(bounds);\n const { hw, ymin, rectTopY } = metrics;\n const rectSectionHeight = rectTopY - ymin;\n\n const parts: BoxGeometry[] = [\n new BoxGeometry(width + barT, barT, barD).translate(0, ymin, 0),\n new BoxGeometry(barT, rectSectionHeight + barT, barD).translate(-hw, ymin + rectSectionHeight / 2, 0),\n new BoxGeometry(barT, rectSectionHeight + barT, barD).translate(hw, ymin + rectSectionHeight / 2, 0),\n ];\n appendArchedFrameHead(parts, metrics, barT, barD);\n parts.push(...buildArchedDiamondLatticeCameParts(options));\n return parts;\n}\n\nfunction addArchedDiagonalFamily(\n parts: BoxGeometry[],\n bounds: ArchedOpeningBounds,\n metrics: ArchedOpeningMetrics,\n grid: DiamondLatticeGrid,\n phaseShiftY: number,\n barT: number,\n barD: number,\n angle: number,\n): void {\n const { totalHeight, centerY } = metrics;\n const spacing = grid.spacing;\n const len = Math.hypot(bounds.width, totalHeight) + barT;\n const perpX = -Math.sin(angle);\n const perpY = Math.cos(angle);\n const count = Math.ceil(Math.hypot(bounds.width, totalHeight) / spacing) + 2;\n const gridCenterY = centerY + phaseShiftY;\n\n for (let i = -count; i <= count; i++) {\n const cx = perpX * i * spacing;\n const cy = gridCenterY + perpY * i * spacing;\n const dx = Math.cos(angle) * len * 0.5;\n const dy = Math.sin(angle) * len * 0.5;\n const clipped = clipSegmentToArchedOpening(\n cx - dx,\n cy - dy,\n cx + dx,\n cy + dy,\n bounds,\n );\n if (!clipped) continue;\n\n const [x1, y1, x2, y2] = clipped;\n const clippedLen = Math.hypot(x2 - x1, y2 - y1);\n if (clippedLen < 1e-6) continue;\n\n const geo = new BoxGeometry(clippedLen, barT, barD);\n geo.rotateZ(angle);\n geo.translate((x1 + x2) / 2, (y1 + y2) / 2, 0);\n parts.push(geo);\n }\n}\n","import { BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport {\n archedOpeningMetrics,\n buildArchedDiamondLatticeCameParts,\n diamondLatticeGridFromCells,\n type ArchedOpeningMetrics,\n type DiamondLatticeGrid,\n} from \"./diamondLattice\";\n\nexport interface ArchedDiamondLatticeWindowGeometryOptions {\n /** Opening width (world units). */\n width?: number;\n /** Height of the straight-sided lower section. */\n rectHeight?: number;\n /** Arch rise from the spring line to the apex. Defaults to `width / 2`. */\n archHeight?: number;\n /** Lead came thickness (cross-section). Defaults to `0.055`. */\n leadThickness?: number;\n /** Lead depth (Z extent). Defaults to `0.11`. */\n leadDepth?: number;\n /** Quarrels spanning east–west across the bounding opening. Defaults to `10`. */\n cellsX?: number;\n /** Quarrels spanning north–south across the bounding opening. Defaults to `12`. */\n cellsY?: number;\n /** Vertical center of the full opening. Defaults to `0`. */\n centerY?: number;\n}\n\n/**\n * Diamond cames analytically clipped to the arched (rect-plus-Tudor-head)\n * opening — real trimmed geometry, no stencil, so it shadows and raycasts\n * correctly. Frame is a separate extruded ring on {@link ArchedDiamondLatticeWindow}.\n */\nexport class ArchedDiamondLatticeWindowGeometry extends BufferGeometry {\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n readonly opening: ArchedOpeningMetrics;\n\n constructor({\n width = 4.5,\n rectHeight = 4,\n archHeight,\n leadThickness = 0.055,\n leadDepth = 0.11,\n cellsX = 10,\n cellsY = 12,\n centerY = 0,\n }: ArchedDiamondLatticeWindowGeometryOptions = {}) {\n super();\n\n this.cellsX = Math.max(1, Math.round(cellsX));\n this.cellsY = Math.max(1, Math.round(cellsY));\n this.opening = archedOpeningMetrics({ width, rectHeight, archHeight, centerY });\n this.fittedGrid = diamondLatticeGridFromCells(\n width,\n this.opening.totalHeight,\n this.cellsX,\n this.cellsY,\n );\n\n const parts = buildArchedDiamondLatticeCameParts({\n width,\n rectHeight,\n archHeight,\n centerY,\n grid: this.fittedGrid,\n leadThickness,\n leadDepth,\n // Frame ring occupies `leadThickness` around the perimeter. End the cames\n // half a ring-width in so their tips overlap under the frame (no gap at the\n // crown) while their end-caps stay inside the outer silhouette (no spikes).\n clipInset: leadThickness * 0.5,\n });\n\n const merged = mergeGeometries(parts);\n if (!merged) throw new Error(\"ArchedDiamondLatticeWindowGeometry: merge failed\");\n\n this.copy(merged);\n merged.dispose();\n for (const part of parts) part.dispose();\n }\n}","import { BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport {\n buildDiamondLatticeParts,\n diamondLatticeGridFromCells,\n type DiamondLatticeGrid,\n} from \"./diamondLattice\";\n\nexport interface DiamondLatticeWindowGeometryOptions {\n /** Opening width (world units). */\n width?: number;\n /** Opening height (world units). */\n height?: number;\n /** Lead came thickness (cross-section). Defaults to `0.055`. */\n leadThickness?: number;\n /** Lead depth (Z extent). Defaults to `0.11`. */\n leadDepth?: number;\n /** Quarrels spanning east–west across the opening. Defaults to `10`. */\n cellsX?: number;\n /** Quarrels spanning north–south across the opening. Defaults to `10`. */\n cellsY?: number;\n /** Vertical center of the opening in local geometry space. Defaults to `0`. */\n centerY?: number;\n}\n\n/**\n * Diamond lattice window — outer frame plus diagonal cames.\n * Quarrel tips align to the vertical and horizontal axes (`<>`).\n * Built in the XY plane facing +Z.\n *\n * Glass is a separate pane on {@link DiamondLatticeWindow} — this geometry is\n * lead and frame only (casts shadow; glass typically does not).\n */\nexport class DiamondLatticeWindowGeometry extends BufferGeometry {\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n\n constructor({\n width = 4.5,\n height = 5.5,\n leadThickness = 0.055,\n leadDepth = 0.11,\n cellsX = 10,\n cellsY = 10,\n centerY = 0,\n }: DiamondLatticeWindowGeometryOptions = {}) {\n super();\n\n this.cellsX = Math.max(1, Math.round(cellsX));\n this.cellsY = Math.max(1, Math.round(cellsY));\n this.fittedGrid = diamondLatticeGridFromCells(width, height, this.cellsX, this.cellsY);\n\n const parts = buildDiamondLatticeParts({\n width,\n height,\n centerY,\n grid: this.fittedGrid,\n leadThickness,\n leadDepth,\n });\n\n const merged = mergeGeometries(parts);\n if (!merged) throw new Error(\"DiamondLatticeWindowGeometry: merge failed\");\n\n this.copy(merged);\n merged.dispose();\n for (const part of parts) part.dispose();\n }\n}","import { BoxGeometry } from \"three\";\n\n/** Pane dimensions derived from opening size and cell counts. */\nexport interface GregorianLatticeGrid {\n /** Width of each rectangular pane. */\n paneWidth: number;\n /** Height of each rectangular pane. */\n paneHeight: number;\n}\n\n/**\n * Derive pane size from cell counts.\n *\n * `cellsX` panes span the opening width; `cellsY` span the height. Mullions\n * divide the opening evenly so every segment is a full rectangle.\n */\nexport function gregorianLatticeGridFromCells(\n width: number,\n height: number,\n cellsX: number,\n cellsY: number,\n): GregorianLatticeGrid {\n const cx = Math.max(1, Math.round(cellsX));\n const cy = Math.max(1, Math.round(cellsY));\n return {\n paneWidth: width / cx,\n paneHeight: height / cy,\n };\n}\n\nexport interface GregorianLatticePartOptions {\n width: number;\n height: number;\n /** Center Y of the opening in local space. Defaults to `0`. */\n centerY?: number;\n cellsX: number;\n cellsY: number;\n mullionThickness: number;\n mullionDepth: number;\n}\n\n/**\n * Build merged box geometries for the outer frame and interior mullions.\n * Orthogonal grid — no clipping required; counts guarantee full panes.\n */\nexport function buildGregorianLatticeParts({\n width,\n height,\n centerY = 0,\n cellsX,\n cellsY,\n mullionThickness: barT,\n mullionDepth: barD,\n}: GregorianLatticePartOptions): BoxGeometry[] {\n const hw = width / 2;\n const hh = height / 2;\n const parts: BoxGeometry[] = [\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY - hh, 0),\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY + hh, 0),\n new BoxGeometry(barT, height + barT, barD).translate(-hw, centerY, 0),\n new BoxGeometry(barT, height + barT, barD).translate(hw, centerY, 0),\n ];\n\n const { paneWidth, paneHeight } = gregorianLatticeGridFromCells(width, height, cellsX, cellsY);\n\n for (let col = 1; col < cellsX; col++) {\n const x = -hw + paneWidth * col;\n parts.push(new BoxGeometry(barT, height + barT, barD).translate(x, centerY, 0));\n }\n\n for (let row = 1; row < cellsY; row++) {\n const y = centerY - hh + paneHeight * row;\n parts.push(new BoxGeometry(width + barT, barT, barD).translate(0, y, 0));\n }\n\n return parts;\n}","import { BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport {\n buildGregorianLatticeParts,\n gregorianLatticeGridFromCells,\n type GregorianLatticeGrid,\n} from \"./gregorianLattice\";\n\nexport interface GregorianLatticeWindowGeometryOptions {\n /** Opening width (world units). */\n width?: number;\n /** Opening height (world units). */\n height?: number;\n /** Mullion thickness (cross-section). Defaults to `0.055`. */\n mullionThickness?: number;\n /** Mullion depth (Z extent). Defaults to `0.11`. */\n mullionDepth?: number;\n /** Rectangular panes across the opening width. Defaults to `4`. */\n cellsX?: number;\n /** Rectangular panes up the opening height. Defaults to `6`. */\n cellsY?: number;\n /** Vertical center of the opening in local geometry space. Defaults to `0`. */\n centerY?: number;\n}\n\n/**\n * Gregorian lattice window — outer frame plus orthogonal mullions in a rectangular grid.\n * Built in the XY plane facing +Z.\n */\nexport class GregorianLatticeWindowGeometry extends BufferGeometry {\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: GregorianLatticeGrid;\n\n constructor({\n width = 4.5,\n height = 5.5,\n mullionThickness = 0.055,\n mullionDepth = 0.11,\n cellsX = 4,\n cellsY = 6,\n centerY = 0,\n }: GregorianLatticeWindowGeometryOptions = {}) {\n super();\n\n this.cellsX = Math.max(1, Math.round(cellsX));\n this.cellsY = Math.max(1, Math.round(cellsY));\n this.fittedGrid = gregorianLatticeGridFromCells(width, height, this.cellsX, this.cellsY);\n\n const parts = buildGregorianLatticeParts({\n width,\n height,\n centerY,\n cellsX: this.cellsX,\n cellsY: this.cellsY,\n mullionThickness,\n mullionDepth,\n });\n\n const merged = mergeGeometries(parts);\n if (!merged) throw new Error(\"GregorianLatticeWindowGeometry: merge failed\");\n\n this.copy(merged);\n merged.dispose();\n for (const part of parts) part.dispose();\n }\n}","import {\n BoxGeometry,\n ExtrudeGeometry,\n Path,\n Plane,\n Shape,\n Vector3,\n} from \"three\";\n\n/** Ring-spacing factor — overlap tightens as this approaches 1. */\nexport const RING_LATTICE_SPACING_FACTOR = 0.96;\n\n/**\n * Four clipping planes for a rectangular opening (shadow + mesh clip).\n * Fragments are discarded when `dot(normal, position) > constant`.\n */\nexport function createOpeningClippingPlanes(width: number, height: number, centerY = 0): Plane[] {\n const hw = width / 2;\n const hh = height / 2;\n return [\n new Plane(new Vector3(1, 0, 0), hw),\n new Plane(new Vector3(-1, 0, 0), hw),\n new Plane(new Vector3(0, 1, 0), centerY + hh),\n new Plane(new Vector3(0, -1, 0), -centerY + hh),\n ];\n}\n\nexport interface RingLatticeGrid {\n /** Requested ring-center spacing before the overlap factor. */\n cell: number;\n /** Effective center spacing (`cell × 0.96`). */\n latticeCell: number;\n /** Outer half-extent of each square ring profile. */\n ringOuter: number;\n /** Ring instance count. */\n count: number;\n}\n\nexport interface RingLatticeSpotOptions {\n width: number;\n height: number;\n centerY?: number;\n cell: number;\n}\n\n/** Resolve uniform ring spacing — `cell` wins over the `cellsX` density hint. */\nexport function resolveRingLatticeCell(\n width: number,\n _height: number,\n cell?: number,\n cellsX?: number,\n): number {\n if (cell !== undefined) return cell;\n if (cellsX !== undefined) return width / Math.max(1, Math.round(cellsX));\n return 0.55;\n}\n\n/** Ring-center positions overscanning the opening (stencil trims the excess). */\nexport function ringLatticeSpots({\n width,\n height,\n centerY = 0,\n cell,\n}: RingLatticeSpotOptions): { spots: [number, number][]; grid: RingLatticeGrid } {\n const latticeCell = cell * RING_LATTICE_SPACING_FACTOR;\n const pad = latticeCell * 0.6;\n const hh = height / 2;\n const hw = width / 2 + pad;\n\n const xCount = Math.ceil((2 * hw) / latticeCell) + 1;\n const xSpan = (xCount - 1) * latticeCell;\n const xs = Array.from({ length: xCount }, (_, i) => -xSpan / 2 + i * latticeCell);\n\n const spots: [number, number][] = [];\n const y0 = centerY - hh + latticeCell * 0.5 - pad;\n const y1 = centerY + hh - latticeCell * 0.5 + pad;\n for (let y = y0; y <= y1 + 1e-9; y += latticeCell) {\n for (const x of xs) spots.push([x, y]);\n }\n\n return {\n spots,\n grid: {\n cell,\n latticeCell,\n ringOuter: latticeCell * 0.5,\n count: spots.length,\n },\n };\n}\n\n/** Hollow square profile extruded for one lattice ring (local XY, facing +Z). */\nexport function createRingLatticeGeometry(outer: number, wall: number, depth: number): ExtrudeGeometry {\n const inner = Math.max(outer - wall, outer * 0.5);\n const ring = new Shape();\n ring.moveTo(-outer, -outer);\n ring.lineTo(outer, -outer);\n ring.lineTo(outer, outer);\n ring.lineTo(-outer, outer);\n ring.closePath();\n\n const hole = new Path();\n hole.moveTo(-inner, -inner);\n hole.lineTo(-inner, inner);\n hole.lineTo(inner, inner);\n hole.lineTo(inner, -inner);\n hole.closePath();\n ring.holes.push(hole);\n\n return new ExtrudeGeometry(ring, { depth, bevelEnabled: false });\n}\n\nexport interface RingLatticeFramePartOptions {\n width: number;\n height: number;\n centerY?: number;\n frameThickness: number;\n frameDepth: number;\n}\n\n/** Outer frame bars — shared topology across lattice window openings. */\nexport function buildRingLatticeFrameParts({\n width,\n height,\n centerY = 0,\n frameThickness: barT,\n frameDepth: barD,\n}: RingLatticeFramePartOptions): BoxGeometry[] {\n const hw = width / 2;\n const hh = height / 2;\n return [\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY - hh, 0),\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY + hh, 0),\n new BoxGeometry(barT, height + barT, barD).translate(-hw, centerY, 0),\n new BoxGeometry(barT, height + barT, barD).translate(hw, centerY, 0),\n ];\n}","export type StairVec3 = [number, number, number];\nexport type StairVec2 = [number, number];\n\n/**\n * Append one quad (two triangles). Corners must be CCW when viewed along `normal`.\n */\nexport function pushQuad(\n positions: number[],\n normals: number[],\n uvs: number[],\n indices: number[],\n corners: [StairVec3, StairVec3, StairVec3, StairVec3],\n normal: StairVec3,\n cornerUvs: [StairVec2, StairVec2, StairVec2, StairVec2],\n): void {\n const base = positions.length / 3;\n for (const [x, y, z] of corners) {\n positions.push(x, y, z);\n normals.push(...normal);\n }\n for (const [u, v] of cornerUvs) uvs.push(u, v);\n indices.push(base, base + 1, base + 2, base, base + 2, base + 3);\n}\n\nexport const UNIT_QUAD_UV: [StairVec2, StairVec2, StairVec2, StairVec2] = [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n];\n\n/** Riser facing +Z at `zFront`. */\nexport function pushRiserZ(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n hw: number,\n yBottom: number,\n yTop: number,\n zFront: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [-hw, yBottom, zFront],\n [-hw, yTop, zFront],\n [hw, yTop, zFront],\n [hw, yBottom, zFront],\n ],\n [0, 0, 1],\n [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n ],\n );\n}\n\n/** Tread facing +Y between `zFront` and `zBack`. */\nexport function pushTreadZ(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n hw: number,\n yTop: number,\n zFront: number,\n zBack: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [-hw, yTop, zFront],\n [-hw, yTop, zBack],\n [hw, yTop, zBack],\n [hw, yTop, zFront],\n ],\n [0, 1, 0],\n UNIT_QUAD_UV,\n );\n}\n\n/** Riser facing +X at `xFront` (second flight climbing −X). */\nexport function pushRiserX(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n yBottom: number,\n yTop: number,\n xFront: number,\n zNear: number,\n zFar: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xFront, yBottom, zFar],\n [xFront, yBottom, zNear],\n [xFront, yTop, zNear],\n [xFront, yTop, zFar],\n ],\n [1, 0, 0],\n [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n ],\n );\n}\n\n/** Tread facing +Y between `xFront` and `xBack` (second flight climbing −X). */\nexport function pushTreadX(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n yTop: number,\n xFront: number,\n xBack: number,\n zNear: number,\n zFar: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xFront, yTop, zNear],\n [xFront, yTop, zFar],\n [xBack, yTop, zFar],\n [xBack, yTop, zNear],\n ],\n [0, 1, 0],\n UNIT_QUAD_UV,\n );\n}\n\n/** Point on the XZ circle at `angle` (radians, +Y up, 0 = +X, CCW = +Z). */\nexport function polarXZ(radius: number, angle: number): [number, number] {\n return [radius * Math.cos(angle), radius * Math.sin(angle)];\n}\n\n/** Tangent on the XZ circle at `angle`, CCW when viewed from +Y. */\nexport function tangentXZ(angle: number): [number, number, number] {\n return [-Math.sin(angle), 0, Math.cos(angle)];\n}\n\n/**\n * Spiral riser — vertical quad along one radial line at `angle`.\n * Normal faces the CCW climb direction (turret stair ascending counter-clockwise).\n */\nexport function pushSpiralRiser(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n innerRadius: number,\n outerRadius: number,\n yBottom: number,\n yTop: number,\n angle: number,\n): void {\n const [xi, zi] = polarXZ(innerRadius, angle);\n const [xo, zo] = polarXZ(outerRadius, angle);\n const normal = tangentXZ(angle);\n\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xi, yBottom, zi],\n [xi, yTop, zi],\n [xo, yTop, zo],\n [xo, yBottom, zo],\n ],\n normal,\n [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n ],\n );\n}\n\n/**\n * Spiral tread — horizontal trapezoid between inner/outer radii from `angleStart`\n * to `angleEnd` (exclusive overlap with the next step when angles are contiguous).\n */\nexport function pushSpiralTread(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n innerRadius: number,\n outerRadius: number,\n yTop: number,\n angleStart: number,\n angleEnd: number,\n): void {\n const [xIf, zIf] = polarXZ(innerRadius, angleStart);\n const [xIb, zIb] = polarXZ(innerRadius, angleEnd);\n const [xOb, zOb] = polarXZ(outerRadius, angleEnd);\n const [xOf, zOf] = polarXZ(outerRadius, angleStart);\n\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xIf, yTop, zIf],\n [xIb, yTop, zIb],\n [xOb, yTop, zOb],\n [xOf, yTop, zOf],\n ],\n [0, 1, 0],\n [\n [0, 0],\n [1, 0],\n [1, 1],\n [0, 1],\n ],\n );\n}\n\n/** Landing platform facing +Y. */\nexport function pushLanding(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n hw: number,\n y: number,\n zNear: number,\n zFar: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [-hw, y, zNear],\n [-hw, y, zFar],\n [hw, y, zFar],\n [hw, y, zNear],\n ],\n [0, 1, 0],\n UNIT_QUAD_UV,\n );\n}","import { BufferAttribute, BufferGeometry } from \"three\";\nimport {\n pushLanding,\n pushRiserX,\n pushRiserZ,\n pushTreadX,\n pushTreadZ,\n} from \"./staircaseQuad\";\n\nexport interface LShapedStaircaseGeometryOptions {\n /** Stair width (tread left–right extent). Defaults to `2`. */\n width?: number;\n /** Vertical rise per step (riser). Defaults to `0.3`. */\n riserHeight?: number;\n /** Horizontal run per step (tread depth). Defaults to `0.5`. */\n treadDepth?: number;\n /** Steps in each flight (before and after the landing). Defaults to `5`. */\n stepsPerFlight?: number;\n}\n\n/**\n * L-shaped staircase with a square landing (width × width) at the 90° turn.\n *\n * Local frame:\n * - First flight climbs +Z, centered on X = 0.\n * - Landing is a width² platform starting at the last tread (no cantilever over\n * the lower flight) and extending forward at the turn.\n * - Second flight climbs −X from the left edge of the landing.\n */\nexport class LShapedStaircaseGeometry extends BufferGeometry {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepsPerFlight: number;\n readonly landingSize: number;\n readonly flightRun: number;\n readonly totalHeight: number;\n\n constructor({\n width = 2,\n riserHeight = 0.3,\n treadDepth = 0.5,\n stepsPerFlight = 5,\n }: LShapedStaircaseGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.riserHeight = riserHeight;\n this.treadDepth = treadDepth;\n this.stepsPerFlight = Math.max(1, Math.round(stepsPerFlight));\n this.landingSize = width;\n this.flightRun = this.stepsPerFlight * this.treadDepth;\n this.totalHeight = this.stepsPerFlight * 2 * this.riserHeight;\n\n const hw = width / 2;\n const positions: number[] = [];\n const normals: number[] = [];\n const uvs: number[] = [];\n const indices: number[] = [];\n const buffers = { positions, normals, uvs, indices };\n\n for (let i = 0; i < this.stepsPerFlight; i++) {\n const yBottom = i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n const zFront = i * this.treadDepth;\n const zBack = zFront + this.treadDepth;\n\n pushRiserZ(buffers, hw, yBottom, yTop, zFront);\n pushTreadZ(buffers, hw, yTop, zFront, zBack);\n }\n\n const landingY = this.stepsPerFlight * this.riserHeight;\n // Begin at the front of the last tread — avoids a shelf over the lower flight.\n const landingZNear = (this.stepsPerFlight - 1) * this.treadDepth;\n const landingZFar = landingZNear + this.landingSize;\n\n pushLanding(buffers, hw, landingY, landingZNear, landingZFar);\n\n const leftEdgeX = -hw;\n for (let i = 0; i < this.stepsPerFlight; i++) {\n const yBottom = landingY + i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n const xFront = leftEdgeX - i * this.treadDepth;\n const xBack = xFront - this.treadDepth;\n\n pushRiserX(buffers, yBottom, yTop, xFront, landingZNear, landingZFar);\n pushTreadX(buffers, yTop, xFront, xBack, landingZNear, landingZFar);\n }\n\n this.setIndex(indices);\n this.setAttribute(\"position\", new BufferAttribute(new Float32Array(positions), 3));\n this.setAttribute(\"normal\", new BufferAttribute(new Float32Array(normals), 3));\n this.setAttribute(\"uv\", new BufferAttribute(new Float32Array(uvs), 2));\n this.computeBoundingSphere();\n }\n}","import { BufferAttribute, BufferGeometry } from \"three\";\nimport { pushSpiralRiser, pushSpiralTread } from \"./staircaseQuad\";\n\nexport interface SpiralStaircaseGeometryOptions {\n /** Newel / center-hole radius (inner edge of every tread). Defaults to `0.45`. */\n innerRadius?: number;\n /** Radial tread width (outer − inner radius). Defaults to `1.95`. */\n width?: number;\n /** Arc run per step at the walking line (mid-radius). Defaults to `0.45`. */\n treadDepth?: number;\n /** Vertical rise per step (riser). Defaults to `0.2`. */\n riserHeight?: number;\n /** Number of steps. Defaults to `20`. */\n stepCount?: number;\n /** Spiral start angle in radians (+X = 0, CCW). Defaults to `0`. */\n startAngle?: number;\n /** Override step angle (radians). When omitted, derived from `treadDepth`. */\n stepAngle?: number;\n}\n\n/**\n * Turret-style spiral staircase — trapezoidal treads between an inner newel radius\n * and an outer wall radius, ascending counter-clockwise when viewed from above.\n *\n * Each step is a four-sided tread (no pinched center point). Step angle is\n * derived from tread depth at the mid-radius so treads meet without overlapping.\n */\nexport class SpiralStaircaseGeometry extends BufferGeometry {\n readonly innerRadius: number;\n readonly width: number;\n readonly outerRadius: number;\n readonly treadDepth: number;\n readonly riserHeight: number;\n readonly stepCount: number;\n readonly startAngle: number;\n readonly stepAngle: number;\n readonly totalHeight: number;\n readonly totalTurn: number;\n\n constructor({\n innerRadius = 0.45,\n width = 1.95,\n treadDepth = 0.45,\n riserHeight = 0.2,\n stepCount = 20,\n startAngle = 0,\n stepAngle: stepAngleOption,\n }: SpiralStaircaseGeometryOptions = {}) {\n super();\n\n this.innerRadius = Math.max(0.01, innerRadius);\n this.width = Math.max(0.05, width);\n this.outerRadius = this.innerRadius + this.width;\n this.treadDepth = treadDepth;\n this.riserHeight = riserHeight;\n this.stepCount = Math.max(1, Math.round(stepCount));\n this.startAngle = startAngle;\n\n const walkRadius = (this.innerRadius + this.outerRadius) * 0.5;\n this.stepAngle =\n stepAngleOption ?? Math.max(treadDepth / walkRadius, Math.PI / 180);\n this.totalHeight = this.stepCount * this.riserHeight;\n this.totalTurn = this.stepCount * this.stepAngle;\n\n const positions: number[] = [];\n const normals: number[] = [];\n const uvs: number[] = [];\n const indices: number[] = [];\n const buffers = { positions, normals, uvs, indices };\n\n for (let i = 0; i < this.stepCount; i++) {\n const angleStart = this.startAngle + i * this.stepAngle;\n const angleEnd = angleStart + this.stepAngle;\n const yBottom = i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n\n pushSpiralRiser(buffers, this.innerRadius, this.outerRadius, yBottom, yTop, angleStart);\n pushSpiralTread(buffers, this.innerRadius, this.outerRadius, yTop, angleStart, angleEnd);\n }\n\n this.setIndex(indices);\n this.setAttribute(\"position\", new BufferAttribute(new Float32Array(positions), 3));\n this.setAttribute(\"normal\", new BufferAttribute(new Float32Array(normals), 3));\n this.setAttribute(\"uv\", new BufferAttribute(new Float32Array(uvs), 2));\n this.computeBoundingSphere();\n }\n}","import { BufferAttribute, BufferGeometry } from \"three\";\nimport { pushRiserZ, pushTreadZ } from \"./staircaseQuad\";\n\nexport interface StaircaseGeometryOptions {\n /** Stair width (tread left–right extent). Defaults to `2`. */\n width?: number;\n /** Vertical rise per step (riser). Defaults to `0.3`. */\n riserHeight?: number;\n /** Horizontal run per step (tread depth). Defaults to `0.5`. */\n treadDepth?: number;\n /** Number of steps. Defaults to `10`. */\n stepCount?: number;\n}\n\n/**\n * Straight run staircase — open risers and treads (no side stringers yet).\n *\n * Local frame: centered on width, rises along +Y, runs along +Z. Each step\n * emits a front riser (+Z) and a top tread (+Y). UVs are normalized per face\n * (0–1) so materials can tile per step.\n */\nexport class StaircaseGeometry extends BufferGeometry {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepCount: number;\n readonly totalHeight: number;\n readonly totalDepth: number;\n\n constructor({\n width = 2,\n riserHeight = 0.3,\n treadDepth = 0.5,\n stepCount = 10,\n }: StaircaseGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.riserHeight = riserHeight;\n this.treadDepth = treadDepth;\n this.stepCount = Math.max(1, Math.round(stepCount));\n this.totalHeight = this.stepCount * this.riserHeight;\n this.totalDepth = this.stepCount * this.treadDepth;\n\n const hw = width / 2;\n const positions: number[] = [];\n const normals: number[] = [];\n const uvs: number[] = [];\n const indices: number[] = [];\n const buffers = { positions, normals, uvs, indices };\n\n for (let i = 0; i < this.stepCount; i++) {\n const yBottom = i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n const zFront = i * this.treadDepth;\n const zBack = zFront + this.treadDepth;\n\n pushRiserZ(buffers, hw, yBottom, yTop, zFront);\n pushTreadZ(buffers, hw, yTop, zFront, zBack);\n }\n\n this.setIndex(indices);\n this.setAttribute(\"position\", new BufferAttribute(new Float32Array(positions), 3));\n this.setAttribute(\"normal\", new BufferAttribute(new Float32Array(normals), 3));\n this.setAttribute(\"uv\", new BufferAttribute(new Float32Array(uvs), 2));\n this.computeBoundingSphere();\n }\n}","import { BufferGeometry, CylinderGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Group indices\n * 0. Jar\n * 1. Cork\n */\nexport class JarGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Jar\n const points = [\n new Vector2(0, 0), // Bottom of the jar\n new Vector2(1.2, 0), // Base\n new Vector2(1.5, 1.5), // Mid-body\n new Vector2(1, 3), // Narrow neck\n new Vector2(0.6, 3.5), // Mouth of the jar\n new Vector2(0.5, 3.5), // Cork\n ];\n\n const bodyGeometry = new LatheGeometry(points, 10);\n\n // Cork\n const corkGeometry = new CylinderGeometry(0.6, 0.5, 0.3, 10);\n corkGeometry.translate(0, 3.5, 0);\n\n this.copy(mergeGeometries([bodyGeometry, corkGeometry], true) as BufferGeometry);\n }\n}\n","/**\n * Calculate the x-coordinate for a given y-coordinate using the slope-intercept equation of a line.\n * x = x1 + (y - y1) / m\n *\n * Example usage\n * ```\n * const x1 = 0.8, y1 = 0, x2 = 1, y2 = 1.5, y = 1.0;\n * const x = calculateXForY(x1, y1, x2, y2, y);\n * console.log(`The x-position for y=${y} is x=${x.toFixed(4)}`);\n * ```\n */\nexport function calculateXFromSlopeIntercept(x1: number, y1: number, x2: number, y2: number, y: number): number {\n const m = (y2 - y1) / (x2 - x1); // slope\n return x1 + (y - y1) / m;\n}\n\n/**\n * Calculate the y-coordinate for a given x-coordinate using the slope-intercept equation of a line.\n * y = y1 + m * (x - x1)\n *\n * Example usage\n * ```\n * const x1 = 0.8, y1 = 0, x2 = 1, y2 = 1.5, x = 0.9333;\n * const y = calculateYForX(x1, y1, x2, y2, x);\n * console.log(`The y-position for x=${x} is y=${y.toFixed(4)}`);\n * ```\n */\nexport function calculateYFromSlopeIntercept(x1: number, y1: number, x2: number, y2: number, x: number): number {\n const m = (y2 - y1) / (x2 - x1); // slope\n return y1 + m * (x - x1);\n}\n\nexport const LineEquations = {\n calculateXFromSlopeIntercept,\n calculateYFromSlopeIntercept,\n};\n","import { BufferGeometry, CylinderGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { calculateXFromSlopeIntercept } from \"../../utils/LineEquations\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Potion bottle geometry\n *\n * Group indices\n * 0. Bottle\n * 1. Cork\n * 2. Liquid (optional)\n */\nexport class PotionBottleGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Bottle\n const points = [\n new Vector2(0, 0), // Origin\n new Vector2(0.8, 0), // Base\n new Vector2(1, 1.5), // Rounded body\n new Vector2(0.5, 2.2), // Neck\n new Vector2(0.6, 2.5), // Mouth\n new Vector2(0.5, 2.5), // Cork\n ];\n\n const bottleGeometry = new LatheGeometry(points, 10);\n\n // Cork\n const corkGeometry = new CylinderGeometry(0.55, 0.45, 0.2, 10);\n corkGeometry.translate(0, 2.5, 0);\n\n // Liquid (optional)\n const liquidPoints = [\n new Vector2(0, 0),\n new Vector2(0.8, 0),\n new Vector2(calculateXFromSlopeIntercept(0.8, 0, 1, 1.5, 1.0), 1.0),\n new Vector2(0, 1.0),\n ];\n\n const liquidGeometry = new LatheGeometry(liquidPoints, 10);\n liquidGeometry.translate(0, 0.1, 0);\n liquidGeometry.scale(0.9, 0.9, 0.9);\n\n this.copy(mergeGeometries([bottleGeometry, corkGeometry, liquidGeometry], true) as BufferGeometry);\n }\n}\n","import { BufferGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface WineBottleGeometryOptions {\n /** Body radius. Defaults to `0.5`. */\n radius?: number;\n /** Neck radius. Defaults to `0.2`. */\n neckRadius?: number;\n /** Total height including neck. Defaults to `3`. */\n height?: number;\n /** Neck height. Defaults to `1`. */\n neckHeight?: number;\n /** Circumference segments. Defaults to `16`. */\n segments?: number;\n}\n\n/**\n * Wine bottle — cylindrical body, shoulder taper, and neck.\n *\n * Local frame: base at Y=0.\n */\nexport class WineBottleGeometry extends BufferGeometry {\n readonly radius: number;\n readonly height: number;\n\n constructor({\n radius = 0.5,\n neckRadius = 0.2,\n height = 3,\n neckHeight = 1,\n segments = 16,\n }: WineBottleGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.height = height;\n\n const bodyHeight = height - neckHeight;\n const bodyGeometry = new CylinderGeometry(radius, radius, bodyHeight, segments);\n bodyGeometry.translate(0, bodyHeight / 2, 0);\n\n const shoulderHeight = 0.3;\n const shoulderGeometry = new CylinderGeometry(neckRadius, radius, shoulderHeight, segments);\n shoulderGeometry.translate(0, bodyHeight + shoulderHeight / 2, 0);\n\n const neckGeometry = new CylinderGeometry(neckRadius, neckRadius, neckHeight, segments);\n neckGeometry.translate(0, bodyHeight + shoulderHeight + neckHeight / 2, 0);\n\n this.copy(mergeGeometries([bodyGeometry, shoulderGeometry, neckGeometry], false) as BufferGeometry);\n }\n}","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface CrossHeadstoneGeometryOptions {\n /** Overall cross width (arm span). Defaults to `0.4`. */\n width?: number;\n /** Total height. Defaults to `1.2`. */\n height?: number;\n /** Slab depth. Defaults to `0.2`. */\n depth?: number;\n}\n\n/**\n * Cross headstone — vertical shaft and horizontal arm.\n *\n * Local frame: base on Y=0, centered on X/Z.\n */\nexport class CrossHeadstoneGeometry extends BufferGeometry {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n\n constructor({ width = 0.4, height = 1.2, depth = 0.2 }: CrossHeadstoneGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n\n const verticalHeight = height * 0.6;\n const verticalGeometry = new BoxGeometry(width / 2, verticalHeight, depth);\n verticalGeometry.translate(0, verticalHeight / 2, 0);\n\n const horizontalWidth = width * 1.5;\n const horizontalGeometry = new BoxGeometry(horizontalWidth, width / 4, depth);\n horizontalGeometry.translate(0, verticalHeight * 0.75, 0);\n\n this.copy(mergeGeometries([verticalGeometry, horizontalGeometry], false) as BufferGeometry);\n this.computeVertexNormals();\n }\n}","import { BoxGeometry, BufferGeometry, ConeGeometry, CylinderGeometry, ExtrudeGeometry, Shape } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Mausoleum Geometry\n *\n * Group indices:\n * 0. Base\n * 1. Building\n * 2. Roof\n * 3. Arched entrance\n */\nexport class MausoleumGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Base of the Mausoleum\n const baseGeometry = new BoxGeometry(5, 1, 5);\n baseGeometry.translate(0, 0.5, 0);\n\n // Main Building Structure\n const buildingGeometry = new BoxGeometry(4, 3, 4);\n buildingGeometry.translate(0, 2.5, 0);\n\n // Pillars\n const pillarPositions = [\n [-1.8, 2.3, -2.2],\n [1.8, 2.3, -2.2],\n [-1.8, 2.3, 2.2],\n [1.8, 2.3, 2.2],\n ];\n\n const pillars: BufferGeometry[] = [];\n pillarPositions.forEach((position) => {\n const pillar = new CylinderGeometry(0.2, 0.2, 3.5, 16);\n pillar.translate(position[0], position[1], position[2]);\n pillars.push(pillar);\n });\n\n // Roof (Peaked)\n const roofGeometry = new ConeGeometry(3.5, 2, 4);\n roofGeometry.rotateY(Math.PI / 4);\n roofGeometry.translate(0, 5, 0);\n\n // Arched Entrance\n const archShape = new Shape();\n archShape.moveTo(-1, 0);\n archShape.lineTo(-1, 2);\n archShape.absarc(0, 2, 1, Math.PI, 0, true);\n archShape.lineTo(1, 0);\n\n const extrudeSettings = {\n depth: 0.5,\n bevelEnabled: false,\n };\n const archGeometry = new ExtrudeGeometry(archShape, extrudeSettings);\n archGeometry.translate(0, 0.5, 1.7);\n archGeometry.setIndex([...Array(archGeometry.attributes.position.count).keys()]);\n\n this.copy(\n mergeGeometries(\n [\n baseGeometry,\n mergeGeometries([buildingGeometry, ...pillars], false) as BufferGeometry,\n roofGeometry,\n archGeometry,\n ],\n true,\n ) as BufferGeometry,\n );\n this.computeVertexNormals();\n }\n}\n","import { BoxGeometry, BufferGeometry, ConeGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface ObeliskHeadstoneGeometryOptions {\n /** Total monument height. Defaults to `1.75`. */\n totalHeight?: number;\n /** Base platform width. Defaults to `0.75`. */\n baseWidth?: number;\n}\n\n/**\n * Tiered obelisk headstone with pyramid cap.\n *\n * Local frame: base on Y=0, centered on X/Z.\n */\nexport class ObeliskHeadstoneGeometry extends BufferGeometry {\n readonly totalHeight: number;\n readonly baseWidth: number;\n\n constructor({ totalHeight = 1.75, baseWidth = 0.75 }: ObeliskHeadstoneGeometryOptions = {}) {\n super();\n\n this.totalHeight = totalHeight;\n this.baseWidth = baseWidth;\n\n const baseHeight = totalHeight * 0.05;\n const lowerSegmentHeight = totalHeight * 0.15;\n const middleSegmentHeight = totalHeight * 0.15;\n const topSegmentHeight = totalHeight * 0.75;\n\n let currentHeight = 0;\n\n const baseGeometry = new BoxGeometry(baseWidth, baseHeight, baseWidth);\n baseGeometry.translate(0, currentHeight + baseHeight / 2, 0);\n currentHeight += baseHeight;\n\n const lowerSegmentGeometry = new BoxGeometry(baseWidth * 0.8, lowerSegmentHeight, baseWidth * 0.8);\n lowerSegmentGeometry.translate(0, currentHeight + lowerSegmentHeight / 2, 0);\n currentHeight += lowerSegmentHeight;\n\n const middleSegmentGeometry = new BoxGeometry(baseWidth * 0.6, middleSegmentHeight, baseWidth * 0.6);\n middleSegmentGeometry.translate(0, currentHeight + middleSegmentHeight / 2, 0);\n currentHeight += middleSegmentHeight;\n\n const topSegmentGeometry = new BoxGeometry(baseWidth * 0.4, topSegmentHeight, baseWidth * 0.4);\n topSegmentGeometry.translate(0, currentHeight + topSegmentHeight / 2, 0);\n currentHeight += topSegmentHeight;\n\n const pyramidGeometry = new ConeGeometry((baseWidth * 0.4) / Math.sqrt(2), 0.1, 4, 1, false, Math.PI / 4);\n pyramidGeometry.translate(0, currentHeight + 0.1 / 2, 0);\n\n this.copy(\n mergeGeometries(\n [baseGeometry, lowerSegmentGeometry, middleSegmentGeometry, topSegmentGeometry, pyramidGeometry],\n false,\n ) as BufferGeometry,\n );\n this.computeVertexNormals();\n }\n}","import { BoxGeometry, BufferGeometry, CylinderGeometry } from \"three\";\nimport {mergeGeometries} from \"three/addons/utils/BufferGeometryUtils.js\";\n\nclass RoundedHeadstoneGeometry extends BufferGeometry {\n constructor(width = 0.6, height = 1.0, depth = 0.2, radius = 0.6) {\n super();\n\n // Create the base of the headstone (a box)\n const baseHeight = height - radius / 2;\n const baseGeometry = new BoxGeometry(width, baseHeight, depth);\n baseGeometry.translate(0, baseHeight / 2, 0);\n\n // Create the rounded top part (a half cylinder with caps)\n const topGeometry = new CylinderGeometry(radius / 2, radius / 2, depth, 16, 1, false, 0, Math.PI);\n topGeometry.rotateY(Math.PI / 2);\n topGeometry.rotateX(Math.PI / 2);\n topGeometry.translate(0, baseHeight, 0);\n\n // Merge base and top into a single geometry\n this.copy(mergeGeometries([baseGeometry, topGeometry], false) as BufferGeometry);\n this.computeVertexNormals();\n }\n}\n\nexport { RoundedHeadstoneGeometry };\n","import { BoxGeometry, BufferGeometry } from \"three\";\n\nexport class SquareHeadstoneGeometry extends BufferGeometry {\n constructor(width = 0.5, height = 0.8, depth = 0.15) {\n super();\n\n // Create a rectangular slab\n const slabGeometry = new BoxGeometry(width, height, depth);\n slabGeometry.translate(0, height / 2, 0);\n\n this.copy(slabGeometry);\n }\n}\n","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface StoneFencePostGeometryOptions {\n /** Main column height (excluding base and cap). Defaults to `2.25`. */\n height?: number;\n}\n\n/**\n * Stone fence post — wide base, column, and cap.\n *\n * Local frame: base on Y=0.\n */\nexport class StoneFencePostGeometry extends BufferGeometry {\n readonly height: number;\n\n constructor({ height = 2.25 }: StoneFencePostGeometryOptions = {}) {\n super();\n\n this.height = height;\n\n const baseGeometry = new BoxGeometry(1.2, 0.5, 1.2);\n baseGeometry.translate(0, 0.25, 0);\n\n const columnGeometry = new BoxGeometry(1, height, 1);\n columnGeometry.translate(0, 0.5 + height / 2, 0);\n\n const capGeometry = new BoxGeometry(1.4, 0.3, 1.4);\n capGeometry.translate(0, 0.5 + height + 0.15, 0);\n\n this.copy(mergeGeometries([baseGeometry, columnGeometry, capGeometry], false) as BufferGeometry);\n }\n}","import { BufferGeometry, ConeGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface WroughtIronBarGeometryOptions {\n /** Vertical bar height. Defaults to `2`. */\n barHeight?: number;\n /** Bar cylinder radius. Defaults to `0.05`. */\n barRadius?: number;\n /** Spike cone height. Defaults to `0.3`. */\n spikeHeight?: number;\n /** Spike base radius. Defaults to `0.075`. */\n spikeRadius?: number;\n /** Spike depth scale on Z. Defaults to `1`. */\n spikeScaleZ?: number;\n /** Circumference segments. Defaults to `8`. */\n radialSegments?: number;\n}\n\n/**\n * Wrought-iron fence post — cylinder bar with a decorative spike.\n *\n * Local frame: base at Y=0.\n */\nexport class WroughtIronBarGeometry extends BufferGeometry {\n readonly barHeight: number;\n\n constructor({\n barHeight = 2.0,\n barRadius = 0.05,\n spikeHeight = 0.3,\n spikeRadius = 0.075,\n spikeScaleZ = 1.0,\n radialSegments = 8,\n }: WroughtIronBarGeometryOptions = {}) {\n super();\n\n this.barHeight = barHeight;\n\n const barGeometry = new CylinderGeometry(barRadius, barRadius, barHeight, radialSegments);\n barGeometry.translate(0, barHeight / 2, 0);\n\n const spikeGeometry = new ConeGeometry(spikeRadius, spikeHeight, radialSegments);\n spikeGeometry.translate(0, barHeight + spikeHeight / 2, 0);\n spikeGeometry.scale(1, 1, spikeScaleZ);\n\n this.copy(mergeGeometries([barGeometry, spikeGeometry], false) as BufferGeometry);\n }\n}","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport { WroughtIronBarGeometry } from \"./WroughtIronBarGeometry\";\n\nexport interface WroughtIronFenceGeometryOptions {\n /** Number of posts. Defaults to `20`. */\n count?: number;\n /** Center-to-center post spacing. Defaults to `0.4`. */\n spacing?: number;\n /** Post bar height. Defaults to `2`. */\n barHeight?: number;\n /** Post bar radius. Defaults to `0.05`. */\n barRadius?: number;\n /** Post spike height. Defaults to `0.3`. */\n spikeHeight?: number;\n /** Post spike radius. Defaults to `0.075`. */\n spikeRadius?: number;\n /** Post spike Z scale. Defaults to `1`. */\n spikeScaleZ?: number;\n /** Horizontal rail thickness. Defaults to `0.1`. */\n railHeight?: number;\n /** Horizontal rail depth. Defaults to `0.05`. */\n railDepth?: number;\n /** Top rail offset below the spike tip. Defaults to `0`. */\n railOffset?: number;\n /** Post circumference segments. Defaults to `8`. */\n radialSegments?: number;\n}\n\n/**\n * Wrought-iron fence run — repeated posts with top and bottom rails.\n *\n * Local frame: first post at the origin, extending along +X.\n */\nexport class WroughtIronFenceGeometry extends BufferGeometry {\n readonly count: number;\n readonly spacing: number;\n\n constructor({\n count = 20,\n spacing = 0.4,\n barHeight = 2.0,\n barRadius = 0.05,\n spikeHeight = 0.3,\n spikeRadius = 0.075,\n spikeScaleZ = 1.0,\n railHeight = 0.1,\n railDepth = 0.05,\n railOffset = 0.0,\n radialSegments = 8,\n }: WroughtIronFenceGeometryOptions = {}) {\n super();\n\n this.count = count;\n this.spacing = spacing;\n\n const geometries = [];\n const bar = new WroughtIronBarGeometry({\n barHeight,\n barRadius,\n spikeHeight,\n spikeRadius,\n spikeScaleZ,\n radialSegments,\n });\n const rail = new BoxGeometry(count * spacing, railHeight, railDepth);\n\n for (let i = 0; i < count; i++) {\n const geometry = bar.clone();\n geometry.translate(i * spacing, 0, 0);\n geometries.push(geometry);\n }\n\n const topRail = rail.clone();\n topRail.translate((spacing * (count - 1)) / 2, barHeight - railOffset - railHeight / 2, 0);\n geometries.push(topRail);\n\n const bottomRail = rail.clone();\n bottomRail.translate((spacing * (count - 1)) / 2, railHeight / 2, 0);\n geometries.push(bottomRail);\n\n this.copy(mergeGeometries(geometries) as BufferGeometry);\n }\n}","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface BookshelfGeometryOptions {\n /** Overall width. Defaults to `5`. */\n width?: number;\n /** Overall height. Defaults to `8`. */\n height?: number;\n /** Shelf depth. Defaults to `1`. */\n depth?: number;\n /** Number of interior shelves. Defaults to `4`. */\n shelves?: number;\n /** Frame board thickness. Defaults to `0.1`. */\n frameThickness?: number;\n /** Omit the back panel when `true`. Defaults to `false`. */\n open?: boolean;\n}\n\n/**\n * Bookshelf frame with optional back panel and evenly spaced shelves.\n *\n * Local frame: sits on the Y=0 plane, centered on X/Z.\n */\nexport class BookshelfGeometry extends BufferGeometry {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n readonly shelves: number;\n\n constructor({\n width = 5,\n height = 8,\n depth = 1,\n shelves = 4,\n frameThickness = 0.1,\n open = false,\n }: BookshelfGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.shelves = shelves;\n\n const sidePanelGeometry = new BoxGeometry(frameThickness, height, depth);\n const shelfGeometry = new BoxGeometry(width - 2 * frameThickness, frameThickness, depth);\n\n const leftPanel = sidePanelGeometry.clone();\n leftPanel.translate(-width / 2 + frameThickness / 2, height / 2, 0);\n\n const rightPanel = sidePanelGeometry.clone();\n rightPanel.translate(width / 2 - frameThickness / 2, height / 2, 0);\n\n const topPanel = shelfGeometry.clone();\n topPanel.translate(0, height - frameThickness / 2, 0);\n\n const bottomPanel = shelfGeometry.clone();\n bottomPanel.translate(0, frameThickness / 2, 0);\n\n const backPanel = new BoxGeometry(width, height, frameThickness);\n backPanel.translate(0, height / 2, -depth / 2 + frameThickness / 2);\n\n const shelfPanels = [];\n const shelfSpacing = (height - frameThickness) / (shelves + 1);\n for (let i = 1; i <= shelves; i++) {\n const shelfPanel = shelfGeometry.clone();\n shelfPanel.translate(0, frameThickness / 2 + i * shelfSpacing, 0);\n shelfPanels.push(shelfPanel);\n }\n\n this.copy(\n mergeGeometries(\n [leftPanel, rightPanel, topPanel, bottomPanel, ...(open ? [] : [backPanel]), ...shelfPanels],\n false,\n ) as BufferGeometry,\n );\n }\n}","import { BoxGeometry, BufferGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Group indices:\n * 0. Desk surface\n * 1. Desk legs\n */\nexport class DeskGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Desk Surface\n const surfaceGeometry = new BoxGeometry(5, 0.3, 3);\n surfaceGeometry.translate(0, 3.15, 0);\n\n // Desk Legs (using lathe geometry)\n const points = [\n new Vector2(0.2, 0), //\n new Vector2(0.25, 0.5),\n new Vector2(0.15, 1.5),\n new Vector2(0.3, 3),\n ];\n\n const legLatheGeometry = new LatheGeometry(points, 32);\n\n // Create four legs for the desk\n const legPositions = [\n [2.1, 0, 1.1],\n [-2.1, 0, 1.1],\n [2.1, 0, -1.1],\n [-2.1, 0, -1.1],\n ];\n\n const legGeometry = mergeGeometries(\n legPositions.map((position) => {\n const leg = legLatheGeometry.clone();\n leg.translate(position[0], position[1], position[2]);\n return leg;\n }),\n ) as BufferGeometry;\n\n this.copy(mergeGeometries([surfaceGeometry, legGeometry], true) as BufferGeometry);\n }\n}\n","import { BufferGeometry, Float32BufferAttribute } from \"three\";\n\nexport interface LeafGeometryOptions {\n /** Overall leaf scale. Defaults to `0.13`. */\n size?: number;\n /** Midrib rise above the rim as a fraction of size. Defaults to `0.22`. */\n lift?: number;\n}\n\n/**\n * Low-poly folded leaf — a pointed ellipse with a gently raised midrib so it\n * catches rim light instead of reading as a flat sliver. Spine vertices sit\n * slightly above the mirrored rim outline, giving a soft V cross-section under\n * flat shading.\n *\n * Local frame: tip at +Y, base at −Y, fold rises along +Z.\n */\nexport class LeafGeometry extends BufferGeometry {\n readonly size: number;\n readonly lift: number;\n\n constructor({ size = 0.13, lift = 0.22 }: LeafGeometryOptions = {}) {\n super();\n\n this.size = size;\n this.lift = lift;\n\n // Outline pairs (rim) running tip → base down each side, plus a raised spine.\n const half: [number, number][] = [\n [0.0, 1.0],\n [0.34, 0.55],\n [0.42, 0.05],\n [0.3, -0.45],\n [0.0, -1.0],\n ];\n\n const verts: number[] = [];\n const idx: number[] = [];\n\n const spine: number[] = [];\n for (let i = 0; i < half.length; i++) {\n const [, y] = half[i];\n spine.push(verts.length / 3);\n verts.push(0, y * size, lift * size * (1 - Math.abs(y)));\n }\n\n const left: number[] = [];\n const right: number[] = [];\n for (let i = 0; i < half.length; i++) {\n const [x, y] = half[i];\n right.push(verts.length / 3);\n verts.push(x * size, y * size, 0);\n left.push(verts.length / 3);\n verts.push(-x * size, y * size, 0);\n }\n\n for (let i = 0; i < half.length - 1; i++) {\n idx.push(spine[i], right[i], right[i + 1], spine[i], right[i + 1], spine[i + 1]);\n idx.push(spine[i], spine[i + 1], left[i + 1], spine[i], left[i + 1], left[i]);\n }\n\n this.setAttribute(\"position\", new Float32BufferAttribute(verts, 3));\n this.setIndex(idx);\n this.computeVertexNormals();\n this.computeBoundingSphere();\n }\n}","import { ParametricGeometry } from \"three/addons/geometries/ParametricGeometry.js\";\nimport { Vector3 } from \"three\";\n\nexport interface FlameGeometryOptions {\n /** Flame tip height. Defaults to `0.25`. */\n height?: number;\n /** Base radius at the widest point. Defaults to `0.05`. */\n radius?: number;\n /** Parametric segments around the circumference. Defaults to `16`. */\n segmentsU?: number;\n /** Parametric segments along the height. Defaults to `16`. */\n segmentsV?: number;\n}\n\n/**\n * Teardrop flame volume — parametric surface tapering to a point at the top.\n *\n * Local frame: base at Y=0, tip at Y=`height`.\n */\nexport class FlameGeometry extends ParametricGeometry {\n readonly height: number;\n readonly radius: number;\n readonly segmentsU: number;\n readonly segmentsV: number;\n\n constructor({\n height = 0.25,\n radius = 0.05,\n segmentsU = 16,\n segmentsV = 16,\n }: FlameGeometryOptions = {}) {\n super(\n (u: number, v: number, target: Vector3) => {\n const theta = u * Math.PI * 2;\n const radialFactor = Math.sin(v * Math.PI);\n const x = radius * radialFactor * Math.cos(theta);\n const y = v * height;\n const z = radius * radialFactor * Math.sin(theta);\n\n target.set(x, y, -z);\n },\n segmentsU,\n segmentsV,\n );\n\n this.height = height;\n this.radius = radius;\n this.segmentsU = segmentsU;\n this.segmentsV = segmentsV;\n }\n}","import { BufferGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport { FlameGeometry } from \"./FlameGeometry\";\n\nexport interface CandleGeometryOptions {\n /** Stick top radius. Defaults to `0.2`. */\n radiusTop?: number;\n /** Stick bottom radius. Defaults to `0.2`. */\n radiusBottom?: number;\n /** Stick height. Defaults to `1`. */\n height?: number;\n /** Flame tip height. Defaults to `0.25`. */\n flameHeight?: number;\n /** Flame base radius. Defaults to `0.05`. */\n flameRadius?: number;\n /** Circumference segments. Defaults to `16`. */\n segments?: number;\n}\n\n/**\n * Candle stick and flame — group 0 stick, group 1 flame.\n *\n * Local frame: base at Y=0.\n */\nexport class CandleGeometry extends BufferGeometry {\n readonly radiusTop: number;\n readonly radiusBottom: number;\n readonly height: number;\n readonly flameHeight: number;\n readonly flameRadius: number;\n readonly segments: number;\n\n constructor({\n radiusTop = 0.2,\n radiusBottom = 0.2,\n height = 1,\n flameHeight = 0.25,\n flameRadius = 0.05,\n segments = 16,\n }: CandleGeometryOptions = {}) {\n super();\n\n this.radiusTop = radiusTop;\n this.radiusBottom = radiusBottom;\n this.height = height;\n this.flameHeight = flameHeight;\n this.flameRadius = flameRadius;\n this.segments = segments;\n\n const stickGeometry = new CylinderGeometry(radiusTop, radiusBottom, height, segments);\n stickGeometry.translate(0, height / 2, 0);\n\n const flameGeometry = new FlameGeometry({\n segmentsU: segments,\n segmentsV: segments,\n height: flameHeight,\n radius: flameRadius,\n });\n flameGeometry.translate(0, height, 0);\n\n this.copy(mergeGeometries([stickGeometry, flameGeometry], true) as BufferGeometry);\n }\n}","import { BufferGeometry, ConeGeometry, CylinderGeometry, TorusGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface LanternGeometryOptions {\n /** Base / foot radius. Defaults to `0.5`. */\n baseWidth?: number;\n /** Glass body height. Defaults to `1.3`. */\n bodyHeight?: number;\n /** Base height. Defaults to `0.2`. */\n baseHeight?: number;\n /** Roof cone height. Defaults to `0.5`. */\n roofHeight?: number;\n /** Roof cone radius. Defaults to `baseWidth * 1.1`. */\n roofRadius?: number;\n /** Glass radius relative to `baseWidth`. Defaults to `0.9`. */\n glassRadiusScale?: number;\n /** Glass height inset relative to `bodyHeight`. Defaults to `0.96`. */\n innerScale?: number;\n /** Carry-handle major radius. Defaults to `baseWidth * 0.8`. */\n handleRadius?: number;\n /** Carry-handle tube radius. Defaults to `0.05`. */\n handleTubeRadius?: number;\n /** Gap above the roof to the handle center. Defaults to `0.35`. */\n handleLift?: number;\n /** Radial segments on round parts. Defaults to `8`. */\n segments?: number;\n /** Include the emissive glass body. Defaults to `true`. */\n inner?: boolean;\n}\n\n/**\n * Tabletop lantern — wood/metal base, roof, and handle framing an emissive\n * glass body.\n *\n * Material groups: `0` frame (base + roof + handle), `1` glass body.\n *\n * Local frame: sits on the Y=0 plane; lamp center at `lampCenterY`.\n */\nexport class LanternGeometry extends BufferGeometry {\n readonly baseWidth: number;\n readonly bodyHeight: number;\n readonly baseHeight: number;\n readonly innerScale: number;\n readonly inner: boolean;\n readonly lampCenterY: number;\n\n constructor({\n baseWidth = 0.5,\n bodyHeight = 1.3,\n baseHeight = 0.2,\n roofHeight = 0.5,\n roofRadius = baseWidth * 1.1,\n glassRadiusScale = 0.9,\n innerScale = 0.96,\n handleRadius = baseWidth * 0.8,\n handleTubeRadius = 0.05,\n handleLift = 0.35,\n segments = 8,\n inner = true,\n }: LanternGeometryOptions = {}) {\n super();\n\n this.baseWidth = baseWidth;\n this.bodyHeight = bodyHeight;\n this.baseHeight = baseHeight;\n this.innerScale = innerScale;\n this.inner = inner;\n this.lampCenterY = baseHeight + bodyHeight / 2;\n\n const frame: BufferGeometry[] = [];\n\n const base = new CylinderGeometry(baseWidth, baseWidth, baseHeight, segments);\n base.translate(0, baseHeight / 2, 0);\n frame.push(base);\n\n const roofBottomY = baseHeight + bodyHeight;\n const roof = new ConeGeometry(roofRadius, roofHeight, segments);\n roof.translate(0, roofBottomY + roofHeight / 2, 0);\n frame.push(roof);\n\n const roofTopY = roofBottomY + roofHeight;\n const handle = new TorusGeometry(handleRadius, handleTubeRadius, segments, segments * 2);\n handle.translate(0, roofTopY + handleLift, 0);\n frame.push(handle);\n\n const frameMerged = mergeGeometries(\n frame.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n\n const parts = [frameMerged];\n\n if (inner) {\n const glass = new CylinderGeometry(\n baseWidth * glassRadiusScale * innerScale,\n baseWidth * glassRadiusScale * innerScale,\n bodyHeight * innerScale,\n segments,\n );\n glass.translate(0, this.lampCenterY, 0);\n parts.push(glass.toNonIndexed());\n }\n\n this.copy(mergeGeometries(parts, true) as BufferGeometry);\n this.computeBoundingSphere();\n }\n}","import { BoxGeometry, Quaternion, Vector3 } from \"three\";\n\nconst Y_AXIS = new Vector3(0, 1, 0);\n\n/** Thin box aligned between two points — for open iron lantern cages. */\nexport function barBetween(from: Vector3, to: Vector3, thickness: number): BoxGeometry {\n const direction = to.clone().sub(from);\n const length = direction.length();\n const geometry = new BoxGeometry(thickness, length, thickness);\n geometry.applyQuaternion(new Quaternion().setFromUnitVectors(Y_AXIS, direction.normalize()));\n const midpoint = from.clone().add(to).multiplyScalar(0.5);\n geometry.translate(midpoint.x, midpoint.y, midpoint.z);\n return geometry;\n}","import { BoxGeometry, BufferGeometry, OctahedronGeometry, Vector3 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport { barBetween } from \"./barBetween\";\n\nexport interface HangingLanternGeometryOptions {\n /** Chain length from the hang point. Defaults to `3`. */\n drop?: number;\n /** Chain link cross-section. Defaults to `0.05`. */\n chainWidth?: number;\n /** Cap width (X). Defaults to `0.18`. */\n capWidth?: number;\n /** Cap height (Y). Defaults to `0.16`. */\n capHeight?: number;\n /** Cap depth (Z). Defaults to `0.18`. */\n capDepth?: number;\n /** Cap center offset below the chain bottom. Defaults to `0.02`. */\n capOffset?: number;\n /** Cage vertex radius before stretch. Defaults to `0.42`. */\n cageRadius?: number;\n /** Vertical stretch on the cage. Defaults to `1.4`. */\n cageStretch?: number;\n /** Extra downward offset below the cap-center cage attach. Defaults to `0`. */\n cageGap?: number;\n /** Cage strut thickness. Defaults to `0.03`. */\n cageBarWidth?: number;\n /** Inner lamp scale relative to the cage (inset to sit inside struts). Defaults to `0.96`. */\n innerScale?: number;\n /** Include the solid inner octahedron lamp volume. Defaults to `true`. */\n inner?: boolean;\n}\n\n/**\n * Wrought-iron hanging lantern frame — chain, cap, and open octahedron cage\n * built from edge struts.\n *\n * Material groups: `0` mount (chain + cap), `1` cage struts, `2` inner lamp\n * (solid octahedron).\n *\n * Local frame: origin at the chain top (hang point). The cage top vertex\n * attaches at the cap center, optionally lowered by `cageGap`.\n */\nexport class HangingLanternGeometry extends BufferGeometry {\n readonly drop: number;\n readonly chainWidth: number;\n readonly capWidth: number;\n readonly capHeight: number;\n readonly capDepth: number;\n readonly capOffset: number;\n readonly cageRadius: number;\n readonly cageStretch: number;\n readonly cageGap: number;\n readonly cageBarWidth: number;\n readonly innerScale: number;\n readonly inner: boolean;\n /** Y of the cage center in local space (negative, below the hang point). */\n readonly cageCenterY: number;\n\n constructor({\n drop = 3,\n chainWidth = 0.05,\n capWidth = 0.18,\n capHeight = 0.16,\n capDepth = 0.18,\n capOffset = 0.02,\n cageRadius = 0.42,\n cageStretch = 1.4,\n cageGap = 0,\n cageBarWidth = 0.03,\n innerScale = 0.96,\n inner = true,\n }: HangingLanternGeometryOptions = {}) {\n super();\n\n this.drop = drop;\n this.chainWidth = chainWidth;\n this.capWidth = capWidth;\n this.capHeight = capHeight;\n this.capDepth = capDepth;\n this.capOffset = capOffset;\n this.cageRadius = cageRadius;\n this.cageStretch = cageStretch;\n this.cageGap = cageGap;\n this.cageBarWidth = cageBarWidth;\n this.innerScale = innerScale;\n this.inner = inner;\n\n const capCenterY = -drop + capOffset;\n this.cageCenterY = capCenterY - cageRadius * cageStretch - cageGap;\n\n const mount: BufferGeometry[] = [];\n\n const chain = new BoxGeometry(chainWidth, drop, chainWidth);\n chain.translate(0, -drop / 2, 0);\n mount.push(chain);\n\n const cap = new BoxGeometry(capWidth, capHeight, capDepth);\n cap.translate(0, -drop + capOffset, 0);\n mount.push(cap);\n\n const cy = this.cageCenterY;\n const r = cageRadius;\n const top = new Vector3(0, cy + r * cageStretch, 0);\n const bottom = new Vector3(0, cy - r * cageStretch, 0);\n const px = new Vector3(r, cy, 0);\n const nx = new Vector3(-r, cy, 0);\n const pz = new Vector3(0, cy, r);\n const nz = new Vector3(0, cy, -r);\n\n const cageEdges: [Vector3, Vector3][] = [\n [top, px],\n [top, nx],\n [top, pz],\n [top, nz],\n [bottom, px],\n [bottom, nx],\n [bottom, pz],\n [bottom, nz],\n [px, pz],\n [pz, nx],\n [nx, nz],\n [nz, px],\n ];\n\n const cage = cageEdges.map(([from, to]) => barBetween(from, to, cageBarWidth));\n\n const mountMerged = mergeGeometries(\n mount.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n const cageMerged = mergeGeometries(\n cage.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n\n const parts = [mountMerged, cageMerged];\n\n if (inner) {\n const lamp = new OctahedronGeometry(cageRadius * innerScale, 0);\n lamp.scale(1, cageStretch, 1);\n lamp.translate(0, cy, 0);\n parts.push(lamp.toNonIndexed());\n }\n\n this.copy(mergeGeometries(parts, true) as BufferGeometry);\n this.computeBoundingSphere();\n }\n}","import { BoxGeometry, BufferGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface WallSconceGeometryOptions {\n /** Wall-plate thickness (X). Defaults to `0.05`. */\n plateThickness?: number;\n /** Wall-plate height (Y). Defaults to `0.22`. */\n plateHeight?: number;\n /** Wall-plate depth (Z). Defaults to `0.28`. */\n plateDepth?: number;\n /** Wall-plate center X (negative = into the wall). Defaults to `-0.055`. */\n plateOffsetX?: number;\n /** Bracket length into the room (X). Defaults to `0.1`. */\n bracketLength?: number;\n /** Bracket height (Y). Defaults to `0.05`. */\n bracketHeight?: number;\n /** Bracket depth (Z). Defaults to `0.07`. */\n bracketDepth?: number;\n /** Bracket center X. Defaults to `-0.005`. */\n bracketOffsetX?: number;\n /** Bracket center Y. Defaults to `0.1`. */\n bracketOffsetY?: number;\n /** Chimney / lamp body center X. Defaults to `0.06`. */\n bodyOffsetX?: number;\n /** Chimney height. Defaults to `0.3`. */\n chimneyHeight?: number;\n /** Chimney top radius. Defaults to `0.1`. */\n chimneyTopRadius?: number;\n /** Chimney bottom radius. Defaults to `0.105`. */\n chimneyBottomRadius?: number;\n /** Chimney center Y. Defaults to `-0.05`. */\n chimneyCenterY?: number;\n /** Cap radius. Defaults to `0.115`. */\n capRadius?: number;\n /** Cap height. Defaults to `0.05`. */\n capHeight?: number;\n /** Cap center Y. Defaults to `0.12`. */\n capCenterY?: number;\n /** Bowl top radius. Defaults to `0.09`. */\n bowlTopRadius?: number;\n /** Bowl bottom radius. Defaults to `0.11`. */\n bowlBottomRadius?: number;\n /** Bowl height. Defaults to `0.05`. */\n bowlHeight?: number;\n /** Bowl center Y. Defaults to `-0.22`. */\n bowlCenterY?: number;\n /** Radial segments on cylinders. Defaults to `8`. */\n radialSegments?: number;\n /** Glass chimney scale relative to the frame opening. Defaults to `0.96`. */\n innerScale?: number;\n /** Include the emissive glass chimney. Defaults to `true`. */\n inner?: boolean;\n}\n\n/**\n * Wall-mounted oil-lamp sconce — iron mount, cap, and bowl framing an emissive\n * glass chimney.\n *\n * Material groups: `0` mount (plate + bracket), `1` iron frame (cap + bowl),\n * `2` glass chimney.\n *\n * Local frame: faces +X from a −X wall; lamp center at\n * `(bodyOffsetX, chimneyCenterY, 0)`.\n */\nexport class WallSconceGeometry extends BufferGeometry {\n readonly bodyOffsetX: number;\n readonly chimneyCenterY: number;\n readonly innerScale: number;\n readonly inner: boolean;\n readonly lightCenterX: number;\n readonly lightCenterY: number;\n readonly lightCenterZ: number;\n\n constructor({\n plateThickness = 0.05,\n plateHeight = 0.22,\n plateDepth = 0.28,\n plateOffsetX = -0.055,\n bracketLength = 0.1,\n bracketHeight = 0.05,\n bracketDepth = 0.07,\n bracketOffsetX = -0.005,\n bracketOffsetY = 0.1,\n bodyOffsetX = 0.06,\n chimneyHeight = 0.3,\n chimneyTopRadius = 0.1,\n chimneyBottomRadius = 0.105,\n chimneyCenterY = -0.05,\n capRadius = 0.115,\n capHeight = 0.05,\n capCenterY = 0.12,\n bowlTopRadius = 0.09,\n bowlBottomRadius = 0.11,\n bowlHeight = 0.05,\n bowlCenterY = -0.22,\n radialSegments = 8,\n innerScale = 0.96,\n inner = true,\n }: WallSconceGeometryOptions = {}) {\n super();\n\n this.bodyOffsetX = bodyOffsetX;\n this.chimneyCenterY = chimneyCenterY;\n this.innerScale = innerScale;\n this.inner = inner;\n this.lightCenterX = bodyOffsetX;\n this.lightCenterY = chimneyCenterY;\n this.lightCenterZ = 0;\n\n const mount: BufferGeometry[] = [];\n\n const plate = new BoxGeometry(plateThickness, plateHeight, plateDepth);\n plate.translate(plateOffsetX, 0, 0);\n mount.push(plate);\n\n const bracket = new BoxGeometry(bracketLength, bracketHeight, bracketDepth);\n bracket.translate(bracketOffsetX, bracketOffsetY, 0);\n mount.push(bracket);\n\n const frame: BufferGeometry[] = [];\n\n const cap = new CylinderGeometry(capRadius, capRadius, capHeight, radialSegments);\n cap.translate(bodyOffsetX, capCenterY, 0);\n frame.push(cap);\n\n const bowl = new CylinderGeometry(bowlTopRadius, bowlBottomRadius, bowlHeight, radialSegments);\n bowl.translate(bodyOffsetX, bowlCenterY, 0);\n frame.push(bowl);\n\n const mountMerged = mergeGeometries(\n mount.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n const frameMerged = mergeGeometries(\n frame.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n\n const parts = [mountMerged, frameMerged];\n\n if (inner) {\n const glass = new CylinderGeometry(\n chimneyTopRadius * innerScale,\n chimneyBottomRadius * innerScale,\n chimneyHeight * innerScale,\n radialSegments,\n );\n glass.translate(bodyOffsetX, chimneyCenterY, 0);\n parts.push(glass.toNonIndexed());\n }\n\n this.copy(mergeGeometries(parts, true) as BufferGeometry);\n this.computeBoundingSphere();\n }\n}","import { BufferAttribute, BufferGeometry } from \"three\";\n\n/**\n * Prismatic parallelogram, with horizontal skew (offset in X for the slant).\n */\nexport class ParallelogramBoxGeometry extends BufferGeometry {\n constructor(width = 1, height = 2, depth = 0.5, angle = Math.PI / 4) {\n super();\n\n const s = height * Math.tan(angle); // skew\n const w = width;\n const h = height;\n const d = depth;\n\n // Bottom face vertices (X, Y, Z)\n const vertices = [\n 0, 0, 0, // Front face, bottom left\n w, 0, 0, // Front face, bottom right\n w + s, h, 0, // Front face, top right\n s, h, 0, // Front face, top left\n\n w, 0, -d, // Back face\n 0, 0, -d,\n s, h, -d,\n w + s, h, -d,\n\n 0, 0, -d, // Left face\n 0, 0, 0,\n s, h, 0,\n s, h, -d,\n\n w, 0, 0, // Right face\n w, 0, -d,\n w + s, h, -d,\n w + s, h, 0,\n\n s, h, 0, // Top face\n w + s, h, 0,\n w + s, h, -d,\n s, h, -d,\n\n 0, 0, -d, // Bottom\n w, 0, -d,\n w, 0, 0,\n 0, 0, 0,\n ];\n\n const normals = [\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Front face\n 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, // Back face\n -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // Left face\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Right face\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Top face\n 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, // Bottom face\n ]\n\n // Define indices for faces (triangles)\n const indices = [\n 0, 1, 2, 2, 3, 0, // Front face\n 4, 5, 6, 6, 7, 4, // Back face\n 8, 9, 10, 10, 11, 8, // Left face\n 12, 13, 14, 14, 15, 12, // Right face\n 16, 17, 18, 18, 19, 16, // Top face\n 20, 21, 22, 22, 23, 20, // Bottom face\n ];\n\n // Define UV coordinates\n const uvs = new Float32Array([\n 0, 0, 1, 0, 1, 1, 0, 1, // Front face\n 0, 0, 1, 0, 1, 1, 0, 1, // Back face\n 0, 0, 1, 0, 1, 1, 0, 1, // Left face\n 0, 0, 1, 0, 1, 1, 0, 1, // Right face\n 0, 0, 1, 0, 1, 1, 0, 1, // Top face\n 0, 0, 1, 0, 1, 1, 0, 1, // Bottom face\n ]);\n\n\n const positions = new Float32Array(vertices);\n const normalArray = new Float32Array(normals);\n const uvArray = new Float32Array(uvs);\n const indexArray = new Uint16Array(indices);\n\n this.setAttribute('position', new BufferAttribute(positions, 3));\n this.setAttribute('normal', new BufferAttribute(normalArray, 3));\n this.setAttribute('uv', new BufferAttribute(uvArray, 2));\n this.setIndex(new BufferAttribute(indexArray, 1));\n this.center();\n }\n}\n","import { Path, Shape } from \"three\";\n\nexport class GearShape extends Shape {\n constructor(sides = 5, innerRadius = 0.5, outerRadius = 1, holeSides = 5, holeRadius = 0.25) {\n super();\n\n const step = (Math.PI * 2) / sides;\n const qtrStep = step / 4;\n\n this.moveTo(Math.cos(0) * outerRadius, -Math.sin(0) * outerRadius);\n\n for (let n = 1; n <= sides; ++n) {\n this.lineTo(Math.cos(step * n - qtrStep * 3) * innerRadius, -Math.sin(step * n - qtrStep * 3) * innerRadius);\n this.lineTo(Math.cos(step * n - qtrStep * 2) * innerRadius, -Math.sin(step * n - qtrStep * 2) * innerRadius);\n this.lineTo(Math.cos(step * n - qtrStep) * outerRadius, -Math.sin(step * n - qtrStep) * outerRadius);\n this.lineTo(Math.cos(step * n) * outerRadius, -Math.sin(step * n) * outerRadius);\n }\n this.closePath();\n\n // Create the hole in the gear, if specified\n if (holeRadius > 0 && holeSides > 2) {\n const hole = new Path();\n const holeStep = (Math.PI * 2) / holeSides;\n\n hole.moveTo(Math.cos(0) * holeRadius, -Math.sin(0) * holeRadius);\n for (let n = 1; n < holeSides; ++n) {\n hole.lineTo(Math.cos(holeStep * n) * holeRadius, -Math.sin(holeStep * n) * holeRadius);\n }\n hole.lineTo(Math.cos(0) * holeRadius, -Math.sin(0) * holeRadius);\n\n this.holes.push(hole);\n }\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { GearShape } from \"../../shapes/GearShape\";\n\nexport interface GearGeometryOptions {\n /** Number of gear teeth. Defaults to `5`. */\n sides?: number;\n /** Inner tooth valley radius. Defaults to `0.5`. */\n innerRadius?: number;\n /** Outer tooth tip radius. Defaults to `1`. */\n outerRadius?: number;\n /** Center hole sides. Defaults to `5`. */\n holeSides?: number;\n /** Center hole radius. Defaults to `0.25`. */\n holeRadius?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded gear profile with center hole.\n */\nexport class GearGeometry extends ExtrudeGeometry {\n constructor({\n sides = 5,\n innerRadius = 0.5,\n outerRadius = 1,\n holeSides = 5,\n holeRadius = 0.25,\n depth = 0.25,\n }: GearGeometryOptions = {}) {\n super(new GearShape(sides, innerRadius, outerRadius, holeSides, holeRadius), {\n depth,\n bevelEnabled: false,\n });\n }\n}","import { Shape } from \"three\";\n\nexport class HeartShape extends Shape {\n constructor(size = 1, width = 2.1, height = 1.4, tipDepth = 1.6) {\n super();\n\n // Start from the top middle of the heart\n this.moveTo(0, height * size / 3);\n\n // Left curve\n this.bezierCurveTo(\n -width * 0.375 * size, height * size, // Control point 1 for the left lobe\n -width * size, height * size / 3, // Control point 2 for the left side of the heart\n 0, -tipDepth * size // Bottom tip of the heart, controlled by `tipDepth`\n );\n\n // Right curve\n this.bezierCurveTo(\n width * size, height * size / 3, // Control point 3 for the right side of the heart\n width * 0.375 * size, height * size, // Control point 4 for the right lobe\n 0, height * size / 3 // Close shape at the top middle\n );\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { HeartShape } from \"../../shapes/HeartShape\";\n\nexport interface HeartGeometryOptions {\n /** Overall scale factor. Defaults to `1`. */\n size?: number;\n /** Heart width. Defaults to `2.1`. */\n width?: number;\n /** Heart height. Defaults to `1.4`. */\n height?: number;\n /** Tip depth. Defaults to `1.6`. */\n tipDepth?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded heart prism.\n */\nexport class HeartGeometry extends ExtrudeGeometry {\n constructor({\n size = 1,\n width = 2.1,\n height = 1.4,\n tipDepth = 1.6,\n depth = 0.25,\n }: HeartGeometryOptions = {}) {\n super(new HeartShape(size, width, height, tipDepth), { depth, bevelEnabled: false });\n }\n}","import { Shape } from \"three\";\n\nexport class StarShape extends Shape {\n constructor(points = 5, innerRadius = 0.5, outerRadius = 1.0) {\n super();\n\n const step = (Math.PI * 2) / points;\n const halfStep = step / 2;\n this.moveTo(Math.cos(0) * outerRadius, Math.sin(0) * outerRadius);\n\n for (let n = 1; n <= points; ++n) {\n this.lineTo(Math.cos(step * n - halfStep) * innerRadius, Math.sin(step * n - halfStep) * innerRadius);\n this.lineTo(Math.cos(step * n) * outerRadius, Math.sin(step * n) * outerRadius);\n }\n\n this.closePath();\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { StarShape } from \"../../shapes/StarShape\";\n\nexport interface StarGeometryOptions {\n /** Number of star points. Defaults to `5`. */\n points?: number;\n /** Inner vertex radius. Defaults to `0.5`. */\n innerRadius?: number;\n /** Outer vertex radius. Defaults to `1`. */\n outerRadius?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded star prism.\n */\nexport class StarGeometry extends ExtrudeGeometry {\n constructor({\n points = 5,\n innerRadius = 0.5,\n outerRadius = 1.0,\n depth = 0.25,\n }: StarGeometryOptions = {}) {\n super(new StarShape(points, innerRadius, outerRadius), { depth, bevelEnabled: false });\n }\n}","import { BufferGeometry, CylinderGeometry, SphereGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Bone Geometry, a simple bone shape\n * @extends BufferGeometry\n *\n * @example\n * // Create a bone\n * const boneGeometry = new BoneGeometry();\n * const boneMaterial = new MeshStandardMaterial({ color: 0xffffff });\n * const bone = new Mesh(boneGeometry, boneMaterial);\n * scene.add(bone);\n */\nclass BoneGeometry extends BufferGeometry {\n constructor(radiusTop = 0.1, radiusBottom = 0.1, height = 0.4, radialSegments = 8) {\n super();\n\n // Create the cylinder (shaft of the bone)\n const cylinderGeometry = new CylinderGeometry(radiusTop * 0.6, radiusBottom * 0.6, height, radialSegments);\n cylinderGeometry.translate(0, 0, 0);\n\n // Create the spheres (ends of the bone)\n const sphereGeometry = new SphereGeometry(radiusTop, radialSegments, radialSegments);\n const topSphere1 = sphereGeometry.clone();\n const topSphere2 = sphereGeometry.clone();\n const bottomSphere1 = sphereGeometry.clone();\n const bottomSphere2 = sphereGeometry.clone();\n\n // Position the spheres at each end of the cylinder\n topSphere1.translate(0, height / 2 + radiusTop * 0.6, -radiusTop * 0.6);\n topSphere2.translate(0, height / 2 + radiusTop * 0.6, radiusTop * 0.6);\n bottomSphere1.translate(0, -height / 2 - radiusBottom * 0.6, -radiusBottom * 0.6);\n bottomSphere2.translate(0, -height / 2 - radiusBottom * 0.6, radiusBottom * 0.6);\n\n // Merge the parts\n this.copy(mergeGeometries([cylinderGeometry, topSphere1, topSphere2, bottomSphere1, bottomSphere2], false) as BufferGeometry);\n }\n}\n\nexport { BoneGeometry };\n","import { BufferGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface ErlenmeyerFlaskGeometryOptions {\n /** Flask body radius. Defaults to `1`. */\n flaskRadius?: number;\n /** Neck radius. Defaults to `0.3`. */\n neckRadius?: number;\n /** Body height before the neck. Defaults to `2.5`. */\n height?: number;\n /** Neck height. Defaults to `1`. */\n neckHeight?: number;\n /** Lathe segments. Defaults to `16`. */\n radialSegments?: number;\n}\n\n/**\n * Erlenmeyer flask profile — conical body with straight neck and lip.\n *\n * Local frame: base at Y=0.\n */\nexport class ErlenmeyerFlaskGeometry extends BufferGeometry {\n readonly flaskRadius: number;\n readonly height: number;\n\n constructor({\n flaskRadius = 1,\n neckRadius = 0.3,\n height = 2.5,\n neckHeight = 1,\n radialSegments = 16,\n }: ErlenmeyerFlaskGeometryOptions = {}) {\n super();\n\n this.flaskRadius = flaskRadius;\n this.height = height;\n\n const points = [\n new Vector2(0, 0),\n new Vector2(flaskRadius * 0.875, 0),\n new Vector2(flaskRadius, 0.1),\n new Vector2(neckRadius, height),\n new Vector2(neckRadius, height + neckHeight),\n new Vector2(neckRadius * 1.1, height + neckHeight + 0.3),\n ];\n\n const flaskGeometry = new LatheGeometry(points, radialSegments);\n\n this.copy(mergeGeometries([flaskGeometry], false) as BufferGeometry);\n }\n}","/**\n * Calculate the radius to achieve a spherical cap height.\n * R = r / (1 - cos(thetaLength))\n */\nexport const radiusFromCapHeight = (height: number, thetaLength: number) => height / (1 - Math.cos(thetaLength));\n\n/**\n * Calculate the radius to achieve a spherical cap width.\n * R = w / (2 * sin(thetaLength))\n */\nexport const radiusFromCapWidth = (width: number, thetaLength: number) => width / (2 * Math.sin(thetaLength));\n\n/**\n * Calculate the height of a spherical cap.\n * h = R * (1 - cos(thetaLength))\n */\nexport const capHeightFromRadius = (radius: number, thetaLength: number) => radius * (1 - Math.cos(thetaLength));\n\n/**\n * Calculate the width of a spherical cap.\n * w = 2 * R * sin(thetaLength)\n */\nexport const capWidthFromRadius = (radius: number, thetaLength: number) => 2 * radius * Math.sin(thetaLength);\n\n/**\n * Calculate the thetaLength to achieve a specific hole radius in a sphere.\n * thetaLength = asin(w / (2 * R))\n *\n * Returns the thetaLength in radians.\n *\n * Example usage:\n * ```\n * const sphereRadius = 5; // Radius of the sphere\n * const holeRadius = 1; // Desired radius of the hole at the top\n * const thetaLength = thetaLengthForRadius(sphereRadius, holeRadius);\n * ```\n */\nexport const thetaLengthForRadius = (sphereRadius: number, holeRadius: number) => {\n const holeDiameter = 2 * holeRadius; // Hole width\n return Math.asin(holeDiameter / (2 * sphereRadius));\n};\n\n/**\n * Convert spherical coordinates to Cartesian coordinates.\n * @param {number} radius - The radius of the sphere.\n * @param {number} theta - The azimuthal angle in radians (from the x-axis in the x-y plane).\n * @param {number} phi - The polar angle in radians (from the positive z-axis).\n * @returns {{x: number, y: number, z: number}} The Cartesian coordinates.\n */\nexport const sphericalToCartesian = (radius: number, theta: number, phi: number) => {\n return {\n x: radius * Math.sin(phi) * Math.cos(theta),\n y: radius * Math.sin(phi) * Math.sin(theta),\n z: radius * Math.cos(phi),\n };\n};\n\n/**\n * Convert Cartesian coordinates to spherical coordinates.\n * @param {number} x - The x-coordinate.\n * @param {number} y - The y-coordinate.\n * @param {number} z - The z-coordinate.\n * @returns {{radius: number, theta: number, phi: number}} The spherical coordinates.\n */\nexport const cartesianToSpherical = (x: number, y: number, z: number) => {\n const radius = Math.sqrt(x * x + y * y + z * z);\n const theta = Math.atan2(y, x); // Azimuthal angle\n const phi = Math.acos(z / radius); // Polar angle\n return { radius, theta, phi };\n};\n","import { Vector2 } from \"three\";\nimport { thetaLengthForRadius } from \"./SphericalGeometryUtils\";\n\n/**\n * Generates spherical curve profile points, for use with geometry.\n * Enables connective geometry via holes at the top and bottom of the sphere.\n *\n * Example usage:\n *\n * Tube that connect with a sphere on the bottom:\n * ```\n * const points: Vector2[] = [\n * new Vector2(1, 0),\n * ...appendSphericalCurve(\n * 2, // Radius x\n * 2, // Radius y\n * 5, // Start y\n * 0, // Hole top radius\n * 1, // Hole bottom radius\n * 32, // Segments\n * ),\n * ];\n *\n * const latheGeometry = new LatheGeometry(points, 32);\n * ```\n *\n * Tube that connect with a sphere on the top:\n * ```\n * const points: Vector2[] = [\n * ...appendSphericalCurve(\n * 2, // Radius x\n * 2, // Radius y\n * 1, // Start y\n * 1, // Hole top radius\n * 0, // Hole bottom radius\n * 32, // Segments\n * ),\n * new Vector2(1, 5),\n * ];\n *\n * const latheGeometry = new LatheGeometry(points, 32);\n * ```\n */\nexport function appendSphericalCurve(\n sphereRadiusX: number,\n sphereRadiusY: number,\n sphereStartY: number,\n holeTopRadius: number = 0,\n holeBottomRadius: number = 0,\n segments: number = 32,\n) {\n const thetaTop = holeTopRadius ? thetaLengthForRadius(sphereRadiusX, holeTopRadius) : 0;\n const thetaBottom = holeBottomRadius ? Math.PI - thetaLengthForRadius(sphereRadiusX, holeBottomRadius) : Math.PI;\n\n // Generate sphere points (from bottom to top)\n const spherePoints = [];\n for (let i = 0; i <= segments; i++) {\n const theta = thetaBottom - ((thetaBottom - thetaTop) / segments) * i; // Bottom to top\n const x = sphereRadiusX * Math.sin(theta);\n const y = sphereRadiusY * Math.cos(theta) + sphereStartY; // Offset by sphereStartY\n spherePoints.push(new Vector2(x, y));\n }\n\n // Combine base points and sphere points\n return [...spherePoints];\n}\n","import { BufferGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { appendSphericalCurve } from \"../../utils/SphericalCurve\";\n\nexport class FlorenceFlaskGeometry extends BufferGeometry {\n constructor() {\n super();\n\n const points = [\n ...appendSphericalCurve(1, 1, 0.5, 0.2, 0, 32),\n new Vector2(0.2, 3),\n ];\n\n // Create LatheGeometry\n const latheGeometry = new LatheGeometry(points, 32);\n this.copy(latheGeometry);\n }\n}\n","import { BufferGeometry, CircleGeometry, LatheGeometry, Vector2 } from \"three\";\nimport {mergeGeometries} from \"three/addons/utils/BufferGeometryUtils.js\";\n\nclass MortarGeometry extends BufferGeometry {\n constructor() {\n super();\n\n const mortarPoints = [\n new Vector2(1, 0), // Bottom of the bowl\n new Vector2(1.2, 0.5), // Slight flare at the base\n new Vector2(1.4, 1.5), // Outer wall\n new Vector2(1.3, 1.8), // Flared edge\n new Vector2(0.8, 1.8), // Lip of the bowl\n ];\n const mortarGeometry = new LatheGeometry(mortarPoints, 12);\n\n // Create a disk to close off the bottom\n const baseDisk = new CircleGeometry(1, 12); // Radius matches the base of the mortar\n baseDisk.rotateX(-Math.PI / 2); // Rotate to align with the bottom\n baseDisk.translate(0, 0, 0); // Position at the base of the mortar\n\n this.copy(mergeGeometries([mortarGeometry, baseDisk], false) as BufferGeometry);\n }\n}\n\nexport { MortarGeometry };\n","import { BufferGeometry, CylinderGeometry, TorusGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface StandGeometryOptions {\n /** Ring radius. Defaults to `0.3`. */\n radius?: number;\n /** Leg height. Defaults to `0.4`. */\n height?: number;\n /** Number of legs. Defaults to `3`. */\n count?: number;\n /** Ring tube thickness. Defaults to `0.03`. */\n thickness?: number;\n /** Circumference segments. Defaults to `16`. */\n radialSegments?: number;\n}\n\n/**\n * Tripod-style stand — torus ring with radial legs.\n *\n * Local frame: legs on Y=0.\n */\nexport class StandGeometry extends BufferGeometry {\n readonly radius: number;\n readonly height: number;\n readonly count: number;\n\n constructor({\n radius = 0.3,\n height = 0.4,\n count = 3,\n thickness = 0.03,\n radialSegments = 16,\n }: StandGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.height = height;\n this.count = count;\n\n const ringGeometry = new TorusGeometry(radius, thickness, 8, radialSegments);\n ringGeometry.rotateX(Math.PI / 2);\n ringGeometry.translate(0, height, 0);\n\n const legGeometry = new CylinderGeometry(thickness * 0.6, thickness * 0.6, height, radialSegments);\n const legs = [];\n\n for (let i = 0; i < count; i++) {\n const angle = (i / count) * Math.PI * 2;\n const leg = legGeometry.clone();\n leg.translate(Math.cos(angle) * radius, height / 2, Math.sin(angle) * radius);\n legs.push(leg);\n }\n\n this.copy(mergeGeometries([ringGeometry, ...legs], false) as BufferGeometry);\n }\n}","import { BufferGeometry, CylinderGeometry, SphereGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Group indices\n * 0: Base\n * 1: Coil\n */\nexport class TeslaCoilGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Base geometry\n const baseGeometry = new CylinderGeometry(0.5, 0.6, 0.3, 16);\n baseGeometry.translate(0, 0.15, 0);\n\n // Coil geometry\n const coilGeometry = new CylinderGeometry(0.15, 0.15, 2, 12, 1, true);\n coilGeometry.translate(0, 1.3, 0);\n const coilTopGeometry = new SphereGeometry(0.3, 16, 16);\n coilTopGeometry.translate(0, 2.4, 0);\n\n this.copy(\n mergeGeometries(\n [baseGeometry, mergeGeometries([coilGeometry, coilTopGeometry]) as BufferGeometry],\n true,\n ) as BufferGeometry,\n );\n }\n}\n","import { BufferGeometry, CylinderGeometry, SphereGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nclass TestTubeGeometry extends BufferGeometry {\n constructor(radiusTop = 0.2, radiusBottom = 0.2, height = 3, segments = 32, openEnded = true) {\n super();\n\n // Create the cylindrical body\n const tubeGeometry = new CylinderGeometry(radiusTop, radiusBottom, height, segments, 1, openEnded);\n\n // Create the rounded bottom using a half sphere\n const bottomGeometry = new SphereGeometry(radiusBottom, segments, segments / 2, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2);\n bottomGeometry.translate(0, -(height / 2), 0); // Position it at the bottom of the cylinder\n\n // Merge parts\n this.copy(mergeGeometries([tubeGeometry, bottomGeometry], false) as BufferGeometry);\n }\n}\n\nexport { TestTubeGeometry };\n","import { BufferGeometry, SphereGeometry } from \"three\";\n\nexport interface HillGeometryOptions {\n /** Base sphere radius before vertical squash. Defaults to `3`. */\n radius?: number;\n /** Peak height. Defaults to `0.6`. */\n height?: number;\n /** Horizontal segments. Defaults to `64`. */\n widthSegments?: number;\n /** Vertical segments. Defaults to `16`. */\n heightSegments?: number;\n /** Azimuth start angle (radians). Defaults to `0`. */\n phiStart?: number;\n /** Azimuth sweep (radians). Defaults to `2π`. */\n phiLength?: number;\n}\n\n/**\n * Hemispherical hill — a sphere cap scaled on Y, base on the Y=0 plane.\n */\nexport class HillGeometry extends BufferGeometry {\n readonly radius: number;\n readonly height: number;\n\n constructor({\n radius = 3,\n height = 0.6,\n widthSegments = 64,\n heightSegments = 16,\n phiStart = 0,\n phiLength = Math.PI * 2,\n }: HillGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.height = height;\n\n this.copy(new SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, 0, Math.PI / 2));\n this.scale(1, height / radius, 1);\n }\n}","import { BufferGeometry, SphereGeometry } from \"three\";\nimport { capHeightFromRadius, radiusFromCapWidth } from \"../../utils/SphericalGeometryUtils\";\n\nexport interface MoundGeometryOptions {\n /** Sphere radius. Defaults to a cap width of `5` at `thetaLength`. */\n radius?: number;\n /** Horizontal segments. Defaults to `64`. */\n widthSegments?: number;\n /** Vertical segments. Defaults to `32`. */\n heightSegments?: number;\n /** Azimuth start angle (radians). Defaults to `0`. */\n phiStart?: number;\n /** Azimuth sweep (radians). Defaults to `2π`. */\n phiLength?: number;\n /** Polar sweep from the north pole (radians). Defaults to `π/10`. */\n thetaLength?: number;\n}\n\n/**\n * Mound-like geometry with a flat top — sphere cap, base on Y=0.\n */\nexport class MoundGeometry extends BufferGeometry {\n readonly radius: number;\n readonly thetaLength: number;\n\n constructor({\n radius = radiusFromCapWidth(5, Math.PI / 10),\n widthSegments = 64,\n heightSegments = 32,\n phiStart = 0,\n phiLength = Math.PI * 2,\n thetaLength = Math.PI / 10,\n }: MoundGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.thetaLength = thetaLength;\n\n this.copy(new SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, 0, thetaLength));\n\n const height = capHeightFromRadius(radius, thetaLength);\n this.translate(0, -radius + height, 0);\n }\n}","import { BufferGeometry, CylinderGeometry, DodecahedronGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface TreeGeometryOptions {\n /** Trunk top radius. Defaults to `0.25`. */\n trunkRadiusTop?: number;\n /** Trunk bottom radius. Defaults to `0.4`. */\n trunkRadiusBottom?: number;\n /** Trunk height. Defaults to `2.5`. */\n trunkHeight?: number;\n /** Trunk circumference segments. Defaults to `14`. */\n trunkSegments?: number;\n /** Leaf dodecahedron radius. Defaults to `0.8`. */\n leafSize?: number;\n /** Number of leaf clusters. Defaults to `6`. */\n leafCount?: number;\n /** Leaf dodecahedron detail level. Defaults to `0`. */\n leafDetail?: number;\n /** Horizontal spread of leaf placement. Defaults to `1.5`. */\n leafSpreadRadius?: number;\n}\n\n/**\n * Low-poly tree — trunk (group 0) and leaf clusters (group 1).\n *\n * Local frame: trunk base at Y=0. Leaf positions use `Math.random()` each build.\n */\nexport class TreeGeometry extends BufferGeometry {\n readonly trunkRadiusTop: number;\n readonly trunkRadiusBottom: number;\n readonly trunkHeight: number;\n readonly trunkSegments: number;\n readonly leafSize: number;\n readonly leafCount: number;\n readonly leafDetail: number;\n readonly leafSpreadRadius: number;\n\n constructor({\n trunkRadiusTop = 0.25,\n trunkRadiusBottom = 0.4,\n trunkHeight = 2.5,\n trunkSegments = 14,\n leafSize = 0.8,\n leafCount = 6,\n leafDetail = 0,\n leafSpreadRadius = 1.5,\n }: TreeGeometryOptions = {}) {\n super();\n\n this.trunkRadiusTop = trunkRadiusTop;\n this.trunkRadiusBottom = trunkRadiusBottom;\n this.trunkHeight = trunkHeight;\n this.trunkSegments = trunkSegments;\n this.leafSize = leafSize;\n this.leafCount = leafCount;\n this.leafDetail = leafDetail;\n this.leafSpreadRadius = leafSpreadRadius;\n\n const trunk = new CylinderGeometry(trunkRadiusTop, trunkRadiusBottom, trunkHeight, trunkSegments);\n trunk.translate(0, trunkHeight / 2, 0);\n\n const leafs: DodecahedronGeometry[] = [];\n for (let i = 0; i < leafCount; i++) {\n const leaf = new DodecahedronGeometry(leafSize, leafDetail);\n leaf.translate(\n (Math.random() - 0.5) * leafSpreadRadius,\n (Math.random() - 0.5) * leafSize + trunkHeight,\n (Math.random() - 0.5) * leafSpreadRadius,\n );\n leafs.push(leaf);\n }\n\n this.copy(\n mergeGeometries(\n [trunk.toNonIndexed(), mergeGeometries(leafs, false) as BufferGeometry],\n true,\n ) as BufferGeometry,\n );\n this.computeVertexNormals();\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n LShapedStaircaseGeometry,\n type LShapedStaircaseGeometryOptions,\n} from \"../../geometry/architecture/LShapedStaircaseGeometry\";\n\nexport interface LShapedStaircaseOptions extends LShapedStaircaseGeometryOptions {\n /** Tread and riser tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * L-shaped staircase prefab — two flights with a square width × width landing.\n */\nexport class LShapedStaircase extends Mesh<LShapedStaircaseGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepsPerFlight: number;\n readonly landingSize: number;\n readonly flightRun: number;\n readonly totalHeight: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: LShapedStaircaseOptions = {}) {\n const geometry = new LShapedStaircaseGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n side: DoubleSide,\n }),\n );\n\n this.width = geometry.width;\n this.riserHeight = geometry.riserHeight;\n this.treadDepth = geometry.treadDepth;\n this.stepsPerFlight = geometry.stepsPerFlight;\n this.landingSize = geometry.landingSize;\n this.flightRun = geometry.flightRun;\n this.totalHeight = geometry.totalHeight;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n SpiralStaircaseGeometry,\n type SpiralStaircaseGeometryOptions,\n} from \"../../geometry/architecture/SpiralStaircaseGeometry\";\n\nexport interface SpiralStaircaseOptions extends SpiralStaircaseGeometryOptions {\n /** Tread and riser tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Turret-style spiral staircase prefab — wraps {@link SpiralStaircaseGeometry}.\n */\nexport class SpiralStaircase extends Mesh<SpiralStaircaseGeometry, MeshStandardMaterial> {\n readonly innerRadius: number;\n readonly width: number;\n readonly outerRadius: number;\n readonly treadDepth: number;\n readonly riserHeight: number;\n readonly stepCount: number;\n readonly stepAngle: number;\n readonly totalHeight: number;\n readonly totalTurn: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: SpiralStaircaseOptions = {}) {\n const geometry = new SpiralStaircaseGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n side: DoubleSide,\n }),\n );\n\n this.innerRadius = geometry.innerRadius;\n this.width = geometry.width;\n this.outerRadius = geometry.outerRadius;\n this.treadDepth = geometry.treadDepth;\n this.riserHeight = geometry.riserHeight;\n this.stepCount = geometry.stepCount;\n this.stepAngle = geometry.stepAngle;\n this.totalHeight = geometry.totalHeight;\n this.totalTurn = geometry.totalTurn;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n StaircaseGeometry,\n type StaircaseGeometryOptions,\n} from \"../../geometry/architecture/StaircaseGeometry\";\n\nexport interface StaircaseOptions extends StaircaseGeometryOptions {\n /** Tread and riser tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Straight run staircase prefab — {@link StaircaseGeometry} with a wood-tone\n * default material.\n *\n * Local frame: centered on width, rises along +Y, runs along +Z.\n */\nexport class Staircase extends Mesh<StaircaseGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepCount: number;\n readonly totalHeight: number;\n readonly totalDepth: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: StaircaseOptions = {}) {\n const geometry = new StaircaseGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n // Open shell (no side stringers yet) — same as legacy staircase examples.\n side: DoubleSide,\n }),\n );\n\n this.width = geometry.width;\n this.riserHeight = geometry.riserHeight;\n this.treadDepth = geometry.treadDepth;\n this.stepCount = geometry.stepCount;\n this.totalHeight = geometry.totalHeight;\n this.totalDepth = geometry.totalDepth;\n }\n}","import {\n Color,\n ColorRepresentation,\n DoubleSide,\n Group,\n Mesh,\n MeshPhysicalMaterial,\n MeshStandardMaterial,\n Shape,\n ShapeGeometry,\n} from \"three\";\nimport {\n archedOpeningMetrics,\n buildArchedDiamondLatticeFrameGeometry,\n traceArchedOpeningOutline,\n type ArchedOpeningMetrics,\n type DiamondLatticeGrid,\n} from \"../../geometry/architecture/diamondLattice\";\nimport {\n ArchedDiamondLatticeWindowGeometry,\n type ArchedDiamondLatticeWindowGeometryOptions,\n} from \"../../geometry/architecture/ArchedDiamondLatticeWindowGeometry\";\n\nexport interface ArchedDiamondLatticeWindowOptions extends ArchedDiamondLatticeWindowGeometryOptions {\n /** Lead + outer frame tint. Defaults to `#0c0f14`. */\n leadColor?: ColorRepresentation;\n /** Optional glass pane centered in the lead depth (`z = 0`), visible from both sides. */\n glass?: boolean;\n glassColor?: ColorRepresentation;\n glassEmissive?: ColorRepresentation;\n glassEmissiveIntensity?: number;\n}\n\nconst ARCHED_SHAPE_CURVE_SEGMENTS = 48;\n\n/**\n * Arched diamond lattice window — diagonal lead cames analytically clipped to a\n * Tudor head opening, with an extruded frame ring. The lattice is real trimmed\n * geometry (no stencil mask), so it casts a correct arch-shaped shadow and any\n * collider derived from the mesh matches what's drawn.\n *\n * Local frame: centered on the opening, XY plane facing +Z. Lead is centered on\n * `z = 0`; optional glass sits in the same plane (both faces).\n */\nexport class ArchedDiamondLatticeWindow extends Group {\n readonly lattice: Mesh<ArchedDiamondLatticeWindowGeometry, MeshStandardMaterial>;\n readonly frame: Mesh;\n readonly glass?: Mesh<ShapeGeometry, MeshPhysicalMaterial>;\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n readonly opening: ArchedOpeningMetrics;\n\n constructor({\n leadColor = \"#0c0f14\",\n glass = false,\n glassColor = \"#6a7d8c\",\n glassEmissive,\n glassEmissiveIntensity = 0,\n width = 4.5,\n rectHeight = 4,\n archHeight,\n centerY = 0,\n leadThickness = 0.055,\n leadDepth = 0.11,\n ...geometryOptions\n }: ArchedDiamondLatticeWindowOptions = {}) {\n super();\n\n this.opening = archedOpeningMetrics({ width, rectHeight, archHeight, centerY });\n\n const geometry = new ArchedDiamondLatticeWindowGeometry({\n width,\n rectHeight,\n archHeight,\n centerY,\n leadThickness,\n leadDepth,\n ...geometryOptions,\n });\n this.cellsX = geometry.cellsX;\n this.cellsY = geometry.cellsY;\n this.fittedGrid = geometry.fittedGrid;\n\n const leadColorObj = new Color(leadColor);\n\n if (glass) {\n const openingShape = new Shape();\n traceArchedOpeningOutline(openingShape, this.opening);\n const openingGeo = new ShapeGeometry(openingShape, ARCHED_SHAPE_CURVE_SEGMENTS);\n const glassMaterial = new MeshPhysicalMaterial({\n color: new Color(glassColor),\n emissive: glassEmissive ? new Color(glassEmissive) : new Color(0x000000),\n emissiveIntensity: glassEmissiveIntensity,\n transparent: true,\n depthWrite: false,\n roughness: 0.08,\n metalness: 0,\n transmission: glassEmissive ? 0.5 : 0.88,\n thickness: leadDepth * 0.5,\n side: DoubleSide,\n });\n this.glass = new Mesh(openingGeo, glassMaterial);\n this.glass.renderOrder = 0;\n this.glass.castShadow = false;\n this.glass.receiveShadow = false;\n this.add(this.glass);\n }\n\n const latticeMaterial = new MeshStandardMaterial({\n color: leadColorObj,\n roughness: 0.7,\n metalness: 0.35,\n polygonOffset: true,\n polygonOffsetFactor: -1,\n polygonOffsetUnits: -1,\n });\n\n this.lattice = new Mesh(geometry, latticeMaterial);\n this.lattice.castShadow = true;\n this.lattice.renderOrder = 1;\n this.add(this.lattice);\n\n const frameGeo = buildArchedDiamondLatticeFrameGeometry(\n this.opening,\n leadThickness,\n leadDepth,\n );\n this.frame = new Mesh(\n frameGeo,\n new MeshStandardMaterial({\n color: leadColorObj,\n roughness: 0.7,\n metalness: 0.35,\n }),\n );\n this.frame.castShadow = true;\n this.frame.renderOrder = 2;\n this.add(this.frame);\n }\n}\n","import {\n Color,\n ColorRepresentation,\n DoubleSide,\n Group,\n Mesh,\n MeshPhysicalMaterial,\n MeshStandardMaterial,\n PlaneGeometry,\n} from \"three\";\nimport type { DiamondLatticeGrid } from \"../../geometry/architecture/diamondLattice\";\nimport {\n DiamondLatticeWindowGeometry,\n type DiamondLatticeWindowGeometryOptions,\n} from \"../../geometry/architecture/DiamondLatticeWindowGeometry\";\n\nexport interface DiamondLatticeWindowOptions extends DiamondLatticeWindowGeometryOptions {\n /** Lead + outer frame tint. Defaults to `#0c0f14`. */\n leadColor?: ColorRepresentation;\n /**\n * Optional glass pane centered in the lead depth (`z = 0`), visible from both sides.\n * Mad-science uses an emissive sky mesh in the scene instead.\n */\n glass?: boolean;\n glassColor?: ColorRepresentation;\n /** Glass emissive for moonlit / storm backlight. Defaults to off. */\n glassEmissive?: ColorRepresentation;\n glassEmissiveIntensity?: number;\n}\n\n/**\n * Diamond lattice window — diagonal lead cames with axis-aligned quarrels (`<>`).\n *\n * Local frame: centered on the opening, XY plane facing +Z. Lead is centered on\n * `z = 0`; optional glass sits in the same plane (both faces). Pair with\n * a scene-owned backing plane behind the wall.\n */\nexport class DiamondLatticeWindow extends Group {\n readonly lattice: Mesh<DiamondLatticeWindowGeometry, MeshStandardMaterial>;\n readonly glass?: Mesh<PlaneGeometry, MeshPhysicalMaterial>;\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n\n constructor({\n leadColor = \"#0c0f14\",\n glass = false,\n glassColor = \"#6a7d8c\",\n glassEmissive,\n glassEmissiveIntensity = 0,\n centerY = 0,\n leadDepth = 0.11,\n ...geometryOptions\n }: DiamondLatticeWindowOptions = {}) {\n super();\n\n const geometry = new DiamondLatticeWindowGeometry({\n centerY,\n leadDepth,\n ...geometryOptions,\n });\n this.cellsX = geometry.cellsX;\n this.cellsY = geometry.cellsY;\n this.fittedGrid = geometry.fittedGrid;\n\n const leadMaterial = new MeshStandardMaterial({\n color: new Color(leadColor),\n roughness: 0.7,\n metalness: 0.35,\n polygonOffset: true,\n polygonOffsetFactor: -1,\n polygonOffsetUnits: -1,\n });\n\n this.lattice = new Mesh(geometry, leadMaterial);\n this.lattice.castShadow = true;\n this.lattice.renderOrder = 1;\n this.add(this.lattice);\n\n if (glass) {\n const w = geometryOptions.width ?? 4.5;\n const h = geometryOptions.height ?? 5.5;\n const glassMaterial = new MeshPhysicalMaterial({\n color: new Color(glassColor),\n emissive: glassEmissive ? new Color(glassEmissive) : new Color(0x000000),\n emissiveIntensity: glassEmissiveIntensity,\n transparent: true,\n depthWrite: false,\n roughness: 0.08,\n metalness: 0,\n transmission: glassEmissive ? 0.5 : 0.88,\n thickness: leadDepth * 0.5,\n side: DoubleSide,\n });\n this.glass = new Mesh(new PlaneGeometry(w, h), glassMaterial);\n this.glass.position.y = centerY;\n this.glass.renderOrder = 0;\n this.glass.castShadow = false;\n this.glass.receiveShadow = false;\n this.add(this.glass);\n }\n }\n}","import {\n Color,\n ColorRepresentation,\n DoubleSide,\n Group,\n Mesh,\n MeshPhysicalMaterial,\n MeshStandardMaterial,\n PlaneGeometry,\n} from \"three\";\nimport type { GregorianLatticeGrid } from \"../../geometry/architecture/gregorianLattice\";\nimport {\n GregorianLatticeWindowGeometry,\n type GregorianLatticeWindowGeometryOptions,\n} from \"../../geometry/architecture/GregorianLatticeWindowGeometry\";\n\nexport interface GregorianLatticeWindowOptions extends GregorianLatticeWindowGeometryOptions {\n /** Frame + mullion tint. Defaults to `#5c4033` (wood). */\n mullionColor?: ColorRepresentation;\n /** Optional glass pane coplanar with the mullions (same Z center). */\n glass?: boolean;\n glassColor?: ColorRepresentation;\n glassEmissive?: ColorRepresentation;\n glassEmissiveIntensity?: number;\n}\n\n/**\n * Gregorian lattice window — rectangular pane grid with orthogonal mullions.\n *\n * Local frame: centered on the opening, XY plane facing +Z. Mullions and\n * optional glass share `z = 0`.\n */\nexport class GregorianLatticeWindow extends Group {\n readonly mullions: Mesh<GregorianLatticeWindowGeometry, MeshStandardMaterial>;\n readonly glass?: Mesh<PlaneGeometry, MeshPhysicalMaterial>;\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: GregorianLatticeGrid;\n\n constructor({\n mullionColor = \"#5c4033\",\n glass = false,\n glassColor = \"#6a7d8c\",\n glassEmissive,\n glassEmissiveIntensity = 0,\n ...geometryOptions\n }: GregorianLatticeWindowOptions = {}) {\n super();\n\n const geometry = new GregorianLatticeWindowGeometry(geometryOptions);\n this.cellsX = geometry.cellsX;\n this.cellsY = geometry.cellsY;\n this.fittedGrid = geometry.fittedGrid;\n\n const mullionMaterial = new MeshStandardMaterial({\n color: new Color(mullionColor),\n roughness: 0.85,\n metalness: 0.05,\n });\n\n this.mullions = new Mesh(geometry, mullionMaterial);\n this.mullions.castShadow = true;\n this.mullions.renderOrder = 1;\n this.add(this.mullions);\n\n if (glass) {\n const w = geometryOptions.width ?? 4.5;\n const h = geometryOptions.height ?? 5.5;\n const glassMaterial = new MeshPhysicalMaterial({\n color: new Color(glassColor),\n emissive: glassEmissive ? new Color(glassEmissive) : new Color(0x000000),\n emissiveIntensity: glassEmissiveIntensity,\n transparent: true,\n depthWrite: false,\n roughness: 0.08,\n metalness: 0,\n transmission: glassEmissive ? 0.5 : 0.88,\n thickness: 0.02,\n side: DoubleSide,\n });\n this.glass = new Mesh(new PlaneGeometry(w, h), glassMaterial);\n this.glass.renderOrder = 0;\n this.glass.castShadow = false;\n this.glass.receiveShadow = false;\n this.add(this.glass);\n }\n }\n}","import {\n AlwaysStencilFunc,\n Color,\n ColorRepresentation,\n DoubleSide,\n EqualStencilFunc,\n Group,\n InstancedMesh,\n KeepStencilOp,\n Mesh,\n MeshBasicMaterial,\n MeshPhysicalMaterial,\n MeshStandardMaterial,\n Object3D,\n Plane,\n PlaneGeometry,\n ReplaceStencilOp,\n} from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport {\n buildRingLatticeFrameParts,\n createOpeningClippingPlanes,\n createRingLatticeGeometry,\n resolveRingLatticeCell,\n ringLatticeSpots,\n type RingLatticeGrid,\n} from \"../../geometry/architecture/ringLattice\";\n\nexport interface RingLatticeWindowOptions {\n /** Opening width (world units). */\n width?: number;\n /** Opening height (world units). */\n height?: number;\n /** Uniform ring-center spacing. Overrides `cellsX` when set. Defaults to `0.55`. */\n cell?: number;\n /** Density hint — `cell = width / cellsX` when `cell` is omitted. */\n cellsX?: number;\n /** Wall thickness of each square ring profile. Defaults to `0.05`. */\n ringThickness?: number;\n /** Extrusion depth of each ring. Defaults to `0.06`. */\n ringDepth?: number;\n /** Outer frame bar thickness. Defaults to `0.055`. */\n frameThickness?: number;\n /** Outer frame depth (Z). Defaults to `0.11`. */\n frameDepth?: number;\n /** Vertical center of the opening in local space. Defaults to `0`. */\n centerY?: number;\n /** Lattice + frame tint. Defaults to `#0c0f14`. */\n latticeColor?: ColorRepresentation;\n /** Optional glass pane recessed slightly on −Z. */\n glass?: boolean;\n glassColor?: ColorRepresentation;\n glassEmissive?: ColorRepresentation;\n glassEmissiveIntensity?: number;\n}\n\nconst STENCIL_REF = 1;\n\n/**\n * Ring lattice window — overlapping square rings on a uniform grid (diaper /\n * trellis fretwork), stencil-clipped to a rectangular opening.\n */\nexport class RingLatticeWindow extends Group {\n readonly lattice: InstancedMesh;\n readonly frame: Mesh;\n readonly glass?: Mesh<PlaneGeometry, MeshPhysicalMaterial>;\n readonly cell: number;\n readonly fittedGrid: RingLatticeGrid;\n private readonly clipPlanesLocal: Plane[];\n private readonly clipPlanesWorld: Plane[];\n\n constructor({\n width = 4.5,\n height = 5.5,\n cell: cellOption,\n cellsX,\n centerY = 0,\n ringThickness = 0.05,\n ringDepth = 0.06,\n frameThickness = 0.055,\n frameDepth = 0.11,\n latticeColor = \"#0c0f14\",\n glass = false,\n glassColor = \"#6a7d8c\",\n glassEmissive,\n glassEmissiveIntensity = 0,\n }: RingLatticeWindowOptions = {}) {\n super();\n\n this.cell = resolveRingLatticeCell(width, height, cellOption, cellsX);\n const { spots, grid } = ringLatticeSpots({\n width,\n height,\n centerY,\n cell: this.cell,\n });\n this.fittedGrid = grid;\n this.clipPlanesLocal = createOpeningClippingPlanes(width, height, centerY);\n this.clipPlanesWorld = this.clipPlanesLocal.map((plane) => plane.clone());\n\n if (glass) {\n const glassMaterial = new MeshPhysicalMaterial({\n color: new Color(glassColor),\n emissive: glassEmissive ? new Color(glassEmissive) : new Color(0x000000),\n emissiveIntensity: glassEmissiveIntensity,\n transparent: true,\n depthWrite: false,\n roughness: 0.08,\n metalness: 0,\n transmission: glassEmissive ? 0.5 : 0.88,\n thickness: 0.02,\n side: DoubleSide,\n });\n this.glass = new Mesh(new PlaneGeometry(width, height), glassMaterial);\n this.glass.position.y = centerY;\n this.glass.position.z = -ringDepth * 0.5;\n this.glass.renderOrder = 0;\n this.add(this.glass);\n }\n\n const mask = new Mesh(\n new PlaneGeometry(width, height),\n new MeshBasicMaterial({\n colorWrite: false,\n depthWrite: false,\n depthTest: false,\n stencilWrite: true,\n stencilRef: STENCIL_REF,\n stencilFunc: AlwaysStencilFunc,\n stencilFail: KeepStencilOp,\n stencilZPass: ReplaceStencilOp,\n stencilZFail: KeepStencilOp,\n }),\n );\n mask.position.y = centerY;\n mask.renderOrder = 1;\n this.add(mask);\n\n const ringGeo = createRingLatticeGeometry(grid.ringOuter, ringThickness, ringDepth);\n const latticeMaterial = new MeshStandardMaterial({\n color: new Color(latticeColor),\n roughness: 0.7,\n metalness: 0.35,\n clippingPlanes: this.clipPlanesWorld,\n clipShadows: true,\n stencilWrite: true,\n stencilWriteMask: 0x00,\n stencilRef: STENCIL_REF,\n stencilFunc: EqualStencilFunc,\n stencilFail: KeepStencilOp,\n stencilZPass: KeepStencilOp,\n stencilZFail: KeepStencilOp,\n });\n\n this.lattice = new InstancedMesh(ringGeo, latticeMaterial, spots.length);\n this.lattice.castShadow = true;\n this.lattice.renderOrder = 2;\n\n const dummy = new Object3D();\n for (let i = 0; i < spots.length; i++) {\n dummy.position.set(spots[i][0], spots[i][1], 0);\n dummy.rotation.set(0, 0, Math.PI / 4);\n dummy.updateMatrix();\n this.lattice.setMatrixAt(i, dummy.matrix);\n }\n this.lattice.instanceMatrix.needsUpdate = true;\n this.lattice.onBeforeRender = () => {\n this.updateWorldMatrix(true, false);\n for (let i = 0; i < this.clipPlanesLocal.length; i++) {\n this.clipPlanesWorld[i].copy(this.clipPlanesLocal[i]).applyMatrix4(this.matrixWorld);\n }\n };\n this.add(this.lattice);\n\n const frameParts = buildRingLatticeFrameParts({\n width,\n height,\n centerY,\n frameThickness,\n frameDepth,\n });\n const frameGeo = mergeGeometries(frameParts);\n if (!frameGeo) throw new Error(\"RingLatticeWindow: frame merge failed\");\n for (const part of frameParts) part.dispose();\n\n this.frame = new Mesh(\n frameGeo,\n new MeshStandardMaterial({\n color: new Color(latticeColor),\n roughness: 0.7,\n metalness: 0.35,\n }),\n );\n this.frame.castShadow = true;\n this.frame.renderOrder = 3;\n this.add(this.frame);\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { BookGeometry, type BookGeometryOptions } from \"../../geometry/books/BookGeometry\";\n\nexport interface BookOptions extends BookGeometryOptions {\n /** Cover tint. Defaults to `#8b0000`. */\n coverColor?: ColorRepresentation;\n /** Page block tint. Defaults to `#ffffff`. */\n pageColor?: ColorRepresentation;\n}\n\n/**\n * Book prefab — cover shell and page block with separate material groups.\n *\n * Local frame: spine at X=0, fore-edge at +X, sits on the Y=0 plane.\n */\nexport class Book extends Mesh<BookGeometry, MeshStandardMaterial[]> {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n readonly coverThickness: number;\n readonly pageIndent: number;\n\n constructor({\n coverColor = \"#8b0000\",\n pageColor = \"#ffffff\",\n ...geometryOptions\n }: BookOptions = {}) {\n const geometry = new BookGeometry(geometryOptions);\n\n super(geometry, [\n new MeshStandardMaterial({\n color: new Color(coverColor),\n metalness: 0.1,\n roughness: 0.7,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(pageColor),\n flatShading: true,\n }),\n ]);\n\n this.width = geometry.width;\n this.height = geometry.height;\n this.depth = geometry.depth;\n this.coverThickness = geometry.coverThickness;\n this.pageIndent = geometry.pageIndent;\n }\n}","import { DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { JarGeometry } from \"../../geometry/bottles/JarGeometry\";\n\n/**\n * Material indices\n * 0. Jar\n * 1. Cork\n */\nexport class Jar extends Mesh<JarGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new JarGeometry(), [\n new MeshStandardMaterial({\n color: 0x88ccaa,\n transparent: true,\n depthWrite: false,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.5,\n side: DoubleSide,\n }),\n new MeshStandardMaterial({\n color: 0x8b4513,\n roughness: 1.0,\n }),\n ]);\n }\n}\n","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { ColorPalette } from \"../../constants/ColorPalette\";\nimport { PotionBottleGeometry } from \"../../geometry/bottles/PotionBottleGeometry\";\n\n/**\n * Potion bottle, with optional liquid fill\n *\n * Material indices\n * 0. Bottle\n * 1. Cork\n * 2. Liquid (optional)\n */\nexport class PotionBottle extends Mesh<PotionBottleGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new PotionBottleGeometry(), [\n new MeshStandardMaterial({\n color: 0x88ccff,\n transparent: true,\n depthWrite: false,\n opacity: 0.5,\n roughness: 0.1,\n metalness: 0.3,\n }),\n new MeshStandardMaterial({\n color: 0x8b4513,\n roughness: 1.0,\n }),\n new MeshStandardMaterial({\n color: ColorPalette.PINK_SHERBET,\n transparent: true,\n depthWrite: false,\n opacity: 0.5,\n }),\n ]);\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshPhysicalMaterial } from \"three\";\nimport { WineBottleGeometry, type WineBottleGeometryOptions } from \"../../geometry/bottles/WineBottleGeometry\";\n\nexport interface WineBottleOptions extends WineBottleGeometryOptions {\n /** Glass tint. Defaults to `#556b2f`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Wine bottle prefab — translucent green glass.\n */\nexport class WineBottle extends Mesh<WineBottleGeometry, MeshPhysicalMaterial> {\n constructor({ color = \"#556b2f\", ...geometryOptions }: WineBottleOptions = {}) {\n super(\n new WineBottleGeometry(geometryOptions),\n new MeshPhysicalMaterial({\n color: new Color(color),\n roughness: 0.1,\n transmission: 0.9,\n thickness: 0.2,\n metalness: 0,\n clearcoat: 1.0,\n clearcoatRoughness: 0.1,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n CrossHeadstoneGeometry,\n type CrossHeadstoneGeometryOptions,\n} from \"../../geometry/cemetery/CrossHeadstoneGeometry\";\n\nexport interface CrossHeadstoneOptions extends CrossHeadstoneGeometryOptions {\n /** Stone tint. Defaults to `#777777`. */\n color?: ColorRepresentation;\n /** Surface roughness. Defaults to `0.8`. */\n roughness?: number;\n}\n\n/**\n * Cross headstone prefab.\n */\nexport class CrossHeadstone extends Mesh<CrossHeadstoneGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly height: number;\n\n constructor({ color = \"#777777\", roughness = 0.8, ...geometryOptions }: CrossHeadstoneOptions = {}) {\n const geometry = new CrossHeadstoneGeometry(geometryOptions);\n\n super(geometry, new MeshStandardMaterial({ color: new Color(color), roughness }));\n\n this.width = geometry.width;\n this.height = geometry.height;\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { MausoleumGeometry } from \"../../geometry/cemetery/MausoleumGeometry\";\n\n/**\n * Material indices:\n * 0. Base\n * 1. Building\n * 2. Roof\n * 3. Arched entrance\n */\nexport class Mausoleum extends Mesh<MausoleumGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(\n new MausoleumGeometry(),\n [\n new MeshStandardMaterial({ color: 0x808080, flatShading: true }), // Base\n new MeshStandardMaterial({ color: 0x696969, flatShading: true }), // Building\n new MeshStandardMaterial({ color: 0x505050, flatShading: true }), // Roof\n new MeshStandardMaterial({ color: 0x404040, flatShading: true }), // Arched entrance\n ],\n );\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n ObeliskHeadstoneGeometry,\n type ObeliskHeadstoneGeometryOptions,\n} from \"../../geometry/cemetery/ObeliskHeadstoneGeometry\";\n\nexport interface ObeliskHeadstoneOptions extends ObeliskHeadstoneGeometryOptions {\n /** Stone tint. Defaults to `#777777`. */\n color?: ColorRepresentation;\n /** Surface roughness. Defaults to `0.8`. */\n roughness?: number;\n}\n\n/**\n * Obelisk headstone prefab.\n */\nexport class ObeliskHeadstone extends Mesh<ObeliskHeadstoneGeometry, MeshStandardMaterial> {\n readonly totalHeight: number;\n\n constructor({ color = \"#777777\", roughness = 0.8, ...geometryOptions }: ObeliskHeadstoneOptions = {}) {\n const geometry = new ObeliskHeadstoneGeometry(geometryOptions);\n\n super(geometry, new MeshStandardMaterial({ color: new Color(color), roughness }));\n\n this.totalHeight = geometry.totalHeight;\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { RoundedHeadstoneGeometry } from \"../../geometry/cemetery/RoundedHeadstoneGeometry\";\n\nexport class RoundedHeadstone extends Mesh<RoundedHeadstoneGeometry, MeshStandardMaterial> {\n constructor(width = 0.6, height = 1.0, depth = 0.2, radius = 0.6) {\n super(\n new RoundedHeadstoneGeometry(width, height, depth, radius),\n new MeshStandardMaterial({ color: 0x777777, roughness: 0.8 })\n );\n }\n}\n","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { SquareHeadstoneGeometry } from \"../../geometry/cemetery/SquareHeadstoneGeometry\";\n\nexport class SquareHeadstone extends Mesh<SquareHeadstoneGeometry, MeshStandardMaterial> {\n constructor(width = 0.5, height = 0.8, depth = 0.15) {\n super(\n new SquareHeadstoneGeometry(width, height, depth),\n new MeshStandardMaterial({ color: 0x777777, roughness: 0.8 })\n );\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n StoneFencePostGeometry,\n type StoneFencePostGeometryOptions,\n} from \"../../geometry/fence/StoneFencePostGeometry\";\n\nexport interface StoneFencePostOptions extends StoneFencePostGeometryOptions {\n /** Stone tint. Defaults to `#8b7d7b`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Stone fence post prefab.\n */\nexport class StoneFencePost extends Mesh<StoneFencePostGeometry, MeshStandardMaterial> {\n readonly height: number;\n\n constructor({ color = \"#8b7d7b\", ...geometryOptions }: StoneFencePostOptions = {}) {\n const geometry = new StoneFencePostGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({ color: new Color(color), flatShading: true }),\n );\n\n this.height = geometry.height;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n WroughtIronBarGeometry,\n type WroughtIronBarGeometryOptions,\n} from \"../../geometry/fence/WroughtIronBarGeometry\";\n\nexport interface WroughtIronBarOptions extends WroughtIronBarGeometryOptions {\n /** Iron tint. Defaults to `#333333`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Wrought-iron fence post prefab.\n */\nexport class WroughtIronBar extends Mesh<WroughtIronBarGeometry, MeshStandardMaterial> {\n readonly barHeight: number;\n\n constructor({ color = \"#333333\", ...geometryOptions }: WroughtIronBarOptions = {}) {\n const geometry = new WroughtIronBarGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n metalness: 0.8,\n roughness: 0.4,\n }),\n );\n\n this.barHeight = geometry.barHeight;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n WroughtIronFenceGeometry,\n type WroughtIronFenceGeometryOptions,\n} from \"../../geometry/fence/WroughtIronFenceGeometry\";\n\nexport interface WroughtIronFenceOptions extends WroughtIronFenceGeometryOptions {\n /** Iron tint. Defaults to `#333333`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Wrought-iron fence run prefab.\n */\nexport class WroughtIronFence extends Mesh<WroughtIronFenceGeometry, MeshStandardMaterial> {\n readonly count: number;\n\n constructor({ color = \"#333333\", ...geometryOptions }: WroughtIronFenceOptions = {}) {\n const geometry = new WroughtIronFenceGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n metalness: 0.8,\n roughness: 0.4,\n }),\n );\n\n this.count = geometry.count;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { BookshelfGeometry, type BookshelfGeometryOptions } from \"../../geometry/furniture/BookshelfGeometry\";\n\nexport interface BookshelfOptions extends BookshelfGeometryOptions {\n /** Frame tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Bookshelf prefab — framed shelving unit.\n */\nexport class Bookshelf extends Mesh<BookshelfGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly height: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: BookshelfOptions = {}) {\n const geometry = new BookshelfGeometry(geometryOptions);\n\n super(geometry, new MeshStandardMaterial({ color: new Color(color) }));\n\n this.width = geometry.width;\n this.height = geometry.height;\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { DeskGeometry } from \"../../geometry/furniture/DeskGeometry\";\n\n/**\n * Material indices:\n * 0. Desk surface\n * 1. Desk legs\n */\nexport class Desk extends Mesh<DeskGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new DeskGeometry(), [\n new MeshStandardMaterial({ color: 0x8b5a2b }), // Desk surface\n new MeshStandardMaterial({ color: 0x4b3621 }), // Desk legs\n ]);\n }\n}\n","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { LeafGeometry, type LeafGeometryOptions } from \"../../geometry/leafs/LeafGeometry\";\n\nexport interface LeafOptions extends LeafGeometryOptions {\n /** Leaf tint. Defaults to `#a8702c`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Folded autumn leaf prefab — {@link LeafGeometry} with flat-shaded double-sided\n * material matching the graveyard blowing-leaves look.\n *\n * Local frame: tip at +Y, base at −Y, fold rises along +Z.\n */\nexport class Leaf extends Mesh<LeafGeometry, MeshStandardMaterial> {\n readonly size: number;\n readonly lift: number;\n\n constructor({ color = \"#a8702c\", ...geometryOptions }: LeafOptions = {}) {\n const geometry = new LeafGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.05,\n flatShading: true,\n side: DoubleSide,\n }),\n );\n\n this.size = geometry.size;\n this.lift = geometry.lift;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { CandleGeometry, type CandleGeometryOptions } from \"../../geometry/lighting/CandleGeometry\";\n\nexport interface CandleOptions extends CandleGeometryOptions {\n /** Wax stick tint. Defaults to `#ffffff`. */\n stickColor?: ColorRepresentation;\n /** Flame surface tint. Defaults to `#ffd700`. */\n flameColor?: ColorRepresentation;\n /** Flame emissive tint. Defaults to `#ffa500`. */\n flameEmissive?: ColorRepresentation;\n /** Flame emissive strength. Defaults to `0.35`. */\n flameEmissiveIntensity?: number;\n}\n\n/**\n * Candle prefab — wax stick and emissive flame (separate material groups).\n */\nexport class Candle extends Mesh<CandleGeometry, MeshStandardMaterial[]> {\n readonly height: number;\n\n constructor({\n stickColor = \"#ffffff\",\n flameColor = \"#ffd700\",\n flameEmissive = \"#ffa500\",\n flameEmissiveIntensity = 0.35,\n ...geometryOptions\n }: CandleOptions = {}) {\n const geometry = new CandleGeometry(geometryOptions);\n\n super(geometry, [\n new MeshStandardMaterial({ color: new Color(stickColor), flatShading: true }),\n new MeshStandardMaterial({\n color: new Color(flameColor),\n emissive: new Color(flameEmissive),\n emissiveIntensity: flameEmissiveIntensity,\n flatShading: true,\n toneMapped: false,\n }),\n ]);\n\n this.height = geometry.height;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { FlameGeometry, type FlameGeometryOptions } from \"../../geometry/lighting/FlameGeometry\";\n\nexport interface FlameOptions extends FlameGeometryOptions {\n /** Surface tint. Defaults to `#ffd700`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffa500`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.35`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Emissive flame prefab — parametric teardrop volume for candles and lanterns.\n *\n * Local frame: base at Y=0, tip at Y=`height`.\n */\nexport class Flame extends Mesh<FlameGeometry, MeshStandardMaterial> {\n readonly height: number;\n readonly radius: number;\n readonly segmentsU: number;\n readonly segmentsV: number;\n\n constructor({\n color = \"#ffd700\",\n emissive = \"#ffa500\",\n emissiveIntensity = 0.35,\n ...geometryOptions\n }: FlameOptions = {}) {\n const geometry = new FlameGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n flatShading: true,\n toneMapped: false,\n }),\n );\n\n this.height = geometry.height;\n this.radius = geometry.radius;\n this.segmentsU = geometry.segmentsU;\n this.segmentsV = geometry.segmentsV;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n HangingLanternGeometry,\n type HangingLanternGeometryOptions,\n} from \"../../geometry/lighting/HangingLanternGeometry\";\n\nexport interface HangingLanternOptions extends HangingLanternGeometryOptions {\n /** Wrought-iron tint for mount and cage. Defaults to `#171a1f`. */\n color?: ColorRepresentation;\n /** Mount iron tint (chain + cap). Defaults to `color`. */\n mountColor?: ColorRepresentation;\n /** Cage strut tint. Defaults to `color`. */\n cageColor?: ColorRepresentation;\n /** Inner lamp tint (emissive octahedron). Defaults to `#ffb45a`. */\n lampColor?: ColorRepresentation;\n /** Inner lamp emissive strength. Defaults to `1.4`. */\n lampEmissiveIntensity?: number;\n /** Inner lamp opacity for a glass-pane read. Defaults to `0.88`. */\n lampOpacity?: number;\n}\n\n/**\n * Hanging wrought-iron lantern — open cage struts around a solid emissive\n * inner octahedron (glass-pane lamp). Mount, cage, and lamp use separate\n * material groups. Pair {@link GlowHalo} and {@link FlameFlickerEffect} at\n * `cageCenterY` for bloom and flicker.\n *\n * Local frame: origin at the chain top (hang point).\n */\nexport class HangingLantern extends Mesh<HangingLanternGeometry, MeshStandardMaterial[]> {\n readonly drop: number;\n readonly cageCenterY: number;\n\n constructor({\n color = \"#171a1f\",\n mountColor,\n cageColor,\n lampColor = \"#ffb45a\",\n lampEmissiveIntensity = 1.4,\n lampOpacity = 0.88,\n inner = true,\n ...geometryOptions\n }: HangingLanternOptions = {}) {\n const geometry = new HangingLanternGeometry({ inner, ...geometryOptions });\n const lamp = new Color(lampColor);\n\n const materials: MeshStandardMaterial[] = [\n new MeshStandardMaterial({\n color: new Color(mountColor ?? color),\n metalness: 0.7,\n roughness: 0.5,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(cageColor ?? color),\n metalness: 0.7,\n roughness: 0.5,\n flatShading: true,\n }),\n ];\n\n if (inner) {\n materials.push(\n new MeshStandardMaterial({\n color: lamp,\n emissive: lamp,\n emissiveIntensity: lampEmissiveIntensity,\n transparent: lampOpacity < 1,\n opacity: lampOpacity,\n roughness: 0.35,\n metalness: 0,\n flatShading: true,\n side: DoubleSide,\n toneMapped: false,\n }),\n );\n }\n\n super(geometry, materials);\n\n this.drop = geometry.drop;\n this.cageCenterY = geometry.cageCenterY;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n WallSconceGeometry,\n type WallSconceGeometryOptions,\n} from \"../../geometry/lighting/WallSconceGeometry\";\n\nexport interface WallSconceOptions extends WallSconceGeometryOptions {\n /** Wrought-iron tint for mount and frame. Defaults to `#1c1e24`. */\n color?: ColorRepresentation;\n /** Mount iron tint (plate + bracket). Defaults to `color`. */\n mountColor?: ColorRepresentation;\n /** Frame iron tint (cap + bowl). Defaults to `color`. */\n frameColor?: ColorRepresentation;\n /** Glass chimney tint. Defaults to `#e8a058`. */\n lampColor?: ColorRepresentation;\n /** Glass emissive strength. Defaults to `1.4`. */\n lampEmissiveIntensity?: number;\n /** Glass opacity. Defaults to `0.88`. */\n lampOpacity?: number;\n}\n\n/**\n * Wall-mounted oil-lamp sconce — iron mount and cap/bowl frame around an\n * emissive glass chimney. Pair {@link GlowHalo} and {@link FlameFlickerEffect}\n * at `(lightCenterX, lightCenterY, lightCenterZ)` for bloom and flicker.\n *\n * Local frame: faces +X from a −X wall.\n */\nexport class WallSconce extends Mesh<WallSconceGeometry, MeshStandardMaterial[]> {\n readonly lightCenterX: number;\n readonly lightCenterY: number;\n readonly lightCenterZ: number;\n\n constructor({\n color = \"#1c1e24\",\n mountColor,\n frameColor,\n lampColor = \"#e8a058\",\n lampEmissiveIntensity = 1.4,\n lampOpacity = 0.88,\n inner = true,\n ...geometryOptions\n }: WallSconceOptions = {}) {\n const geometry = new WallSconceGeometry({ inner, ...geometryOptions });\n const lamp = new Color(lampColor);\n\n const materials: MeshStandardMaterial[] = [\n new MeshStandardMaterial({\n color: new Color(mountColor ?? color),\n metalness: 0.65,\n roughness: 0.55,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(frameColor ?? color),\n metalness: 0.65,\n roughness: 0.55,\n flatShading: true,\n }),\n ];\n\n if (inner) {\n materials.push(\n new MeshStandardMaterial({\n color: lamp,\n emissive: lamp,\n emissiveIntensity: lampEmissiveIntensity,\n transparent: lampOpacity < 1,\n opacity: lampOpacity,\n roughness: 0.35,\n metalness: 0,\n flatShading: true,\n side: DoubleSide,\n toneMapped: false,\n }),\n );\n }\n\n super(geometry, materials);\n\n this.lightCenterX = geometry.lightCenterX;\n this.lightCenterY = geometry.lightCenterY;\n this.lightCenterZ = geometry.lightCenterZ;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { LanternGeometry, type LanternGeometryOptions } from \"../../geometry/lighting/LanternGeometry\";\n\nexport interface LanternOptions extends LanternGeometryOptions {\n /** Frame tint (base, roof, handle). Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n /** Glass lamp tint. Defaults to `#ffd700`. */\n lampColor?: ColorRepresentation;\n /** Glass emissive strength. Defaults to `1.2`. */\n lampEmissiveIntensity?: number;\n /** Glass opacity. Defaults to `0.75`. */\n lampOpacity?: number;\n}\n\n/**\n * Tabletop lantern — frame around an emissive glass body. Geometry only; add\n * {@link GlowHalo} and {@link FlameFlickerEffect} at `lampCenterY` in the\n * scene.\n *\n * Local frame: sits on the Y=0 plane.\n */\nexport class Lantern extends Mesh<LanternGeometry, MeshStandardMaterial[]> {\n readonly lampCenterY: number;\n\n constructor({\n color = \"#8b4513\",\n lampColor = \"#ffd700\",\n lampEmissiveIntensity = 1.2,\n lampOpacity = 0.75,\n inner = true,\n ...geometryOptions\n }: LanternOptions = {}) {\n\n const geometry = new LanternGeometry({ inner, ...geometryOptions });\n const lamp = new Color(lampColor);\n\n const materials: MeshStandardMaterial[] = [\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n flatShading: true,\n }),\n ];\n\n if (inner) {\n materials.push(\n new MeshStandardMaterial({\n color: lamp,\n emissive: lamp,\n emissiveIntensity: lampEmissiveIntensity,\n transparent: lampOpacity < 1,\n opacity: lampOpacity,\n roughness: 0.35,\n metalness: 0,\n flatShading: true,\n side: DoubleSide,\n toneMapped: false,\n }),\n );\n }\n\n super(geometry, materials);\n\n this.lampCenterY = geometry.lampCenterY;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { MossyRockGeometry, type MossyRockGeometryOptions } from \"../../geometry/rocks/MossyRockGeometry\";\n\nexport interface MossyRockOptions extends MossyRockGeometryOptions {\n /** Rock tint. Defaults to `#808080`. */\n rockColor?: ColorRepresentation;\n /** Moss tint. Defaults to `#4b8b3b`. */\n mossColor?: ColorRepresentation;\n /** Moss opacity. Defaults to `0.8`. */\n mossOpacity?: number;\n}\n\n/**\n * Mossy rock prefab — grey stone with a translucent green moss shell.\n *\n * Material groups: `0` rock, `1` moss.\n */\nexport class MossyRock extends Mesh<MossyRockGeometry, MeshStandardMaterial[]> {\n constructor({\n rockColor = \"#808080\",\n mossColor = \"#4b8b3b\",\n mossOpacity = 0.8,\n ...geometryOptions\n }: MossyRockOptions = {}) {\n super(new MossyRockGeometry(geometryOptions), [\n new MeshStandardMaterial({ color: new Color(rockColor), flatShading: true }),\n new MeshStandardMaterial({\n color: new Color(mossColor),\n flatShading: true,\n opacity: mossOpacity,\n transparent: mossOpacity < 1,\n }),\n ]);\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { RockGeometry, type RockGeometryOptions } from \"../../geometry/rocks/RockGeometry\";\n\nexport interface RockOptions extends RockGeometryOptions {\n /** Stone tint. Defaults to `#808080`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Single rock prefab — noisy sphere mesh.\n */\nexport class Rock extends Mesh<RockGeometry, MeshStandardMaterial> {\n constructor({ color = \"#808080\", ...geometryOptions }: RockOptions = {}) {\n super(\n new RockGeometry(geometryOptions),\n new MeshStandardMaterial({ color: new Color(color), flatShading: true }),\n );\n }\n}","import { ConeGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial } from \"three\";\n\nclass BunsenBurner extends Group {\n constructor() {\n super();\n\n // Base geometry\n const baseGeometry = new CylinderGeometry(0.3, 0.4, 0.1, 16);\n const baseMaterial = new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.6,\n metalness: 0.3,\n });\n const base = new Mesh(baseGeometry, baseMaterial);\n base.position.y = 0.05;\n\n // Burner tube geometry\n const tubeGeometry = new CylinderGeometry(0.1, 0.1, 0.7, 16);\n const tubeMaterial = new MeshStandardMaterial({\n color: 0x555555,\n roughness: 0.5,\n metalness: 0.4,\n });\n const tube = new Mesh(tubeGeometry, tubeMaterial);\n tube.position.y = 0.4;\n\n // Flame geometry\n const flameGeometry = new ConeGeometry(0.075, 0.2, 16);\n const flameMaterial = new MeshStandardMaterial({\n color: 0xff5500,\n emissive: 0xff5500,\n emissiveIntensity: 0.6,\n transparent: true,\n opacity: 0.8,\n });\n const flame = new Mesh(flameGeometry, flameMaterial);\n flame.position.y = 0.8;\n\n this.add(base, tube, flame);\n }\n}\n\nexport { BunsenBurner };\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial, SphereGeometry } from \"three\";\n\nclass ElectricPanel extends Group {\n constructor() {\n super();\n\n const panelGeometry = new BoxGeometry(3, 4, 0.1);\n const panelMaterial = new MeshStandardMaterial({\n color: 0x2e2e2e,\n roughness: 0.8,\n metalness: 0.6,\n });\n\n const switchGeometry = new BoxGeometry(0.2, 0.5, 0.2);\n const switchMaterial = new MeshStandardMaterial({\n color: 0xaaaaaa,\n roughness: 0.5,\n metalness: 0.7,\n });\n\n const dialGeometry = new CylinderGeometry(0.3, 0.3, 0.1, 16);\n const dialMaterial = new MeshStandardMaterial({\n color: 0x555555,\n roughness: 0.7,\n metalness: 0.5,\n });\n\n const panel = new Mesh(panelGeometry, panelMaterial);\n\n for (let i = -1; i <= 1; i++) {\n const toggleSwitch = new Mesh(switchGeometry, switchMaterial);\n toggleSwitch.position.set(i, 1.5, 0.1);\n panel.add(toggleSwitch);\n }\n\n const dial = new Mesh(dialGeometry, dialMaterial);\n dial.rotation.x = Math.PI / 2;\n dial.position.set(0, 0.5, 0.15);\n panel.add(dial);\n\n const lightGeometry = new SphereGeometry(0.15, 8, 8);\n const lightMaterial = new MeshStandardMaterial({\n color: 0xff0000,\n emissive: 0xff0000,\n emissiveIntensity: 0.5,\n });\n const light = new Mesh(lightGeometry, lightMaterial);\n light.position.set(0, -1, 0.1);\n panel.add(light);\n\n this.add(panel);\n }\n}\n\nexport { ElectricPanel };","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshPhysicalMaterial } from \"three\";\nimport {\n ErlenmeyerFlaskGeometry,\n type ErlenmeyerFlaskGeometryOptions,\n} from \"../../geometry/science/ErlenmeyerFlaskGeometry\";\n\nexport interface ErlenmeyerFlaskOptions extends ErlenmeyerFlaskGeometryOptions {\n /** Glass tint. Defaults to `#88ccff`. */\n color?: ColorRepresentation;\n /** Glass opacity. Defaults to `0.4`. */\n opacity?: number;\n}\n\n/**\n * Erlenmeyer flask prefab — translucent glass vessel.\n */\nexport class ErlenmeyerFlask extends Mesh<ErlenmeyerFlaskGeometry, MeshPhysicalMaterial> {\n constructor({\n color = \"#88ccff\",\n opacity = 0.4,\n ...geometryOptions\n }: ErlenmeyerFlaskOptions = {}) {\n super(\n new ErlenmeyerFlaskGeometry(geometryOptions),\n new MeshPhysicalMaterial({\n color: new Color(color),\n transparent: true,\n opacity,\n roughness: 0.1,\n metalness: 0.1,\n reflectivity: 0.8,\n transmission: 0.9,\n side: DoubleSide,\n }),\n );\n }\n}","import { FlorenceFlaskGeometry } from \"../../geometry/science/FlorenceFlaskGeometry\";\nimport { DoubleSide, Mesh, MeshPhysicalMaterial } from \"three\";\n\nexport class FlorenceFlask extends Mesh<FlorenceFlaskGeometry, MeshPhysicalMaterial> {\n constructor() {\n super(\n new FlorenceFlaskGeometry(),\n new MeshPhysicalMaterial({\n color: 0x88ccff,\n transparent: true,\n depthWrite: false,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.1,\n reflectivity: 0.8,\n transmission: 0.9,\n side: DoubleSide,\n }),\n );\n }\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial, SphereGeometry } from \"three\";\n\nclass LeverPanel extends Group {\n constructor() {\n super();\n\n // New panel for levers\n const leverPanelGeometry = new BoxGeometry(2, 3, 0.1);\n const leverPanelMaterial = new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.8,\n metalness: 0.5,\n });\n const leverPanel = new Mesh(leverPanelGeometry, leverPanelMaterial);\n\n // Lever geometry\n const leverBaseGeometry = new CylinderGeometry(0.1, 0.1, 0.2, 8);\n const leverHandleGeometry = new CylinderGeometry(0.05, 0.05, 1, 8);\n\n // Lever material\n const leverMaterial = new MeshStandardMaterial({\n color: 0xaaaaaa,\n roughness: 0.5,\n metalness: 0.7,\n });\n\n // Create multiple levers\n const levers = [];\n for (let i = -0.5; i <= 0.5; i += 0.5) {\n // Lever base\n const leverBase = new Mesh(leverBaseGeometry, leverMaterial);\n leverBase.position.set(i, 1, 0.1);\n\n // Lever handle\n const leverHandle = new Mesh(leverHandleGeometry, leverMaterial);\n leverHandle.position.y = 0.5; // Position handle on top of the base\n // leverHandle.rotation.x = Math.PI / 4; // Tilt forward along the x-axis\n leverBase.add(leverHandle);\n\n // Group base and handle as a lever\n levers.push(leverHandle);\n this.add(leverBase);\n }\n\n // Position the panel in the scene\n this.add(leverPanel);\n }\n}\n\nexport { LeverPanel };\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial } from \"three\";\n\nclass Microscope extends Group {\n constructor() {\n super();\n\n // Base geometry\n const baseGeometry = new BoxGeometry(1, 0.2, 0.5);\n const baseMaterial = new MeshStandardMaterial({\n color: 0x444444,\n roughness: 0.6,\n metalness: 0.3,\n });\n const base = new Mesh(baseGeometry, baseMaterial);\n base.position.y = 0.1;\n\n // Arm geometry\n const armGeometry = new BoxGeometry(0.2, 1, 0.2);\n const arm = new Mesh(armGeometry, baseMaterial);\n arm.position.set(0, 0.6, -0.2);\n\n // Eyepiece geometry\n const eyepieceGeometry = new CylinderGeometry(0.1, 0.1, 0.4, 8);\n const eyepieceMaterial = new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.5,\n metalness: 0.6,\n });\n const eyepiece = new Mesh(eyepieceGeometry, eyepieceMaterial);\n eyepiece.position.set(0, 1.1, -0.35);\n eyepiece.rotation.x = -Math.PI / 4; // Angle the eyepiece for viewing\n\n // Stage geometry\n const stageGeometry = new BoxGeometry(0.6, 0.1, 0.6);\n const stageMaterial = new MeshStandardMaterial({\n color: 0x555555,\n roughness: 0.8,\n metalness: 0.2,\n });\n const stage = new Mesh(stageGeometry, stageMaterial);\n stage.position.set(0, 0.6, 0);\n\n // Assemble microscope\n this.add(base, arm, eyepiece, stage);\n }\n}\n\nexport { Microscope };\n","import { CylinderGeometry, DoubleSide, Group, Mesh, MeshStandardMaterial } from \"three\";\nimport { MortarGeometry } from \"../../geometry/science/MortarGeometry\";\n\nclass MortarAndPestle extends Group {\n constructor() {\n super();\n\n // Mortar geometry\n const mortarGeometry = new MortarGeometry();\n\n // Pestle geometry\n const pestleGeometry = new CylinderGeometry(0.2, 0.3, 1.5, 8);\n pestleGeometry.translate(0, 0.75, 0); // Offset to make the end rounded\n\n // Materials\n const mortarMaterial = new MeshStandardMaterial({\n color: 0x5c4033, // Dark earthy tone\n roughness: 1.0,\n metalness: 0.0,\n side: DoubleSide, // Render inside and outside\n });\n\n const pestleMaterial = new MeshStandardMaterial({\n color: 0x8b5a2b, // Slightly lighter earthy color\n roughness: 0.8,\n metalness: 0.1,\n });\n\n // Meshes\n const mortar = new Mesh(mortarGeometry, mortarMaterial);\n mortar.castShadow = true;\n const pestle = new Mesh(pestleGeometry, pestleMaterial);\n pestle.castShadow = true;\n\n // Position and rotate the pestle to rest in the mortar\n pestle.position.set(0.3, 1.3, 0);\n pestle.rotation.z = Math.PI / 4;\n\n // Group for easy manipulation\n this.add(mortar, pestle);\n }\n}\n\nexport { MortarAndPestle };\n","import { BoxGeometry, Mesh, MeshStandardMaterial } from \"three\";\n\nexport interface PanelOptions {\n width?: number;\n height?: number;\n depth?: number;\n}\n\n/**\n * Prefab for a panel.\n * Designed to be used as a control panel for switches, lights, levels, dials, and gauges.\n */\nexport class Panel extends Mesh {\n public geometry: BoxGeometry;\n public material: MeshStandardMaterial;\n\n constructor({ width = 3, height = 4, depth = 0.1 }: PanelOptions = {}) {\n super();\n\n this.geometry = new BoxGeometry(width, height, depth);\n this.material = new MeshStandardMaterial({\n color: 0x2e2e2e,\n roughness: 0.8,\n metalness: 0.6,\n });\n }\n}\n","import { Mesh, MeshStandardMaterial, SphereGeometry } from \"three\";\n\nexport interface PanelLightOptions {\n radius?: number;\n color?: number;\n emissive?: number;\n emissiveIntensity?: number;\n}\n\n/**\n * Prefab for a panel light.\n * Designed to appear as a LED light\n */\nexport class PanelLight extends Mesh {\n public geometry: SphereGeometry;\n public material: MeshStandardMaterial;\n\n constructor({\n radius = 0.15, //\n color = 0xffc7c7,\n emissive = 0xff0000,\n emissiveIntensity = 0.5,\n }: PanelLightOptions = {}) {\n super();\n\n this.geometry = new SphereGeometry(radius, 8, 8);\n this.material = new MeshStandardMaterial({\n color: color,\n emissive: emissive,\n emissiveIntensity: emissiveIntensity,\n });\n }\n}\n","import { CatmullRomCurve3, Group, Mesh, MeshStandardMaterial, TubeGeometry, Vector3 } from \"three\";\n\nclass SpiralTube extends Group {\n constructor() {\n super();\n\n const spiralLength = 100;\n const heightIncrement = 0.05;\n const curve = new CatmullRomCurve3(\n Array.from({ length: spiralLength }, (_, i) => {\n const angle = i * 0.2;\n return new Vector3(\n Math.cos(angle) * 0.4,\n i * heightIncrement,\n Math.sin(angle) * 0.4,\n );\n }),\n );\n\n const tubeGeometry = new TubeGeometry(curve, 200, 0.1, 8, false);\n const glassMaterial = new MeshStandardMaterial({\n color: 0x88ccff,\n transparent: true,\n opacity: 0.3,\n roughness: 0.1,\n metalness: 0.2,\n emissive: 0x88ccff,\n emissiveIntensity: 0.2,\n });\n const multiSpiralTube = new Mesh(tubeGeometry, glassMaterial);\n this.add(multiSpiralTube);\n }\n}\n\nexport { SpiralTube };","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { StandGeometry, type StandGeometryOptions } from \"../../geometry/science/StandGeometry\";\n\nexport interface StandOptions extends StandGeometryOptions {\n /** Metal tint. Defaults to `#888888`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Laboratory stand prefab — ring and legs.\n */\nexport class Stand extends Mesh<StandGeometry, MeshStandardMaterial> {\n constructor({ color = \"#888888\", ...geometryOptions }: StandOptions = {}) {\n super(\n new StandGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.7,\n metalness: 0.3,\n }),\n );\n }\n}","import { DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { TeslaCoilGeometry } from \"../../geometry/science/TeslaCoilGeometry\";\n\n/**\n * Material indices\n * 0: Base\n * 1: Coil\n */\nexport class TeslaCoil extends Mesh<TeslaCoilGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new TeslaCoilGeometry(), [\n new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.6,\n metalness: 0.5,\n }),\n new MeshStandardMaterial({\n color: 0xff6600,\n roughness: 0.5,\n metalness: 0.8,\n side: DoubleSide,\n }),\n ]);\n }\n}\n","import { DoubleSide, Mesh, MeshPhysicalMaterial } from \"three\";\nimport { TestTubeGeometry } from \"../../geometry/science/TestTubeGeometry\";\n\nexport class TestTube extends Mesh<TestTubeGeometry, MeshPhysicalMaterial> {\n constructor(radiusTop = 0.2, radiusBottom = 0.2, height = 3, segments = 32) {\n super(\n new TestTubeGeometry(radiusTop, radiusBottom, height, segments),\n new MeshPhysicalMaterial({\n color: 0x88ccff,\n transparent: true,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.1,\n reflectivity: 0.8,\n transmission: 0.9,\n depthWrite: false,\n side: DoubleSide,\n }),\n );\n }\n}\n","import { BoxGeometry, Color, ColorRepresentation, DoubleSide, Group, Mesh, MeshStandardMaterial } from \"three\";\nimport { TestTubeGeometry } from \"../../geometry/science/TestTubeGeometry\";\n\nexport interface TestTubeRackOptions {\n /** Number of tubes. Defaults to `3`. */\n count?: number;\n /** Liquid color per tube; cycles when fewer entries than tubes. */\n colors?: ColorRepresentation[];\n}\n\n/**\n * Wooden rack with test tubes and emissive liquid fills.\n *\n * Glass shells use `DoubleSide` and `depthWrite: false`; liquid draws first\n * (`renderOrder` 1), glass second (`renderOrder` 2) so fills stay visible at\n * most camera angles.\n */\nexport class TestTubeRack extends Group {\n readonly count: number;\n\n constructor({\n count = 3,\n colors = [\"#00ffaa\", \"#ff00aa\", \"#aa00ff\"],\n }: TestTubeRackOptions = {}) {\n super();\n\n this.count = count;\n\n const rackGeometry = new BoxGeometry(3, 0.2, 1);\n const rackMaterial = new MeshStandardMaterial({\n color: 0x8b4513,\n roughness: 0.7,\n metalness: 0.3,\n });\n const rack = new Mesh(rackGeometry, rackMaterial);\n rack.position.y = 0.5;\n rack.castShadow = true;\n\n const testTubeGeometry = new TestTubeGeometry(0.1, 0.1, 1, 16);\n const glassMaterial = new MeshStandardMaterial({\n color: 0xaaaaaa,\n transparent: true,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.5,\n depthWrite: false,\n side: DoubleSide,\n });\n\n for (let i = 0; i < count; i++) {\n const testTube = new Mesh(testTubeGeometry, glassMaterial);\n const xPosition = (i - (count - 1) / 2) * 0.8;\n testTube.position.set(xPosition, 1, 0);\n testTube.castShadow = true;\n testTube.renderOrder = 2;\n\n const liquidGeometry = new TestTubeGeometry(0.099, 0.099, 0.5, 16, false);\n const liquidColor = colors[i % colors.length]!;\n const liquidMaterial = new MeshStandardMaterial({\n color: new Color(liquidColor),\n emissive: new Color(liquidColor),\n emissiveIntensity: 0.5,\n transparent: true,\n opacity: 0.6,\n depthWrite: false,\n side: DoubleSide,\n });\n\n const liquid = new Mesh(liquidGeometry, liquidMaterial);\n liquid.position.set(0, -0.25, 0);\n liquid.renderOrder = 1;\n testTube.add(liquid);\n\n rack.add(testTube);\n }\n\n this.add(rack);\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { BurstGeometry, type BurstGeometryOptions } from \"../../geometry/shapes/BurstGeometry\";\n\nexport interface BurstOptions extends BurstGeometryOptions {\n /** Surface tint. Defaults to `#ffff00`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffd700`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.25`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Burst shape prefab.\n */\nexport class Burst extends Mesh<BurstGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#ffff00\",\n emissive = \"#ffd700\",\n emissiveIntensity = 0.25,\n ...geometryOptions\n }: BurstOptions = {}) {\n super(\n new BurstGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { GearGeometry, type GearGeometryOptions } from \"../../geometry/shapes/GearGeometry\";\n\nexport interface GearOptions extends GearGeometryOptions {\n /** Metal tint. Defaults to `#aaaaaa`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Gear shape prefab.\n */\nexport class Gear extends Mesh<GearGeometry, MeshStandardMaterial> {\n constructor({ color = \"#aaaaaa\", ...geometryOptions }: GearOptions = {}) {\n super(\n new GearGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n metalness: 0.8,\n roughness: 0.2,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { HeartGeometry, type HeartGeometryOptions } from \"../../geometry/shapes/HeartGeometry\";\n\nexport interface HeartOptions extends HeartGeometryOptions {\n /** Surface tint. Defaults to `#c62828`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#c61416`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.25`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Heart shape prefab.\n */\nexport class Heart extends Mesh<HeartGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#c62828\",\n emissive = \"#c61416\",\n emissiveIntensity = 0.25,\n ...geometryOptions\n }: HeartOptions = {}) {\n super(\n new HeartGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { HexagonGeometry, type HexagonGeometryOptions } from \"../../geometry/shapes/HexagonGeometry\";\n\nexport interface HexagonOptions extends HexagonGeometryOptions {\n /** Surface tint. Defaults to `#ffffff`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffffff`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.1`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Hexagon tile prefab.\n */\nexport class Hexagon extends Mesh<HexagonGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#ffffff\",\n emissive = \"#ffffff\",\n emissiveIntensity = 0.1,\n ...geometryOptions\n }: HexagonOptions = {}) {\n super(\n new HexagonGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { StarGeometry, type StarGeometryOptions } from \"../../geometry/shapes/StarGeometry\";\n\nexport interface StarOptions extends StarGeometryOptions {\n /** Surface tint. Defaults to `#ffff00`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffd700`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.25`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Star shape prefab.\n */\nexport class Star extends Mesh<StarGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#ffff00\",\n emissive = \"#ffd700\",\n emissiveIntensity = 0.25,\n ...geometryOptions\n }: StarOptions = {}) {\n super(\n new StarGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { BoneGeometry } from \"../../geometry/skeleton/BoneGeometry\";\n\nexport class Bone extends Mesh<BoneGeometry, MeshStandardMaterial> {\n constructor() {\n super(new BoneGeometry(), new MeshStandardMaterial({ color: 0xffffff }));\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { TreeGeometry, type TreeGeometryOptions } from \"../../geometry/trees/TreeGeometry\";\n\nexport interface TreeOptions extends TreeGeometryOptions {\n /** Trunk tint. Defaults to `#8b4513`. */\n trunkColor?: ColorRepresentation;\n /** Leaf tint. Defaults to `#228b22`. */\n leafColor?: ColorRepresentation;\n}\n\n/**\n * Low-poly tree prefab — trunk and leaf clusters with separate material groups.\n */\nexport class Tree extends Mesh<TreeGeometry, MeshStandardMaterial[]> {\n readonly trunkHeight: number;\n\n constructor({\n trunkColor = \"#8b4513\",\n leafColor = \"#228b22\",\n ...geometryOptions\n }: TreeOptions = {}) {\n const geometry = new TreeGeometry(geometryOptions);\n\n super(geometry, [\n new MeshStandardMaterial({\n color: new Color(trunkColor),\n roughness: 0.9,\n metalness: 0,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(leafColor),\n roughness: 0.8,\n metalness: 0,\n flatShading: true,\n }),\n ]);\n\n this.trunkHeight = geometry.trunkHeight;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { HillGeometry, type HillGeometryOptions } from \"../../geometry/terrain/HillGeometry\";\n\nexport interface HillOptions extends HillGeometryOptions {\n /** Surface tint. Defaults to `#00ff00`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Hill prefab — hemispherical terrain mound.\n */\nexport class Hill extends Mesh<HillGeometry, MeshStandardMaterial> {\n readonly radius: number;\n readonly height: number;\n\n constructor({ color = \"#00ff00\", ...geometryOptions }: HillOptions = {}) {\n const geometry = new HillGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({ color: new Color(color), flatShading: true }),\n );\n\n this.radius = geometry.radius;\n this.height = geometry.height;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { MoundGeometry, type MoundGeometryOptions } from \"../../geometry/terrain/MoundGeometry\";\nimport { radiusFromCapWidth } from \"../../utils/SphericalGeometryUtils\";\n\nexport interface MoundOptions extends MoundGeometryOptions {\n /** Surface tint. Defaults to `#00ff00`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Mound prefab — flat-topped terrain cap.\n */\nexport class Mound extends Mesh<MoundGeometry, MeshStandardMaterial> {\n readonly radius: number;\n\n constructor({\n color = \"#00ff00\",\n radius = radiusFromCapWidth(5, Math.PI / 10),\n ...geometryOptions\n }: MoundOptions = {}) {\n const geometry = new MoundGeometry({ radius, ...geometryOptions });\n\n super(\n geometry,\n new MeshStandardMaterial({ color: new Color(color), flatShading: true }),\n );\n\n this.radius = geometry.radius;\n }\n}","import { Material } from \"three\";\n\n/**\n * Shader modification to support instance-specific colors.\n * This function modifies the provided material to accept instance-specific colors.\n *\n * This is not generally necessary for materials that already support vertex colors,\n * but it can be useful for custom materials or when using InstancedMesh.\n *\n * Instanced meshes already allow for per-instance colors, implemented as:\n * ```ts\n * const colors = new Float32Array(instancedMesh.count * 3);\n * for (let i = 0; i < instancedMesh.count; i++) {\n * const [r, g, b] = [Math.random(), Math.random(), Math.random()];\n * colors.set([r, g, b], i * 3); // Normalized to [0, 1]\n * }\n * instancedMesh.instanceColor = new THREE.InstancedBufferAttribute(colors, 3);\n * ```\n *\n * Example usage:\n * ```ts\n * // Material\n * const material = new THREE.MeshStandardMaterial();\n *\n * // Add instance color modifier\n * addInstanceColor(material);\n *\n * // RGB color for each instance\n * const colors = new Float32Array(instancedMesh.count * 3);\n * for (let i = 0; i < instancedMesh.count; i++) {\n * getAnalogousColors(hue).forEach((color, index) => {\n * colors[i * 3 + index] = color / 0xff;\n * });\n * }\n *\n * // Add the instance color attribute to the geometry\n * instancedMesh.geometry.setAttribute(\"instanceColor\", new THREE.InstancedBufferAttribute(colors, 3));\n * ```\n */\nexport function addInstanceColor(material:Material) {\n if (!material) {\n throw new Error(\"A material must be provided to add instance color support.\");\n }\n\n // Modify the material to accept instance-specific colors using onBeforeCompile\n material.onBeforeCompile = (shader) => {\n // Add the instanceColor attribute and varying to the vertex shader\n shader.vertexShader = shader.vertexShader.replace(\n \"void main() {\",\n \"attribute vec3 instanceColor;\\nvarying vec3 vColor;\\nvoid main() {\",\n );\n\n // Pass the instance color to the fragment shader\n shader.vertexShader = shader.vertexShader.replace(\n \"#include <begin_vertex>\",\n \"#include <begin_vertex>\\nvColor = instanceColor;\",\n );\n\n // Add varying in the fragment shader to get the color from the vertex shader\n shader.fragmentShader = shader.fragmentShader.replace(\n \"void main() {\",\n \"varying vec3 vColor;\\nvoid main() {\",\n );\n\n // Use the instance color for the fragment color\n shader.fragmentShader = shader.fragmentShader.replace(\n \"#include <dithering_fragment>\",\n \"#include <dithering_fragment>\\ngl_FragColor.rgb = vColor * gl_FragColor.rgb;\",\n );\n };\n\n return material;\n}\n","import { Material } from \"three\";\n\n/**\n * Utility function to add water-like vertex displacement to an existing Three.js material.\n * @param {Material} material - The material to mutate, e.g., MeshStandardMaterial.\n * @param {Object} options - Options for water wave modification.\n * @param {number} [options.time=0.0] - The time value for the wave function.\n * @param {number} [options.waveFrequency=0.2] - The frequency of the water waves.\n * @param {number} [options.waveAmplitude=0.5] - The amplitude of the water waves.\n */\nexport function addWaterDisplacement<T extends Material>(material:T, { time = 0.0, waveFrequency = 0.2, waveAmplitude = 0.5 } = {}) {\n material.onBeforeCompile = (shader) => {\n // Add uniforms for time, wave frequency, and wave amplitude\n shader.uniforms.time = { value: time };\n shader.uniforms.waveFrequency = { value: waveFrequency };\n shader.uniforms.waveAmplitude = { value: waveAmplitude };\n\n // Inject the water-like wave displacement code in the vertex shader\n shader.vertexShader = `\n uniform float time;\n uniform float waveFrequency;\n uniform float waveAmplitude;\n\n vec3 waterDisplacement(vec3 position, vec3 normal) {\n vec3 displaced = position;\n\n // Displace along the normal direction instead of local y-axis\n displaced += normal * (sin(position.x * waveFrequency + time) * waveAmplitude);\n displaced += normal * (cos(position.z * waveFrequency + time) * waveAmplitude);\n\n return displaced;\n }\n ` + shader.vertexShader;\n\n // Replace the vertex transformation logic to add displacement based on the normal\n shader.vertexShader = shader.vertexShader.replace(\n `#include <begin_vertex>`,\n `\n vec3 transformed = waterDisplacement(position, normal);\n `\n );\n\n // Store shader reference in material for time updates\n material.userData.shader = shader;\n };\n}\n\n/**\n * Updates the time uniform of the material's shader to animate the water effect.\n * @param {Material} material - The material to update.\n * @param {number} deltaTime - The time increment to add.\n */\nexport function updateWaterDisplacementTime<T extends Material>(material:T, deltaTime:number) {\n if (material.userData.shader) {\n material.userData.shader.uniforms.time.value += deltaTime;\n }\n}\n","import { Axis } from \"../constants/Axis\";\nimport { Material, Vector3 } from \"three\";\n\ninterface NoiseDisplacementOptions {\n time?: number;\n intensity?: number;\n axis?: Vector3;\n scale?: number;\n}\n\n/**\n * Utility function to add noise-based vertex displacement to an existing Three.js material.\n * @param {Material} material - The material to mutate, e.g., MeshStandardMaterial.\n * @param {Object} options - Options for noise modification.\n * @param {number} [options.time=0.0] - The time value for the noise function.\n * @param {number} [options.intensity=1.0] - The intensity of the displacement.\n * @param {Vector3} [options.axis=new Vector3(1, 1, 1)] - The axis of displacement.\n * @param {number} [options.scale=10.0] - The scale of the noise effect.\n */\nexport function addNoiseDisplacement<T extends Material>(\n material: T,\n { time = 0.0, intensity = 1.0, axis = Axis.XYZ, scale = 10.0 }: NoiseDisplacementOptions = {},\n) {\n material.onBeforeCompile = (shader) => {\n // Add uniforms for time, axis, intensity, and scale\n shader.uniforms.time = { value: time };\n shader.uniforms.axis = { value: axis };\n shader.uniforms.intensity = { value: intensity };\n shader.uniforms.scale = { value: scale };\n\n // Add noise function and modify the vertex shader to displace vertices\n shader.vertexShader = `\n uniform float time;\n uniform vec3 axis;\n uniform float intensity;\n uniform float scale;\n\n float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec4 perm(vec4 x) { return mod289(((x * 34.0) + 1.0) * x); }\n\n float noise(vec3 p) {\n vec3 a = floor(p);\n vec3 d = p - a;\n d = d * d * (3.0 - 2.0 * d);\n\n vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);\n vec4 k1 = perm(b.xyxy);\n vec4 k2 = perm(k1.xyxy + b.zzww);\n\n vec4 c = k2 + a.zzzz;\n vec4 k3 = perm(c);\n vec4 k4 = perm(c + 1.0);\n\n vec4 o1 = fract(k3 * (1.0 / 41.0));\n vec4 o2 = fract(k4 * (1.0 / 41.0));\n\n vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);\n vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);\n\n return o4.y * d.y + o4.x * (1.0 - d.y);\n }\n ` + shader.vertexShader;\n\n // Replace the vertex transformation logic to add noise-based displacement\n shader.vertexShader = shader.vertexShader.replace(\n `#include <begin_vertex>`,\n `\n vec3 transformed = vec3(position);\n float n = noise(transformed * scale + time);\n transformed += normalize(axis) * n * intensity;\n vec3 transformedNormal = normal;\n `,\n );\n\n // Store shader reference in material for time updates\n material.userData.shader = shader;\n };\n}\n\n/**\n * Updates the time uniform of the material's shader to animate the noise effect.\n * @param {Material} material - The material to update.\n * @param {number} deltaTime - The time increment to add.\n */\nexport function updateNoiseDisplacementTime<T extends Material>(material: T, deltaTime: number) {\n if (material.userData.shader) {\n material.userData.shader.uniforms.time.value += deltaTime;\n }\n}\n","import { MathUtils, Uniform, Vector3 } from \"three\";\n\nexport interface AtmosphericShaderUniforms {\n turbidity: Uniform<number>;\n rayleigh: Uniform<number>;\n mieCoefficient: Uniform<number>;\n mieDirectionalG: Uniform<number>;\n sunPosition: Uniform<Vector3>;\n up: Uniform<Vector3>;\n}\n\n/**\n * Atmospheric scattering shader.\n *\n * Based on \"A Practical Analytic Model for Daylight\"\n * aka The Preetham Model, the de facto standard analytic skydome model\n * https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight\n *\n * First implemented by Simon Wallner\n * http://simonwallner.at/project/atmospheric-scattering/\n *\n * Improved by Martin Upitis\n * http://blenderartists.org/forum/showthread.php?245954-preethams-sky-impementation-HDR\n *\n * Three.js integration by zz85 http://twitter.com/blurspline\n *\n * Example:\n * ```\n * const geometry = new BoxGeometry(1, 1, 1);\n *\n * const material = new ShaderMaterial({\n * uniforms: atmosphericShader.uniforms,\n * vertexShader: atmosphericShader.vertexShader,\n * fragmentShader: atmosphericShader.fragmentShader,\n * depthWrite: false,\n * side: BackSide,\n * }) as ShaderMaterial & { uniforms: AtmosphericShaderUniforms };\n *\n * const theta = MathUtils.degToRad(89);\n * const phi = MathUtils.degToRad(180);\n * const sun = new Vector3().setFromSphericalCoords(1, theta, phi);\n *\n * material.uniforms.sunPosition.value = sun;\n *\n * const mesh = new Mesh(geometry, material);\n * mesh.scale.setScalar(450000);\n * ```\n */\nexport const atmosphericShader = {\n uniforms: {\n turbidity: { value: 10 },\n rayleigh: { value: 2 },\n mieCoefficient: { value: 0.005 },\n mieDirectionalG: { value: 0.8 },\n sunPosition: { value: new Vector3().setFromSphericalCoords(1, MathUtils.degToRad(90), MathUtils.degToRad(180)) },\n up: { value: new Vector3(0, 1, 0) },\n },\n vertexShader: `\n\t\tuniform vec3 sunPosition;\n\t\tuniform float rayleigh;\n\t\tuniform float turbidity;\n\t\tuniform float mieCoefficient;\n\t\tuniform vec3 up;\n\n\t\tvarying vec3 vWorldPosition;\n\t\tvarying vec3 vSunDirection;\n\t\tvarying float vSunfade;\n\t\tvarying vec3 vBetaR;\n\t\tvarying vec3 vBetaM;\n\t\tvarying float vSunE;\n\n\t\t// constants for atmospheric scattering\n\t\tconst float e = 2.71828182845904523536028747135266249775724709369995957;\n\t\tconst float pi = 3.141592653589793238462643383279502884197169;\n\n\t\t// wavelength of used primaries, according to preetham\n\t\tconst vec3 lambda = vec3( 680E-9, 550E-9, 450E-9 );\n\t\t// this pre-calculation replaces older TotalRayleigh(vec3 lambda) function:\n\t\t// (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn))\n\t\tconst vec3 totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 );\n\n\t\t// mie stuff\n\t\t// K coefficient for the primaries\n\t\tconst float v = 4.0;\n\t\tconst vec3 K = vec3( 0.686, 0.678, 0.666 );\n\t\t// MieConst = pi * pow( ( 2.0 * pi ) / lambda, vec3( v - 2.0 ) ) * K\n\t\tconst vec3 MieConst = vec3( 1.8399918514433978E14, 2.7798023919660528E14, 4.0790479543861094E14 );\n\n\t\t// earth shadow hack\n\t\t// cutoffAngle = pi / 1.95;\n\t\tconst float cutoffAngle = 1.6110731556870734;\n\t\tconst float steepness = 1.5;\n\t\tconst float EE = 1000.0;\n\n\t\tfloat sunIntensity( float zenithAngleCos ) {\n\t\t\tzenithAngleCos = clamp( zenithAngleCos, -1.0, 1.0 );\n\t\t\treturn EE * max( 0.0, 1.0 - pow( e, -( ( cutoffAngle - acos( zenithAngleCos ) ) / steepness ) ) );\n\t\t}\n\n\t\tvec3 totalMie( float T ) {\n\t\t\tfloat c = ( 0.2 * T ) * 10E-18;\n\t\t\treturn 0.434 * c * MieConst;\n\t\t}\n\n\t\tvoid main() {\n\t\t\tvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\t\t\tvWorldPosition = worldPosition.xyz;\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\t\t\tgl_Position.z = gl_Position.w; // set z to camera.far\n\n\t\t\tvSunDirection = normalize( sunPosition );\n\n\t\t\tvSunE = sunIntensity( dot( vSunDirection, up ) );\n\n\t\t\tvSunfade = 1.0 - clamp( 1.0 - exp( ( sunPosition.y / 450000.0 ) ), 0.0, 1.0 );\n\n\t\t\tfloat rayleighCoefficient = rayleigh - ( 1.0 * ( 1.0 - vSunfade ) );\n\n\t\t\t// extinction (absorption + out scattering)\n\t\t\t// rayleigh coefficients\n\t\t\tvBetaR = totalRayleigh * rayleighCoefficient;\n\n\t\t\t// mie coefficients\n\t\t\tvBetaM = totalMie( turbidity ) * mieCoefficient;\n }\n `,\n fragmentShader: `\n \tvarying vec3 vWorldPosition;\n\t\tvarying vec3 vSunDirection;\n\t\tvarying float vSunfade;\n\t\tvarying vec3 vBetaR;\n\t\tvarying vec3 vBetaM;\n\t\tvarying float vSunE;\n\n\t\tuniform float mieDirectionalG;\n\t\tuniform vec3 up;\n\n\t\t// constants for atmospheric scattering\n\t\tconst float pi = 3.141592653589793238462643383279502884197169;\n\n\t\tconst float n = 1.0003; // refractive index of air\n\t\tconst float N = 2.545E25; // number of molecules per unit volume for air at 288.15K and 1013mb (sea level -45 celsius)\n\n\t\t// optical length at zenith for molecules\n\t\tconst float rayleighZenithLength = 8.4E3;\n\t\tconst float mieZenithLength = 1.25E3;\n\t\t// 66 arc seconds -> degrees, and the cosine of that\n\t\tconst float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;\n\n\t\t// 3.0 / ( 16.0 * pi )\n\t\tconst float THREE_OVER_SIXTEENPI = 0.05968310365946075;\n\t\t// 1.0 / ( 4.0 * pi )\n\t\tconst float ONE_OVER_FOURPI = 0.07957747154594767;\n\n\t\tfloat rayleighPhase( float cosTheta ) {\n\t\t\treturn THREE_OVER_SIXTEENPI * ( 1.0 + pow( cosTheta, 2.0 ) );\n\t\t}\n\n\t\tfloat hgPhase( float cosTheta, float g ) {\n\t\t\tfloat g2 = pow( g, 2.0 );\n\t\t\tfloat inverse = 1.0 / pow( 1.0 - 2.0 * g * cosTheta + g2, 1.5 );\n\t\t\treturn ONE_OVER_FOURPI * ( ( 1.0 - g2 ) * inverse );\n\t\t}\n\n void main() {\n\t\t\tvec3 direction = normalize( vWorldPosition - cameraPosition );\n\n\t\t\t// optical length\n\t\t\t// cutoff angle at 90 to avoid singularity in next formula.\n\t\t\tfloat zenithAngle = acos( max( 0.0, dot( up, direction ) ) );\n\t\t\tfloat inverse = 1.0 / ( cos( zenithAngle ) + 0.15 * pow( 93.885 - ( ( zenithAngle * 180.0 ) / pi ), -1.253 ) );\n\t\t\tfloat sR = rayleighZenithLength * inverse;\n\t\t\tfloat sM = mieZenithLength * inverse;\n\n\t\t\t// combined extinction factor\n\t\t\tvec3 Fex = exp( -( vBetaR * sR + vBetaM * sM ) );\n\n\t\t\t// in scattering\n\t\t\tfloat cosTheta = dot( direction, vSunDirection );\n\n\t\t\tfloat rPhase = rayleighPhase( cosTheta * 0.5 + 0.5 );\n\t\t\tvec3 betaRTheta = vBetaR * rPhase;\n\n\t\t\tfloat mPhase = hgPhase( cosTheta, mieDirectionalG );\n\t\t\tvec3 betaMTheta = vBetaM * mPhase;\n\n\t\t\tvec3 Lin = pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * ( 1.0 - Fex ), vec3( 1.5 ) );\n\t\t\tLin *= mix( vec3( 1.0 ), pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * Fex, vec3( 1.0 / 2.0 ) ), clamp( pow( 1.0 - dot( up, vSunDirection ), 5.0 ), 0.0, 1.0 ) );\n\n\t\t\t// night sky\n\t\t\tfloat theta = acos( direction.y ); // elevation --> y-axis, [-pi/2, pi/2]\n\t\t\tfloat phi = atan( direction.z, direction.x ); // azimuth --> x-axis [-pi/2, pi/2]\n\t\t\tvec2 uv = vec2( phi, theta ) / vec2( 2.0 * pi, pi ) + vec2( 0.5, 0.0 );\n\t\t\tvec3 L0 = vec3( 0.1 ) * Fex;\n\n\t\t\t// composition + solar disc\n\t\t\tfloat sundisk = smoothstep( sunAngularDiameterCos, sunAngularDiameterCos + 0.00002, cosTheta );\n\t\t\tL0 += ( vSunE * 19000.0 * Fex ) * sundisk;\n\n\t\t\tvec3 texColor = ( Lin + L0 ) * 0.04 + vec3( 0.0, 0.0003, 0.00075 );\n\n\t\t\tvec3 retColor = pow( texColor, vec3( 1.0 / ( 1.2 + ( 1.2 * vSunfade ) ) ) );\n\n\t\t\tgl_FragColor = vec4( retColor, 1.0 );\n\n\t\t\t#include <tonemapping_fragment>\n\t\t\t#include <colorspace_fragment>\n\t\t}\n `,\n};\n","// Shader for blur transition effect\nexport const blurTransitionShader = {\n uniforms: {\n tDiffuse: { value: null },\n kernelSize: { value: 0.0 },\n resolution: { value: null }, // Set to new THREE.Vector2(width, height)\n },\n vertexShader: `\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `,\n fragmentShader: `\n uniform sampler2D tDiffuse;\n uniform float kernelSize;\n uniform vec2 resolution;\n varying vec2 vUv;\n\n void main() {\n vec2 texelSize = 1.0 / resolution;\n vec4 color = vec4(0.0);\n float total = 0.0;\n\n // Box blur with dynamic kernel size\n float radius = kernelSize;\n for (float x = -10.0; x <= 10.0; x += 1.0) {\n for (float y = -10.0; y <= 10.0; y += 1.0) {\n float weight = 1.0 - (abs(x) + abs(y)) / (radius * 2.0 + 1.0);\n if (weight > 0.0 && abs(x) <= radius && abs(y) <= radius) {\n vec2 offset = vec2(x, y) * texelSize * 2.0;\n color += texture2D(tDiffuse, vUv + offset) * weight;\n total += weight;\n }\n }\n }\n\n gl_FragColor = total > 0.0 ? color / total : texture2D(tDiffuse, vUv);\n }\n `,\n};\n","// Shader for crossfade transition between two textures\nexport const crossfadeShader = {\n uniforms: {\n tDiffuseA: { value: null },\n tDiffuseB: { value: null },\n mixRatio: { value: 0.0 },\n },\n vertexShader: `\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `,\n fragmentShader: `\n uniform sampler2D tDiffuseA;\n uniform sampler2D tDiffuseB;\n uniform float mixRatio;\n varying vec2 vUv;\n\n vec3 linearTosRGB(vec3 color) {\n return mix(\n color * 12.92,\n 1.055 * pow(color, vec3(1.0 / 2.4)) - 0.055,\n step(0.0031308, color)\n );\n }\n\n void main() {\n vec4 texelA = texture2D(tDiffuseA, vUv);\n vec4 texelB = texture2D(tDiffuseB, vUv);\n vec3 blendedColor = mix(texelA.rgb, texelB.rgb, mixRatio);\n gl_FragColor = vec4(linearTosRGB(blendedColor), max(texelA.a, texelB.a));\n }\n `,\n};\n","import { Color, Uniform } from \"three\";\n\nexport interface DaySkyUniforms {\n topColor: Uniform<Color>;\n bottomColor: Uniform<Color>;\n}\n\n/**\n * Shader for a day skybox.\n *\n * Example:\n * ```\n * this.material = new ShaderMaterial({\n * uniforms: daySkyShader.uniforms,\n * vertexShader: daySkyShader.vertexShader,\n * fragmentShader: daySkyShader.fragmentShader,\n * side: BackSide,\n * }) as ShaderMaterial & { uniforms: DaySkyUniforms };\n * ```\n */\nexport const daySkyShader = {\n uniforms: {\n topColor: { value: new Color(0.5, 0.8, 1.0) },\n bottomColor: { value: new Color(1.0, 1.0, 1.0) },\n },\n vertexShader: `\n varying vec3 vPosition;\n void main() {\n vPosition = position;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `,\n fragmentShader: `\n uniform vec3 topColor;\n uniform vec3 bottomColor;\n varying vec3 vPosition;\n void main() {\n float y = normalize(vPosition).y * 0.5 + 0.5; // Normalizing y to range 0 to 1\n gl_FragColor = vec4(mix(bottomColor, topColor, y), 1.0);\n }\n `,\n};\n","// Shader for fade-to-color transition effect\nexport const fadeShader = {\n uniforms: {\n tDiffuse: { value: null },\n fadeAmount: { value: 0.0 },\n fadeColor: { value: null }, // Set to new THREE.Color()\n },\n vertexShader: `\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `,\n fragmentShader: `\n uniform sampler2D tDiffuse;\n uniform float fadeAmount;\n uniform vec3 fadeColor;\n varying vec2 vUv;\n\n vec3 linearTosRGB(vec3 color) {\n return mix(\n color * 12.92,\n 1.055 * pow(color, vec3(1.0 / 2.4)) - 0.055,\n step(0.0031308, color)\n );\n }\n\n void main() {\n vec4 texel = texture2D(tDiffuse, vUv);\n vec3 blendedColor = mix(texel.rgb, fadeColor, fadeAmount);\n gl_FragColor = vec4(linearTosRGB(blendedColor), 1.0);\n }\n `,\n};\n","// Shader for fade transition between two scenes through a color\nexport const fadeTransitionSceneShader = {\n uniforms: {\n tDiffuseA: { value: null },\n tDiffuseB: { value: null },\n mixRatio: { value: 0.0 },\n fadeColor: { value: null }, // Set to new THREE.Color()\n },\n vertexShader: `\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `,\n fragmentShader: `\n uniform sampler2D tDiffuseA;\n uniform sampler2D tDiffuseB;\n uniform float mixRatio;\n uniform vec3 fadeColor;\n varying vec2 vUv;\n\n vec3 linearTosRGB(vec3 color) {\n return mix(\n color * 12.92,\n 1.055 * pow(color, vec3(1.0 / 2.4)) - 0.055,\n step(0.0031308, color)\n );\n }\n\n void main() {\n vec4 texelA = texture2D(tDiffuseA, vUv);\n vec4 texelB = texture2D(tDiffuseB, vUv);\n\n // Fade out to color, then fade in from color\n float fadeOut = smoothstep(0.0, 0.5, mixRatio) * 2.0;\n float fadeIn = smoothstep(0.5, 1.0, mixRatio) * 2.0 - 1.0;\n\n vec3 colorA = mix(texelA.rgb, fadeColor, clamp(fadeOut, 0.0, 1.0));\n vec3 colorB = mix(fadeColor, texelB.rgb, clamp(fadeIn, 0.0, 1.0));\n\n vec3 blendedColor = mix(colorA, colorB, step(0.5, mixRatio));\n gl_FragColor = vec4(linearTosRGB(blendedColor), 1.0);\n }\n `,\n};\n","import { Color, Uniform } from \"three\";\n\nexport interface NightSkyUniforms {\n topColor: Uniform<Color>;\n bottomColor: Uniform<Color>;\n offset: Uniform<number>;\n exponent: Uniform<number>;\n}\n\n/**\n * Shader for a night skybox.\n *\n * Example:\n * ```\n * this.material = new ShaderMaterial({\n * vertexShader: nightSkyShader.vertexShader,\n * fragmentShader: nightSkyShader.fragmentShader,\n * uniforms: nightSkyShader.uniforms,\n * side: BackSide,\n * }) as ShaderMaterial & { uniforms: NightSkyUniforms };\n * ```\n */\nexport const nightSkyShader = {\n uniforms: {\n topColor: { value: new Color(0x000033) },\n bottomColor: { value: new Color(0x000011) },\n offset: { value: 33 },\n exponent: { value: 0.6 },\n },\n vertexShader: `\n varying vec3 vWorldPosition;\n void main() {\n vec4 worldPosition = modelMatrix * vec4(position, 1.0);\n vWorldPosition = worldPosition.xyz;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n `,\n fragmentShader: `\n uniform vec3 topColor;\n uniform vec3 bottomColor;\n uniform float offset;\n uniform float exponent;\n varying vec3 vWorldPosition;\n void main() {\n float h = normalize(vWorldPosition + offset).y;\n gl_FragColor = vec4(mix(bottomColor, topColor, max(pow(max(h, 0.0), exponent), 0.0)), 1.0);\n }\n `,\n};\n","import { BackSide, BoxGeometry, MathUtils, Mesh, ShaderMaterial, Vector3 } from \"three\";\nimport { atmosphericShader, AtmosphericShaderUniforms } from \"../shaders/atmosphericShader\";\n\n/**\n * Atmospheric scattering skybox.\n *\n * Elevation (theta, θ): Angle measured above or below the horizon (from the xy-plane towards the zenith or nadir).\n * Azimuth (phi, φ): Angle measured around the horizon from a reference direction (e.g., north, east).\n */\nexport class AtmosphericSkybox extends Mesh {\n geometry: BoxGeometry;\n material: ShaderMaterial & { uniforms: AtmosphericShaderUniforms };\n\n constructor() {\n super();\n\n this.geometry = new BoxGeometry(1, 1, 1);\n\n this.material = new ShaderMaterial({\n uniforms: atmosphericShader.uniforms,\n vertexShader: atmosphericShader.vertexShader,\n fragmentShader: atmosphericShader.fragmentShader,\n depthWrite: false,\n side: BackSide,\n }) as ShaderMaterial & { uniforms: AtmosphericShaderUniforms };\n\n this.scale.setScalar(450000);\n\n const theta = MathUtils.degToRad(89);\n const phi = MathUtils.degToRad(180);\n const sun = new Vector3().setFromSphericalCoords(1, theta, phi);\n\n this.material.uniforms.sunPosition.value = sun;\n }\n\n /**\n * Set the sun position.\n *\n * Elevation (theta, θ)\n * - Angle measured above or below the horizon (from the xy-plane towards the zenith or nadir).\n * - Ranges from 0 to π/2 radians (or 0 to 90 degrees).\n * - This is the vertical angle in the xy-plane.\n *\n * Azimuth (phi, φ)\n * - Angle measured around the horizon from a reference direction (e.g., north, east).\n * - Ranges from 0 to 2π radians (or 0 to 360 degrees).\n * - This is the horizontal angle in the xy-plane.\n */\n sunPosition(theta: number, phi: number) {\n const sun = new Vector3();\n sun.setFromSphericalCoords(1, theta, phi);\n\n this.material.uniforms.sunPosition.value = sun;\n }\n}\n","import { BackSide, BoxGeometry, Mesh, ShaderMaterial } from \"three\";\nimport { daySkyShader, DaySkyUniforms } from \"../shaders/daySkyShader\";\n\nexport class DaySkybox extends Mesh {\n geometry: BoxGeometry;\n material: ShaderMaterial & { uniforms: DaySkyUniforms };\n\n constructor(size = 1000) {\n super();\n\n this.geometry = new BoxGeometry(size, size, size);\n\n this.material = new ShaderMaterial({\n uniforms: daySkyShader.uniforms,\n vertexShader: daySkyShader.vertexShader,\n fragmentShader: daySkyShader.fragmentShader,\n side: BackSide,\n }) as ShaderMaterial & { uniforms: DaySkyUniforms };\n }\n}\n","import { BackSide, Mesh, ShaderMaterial, SphereGeometry } from \"three\";\nimport { nightSkyShader, NightSkyUniforms } from \"../shaders/nightSkyShader\";\n\nexport class NightSkybox extends Mesh {\n geometry: SphereGeometry;\n material: ShaderMaterial & { uniforms: NightSkyUniforms };\n\n constructor(size = 1000) {\n super();\n\n this.geometry = new SphereGeometry(size, 32, 15);\n\n this.material = new ShaderMaterial({\n vertexShader: nightSkyShader.vertexShader,\n fragmentShader: nightSkyShader.fragmentShader,\n uniforms: nightSkyShader.uniforms,\n side: BackSide,\n }) as ShaderMaterial & { uniforms: NightSkyUniforms };\n }\n}\n","import { DataTexture, NearestFilter, RepeatWrapping, RGBAFormat, UnsignedByteType } from \"three\";\n\n/**\n * Create a checkerboard texture\n *\n * Example:\n * ```\n * const material = new MeshStandardMaterial();\n * material.map = createCheckerboardTexture(8);\n * ```\n */\nexport const checkerboardTexture = (size: number): DataTexture => {\n const data = new Uint8Array(4 * size * size);\n for (let i = 0; i < size * size; i++) {\n const stride = i * 4;\n const color = (i % size ^ Math.floor(i / size)) & 1 ? 255 : 0;\n data[stride] = color; // red\n data[stride + 1] = color; // green\n data[stride + 2] = color; // blue\n data[stride + 3] = 255; // alpha\n }\n\n const texture = new DataTexture(data, size, size, RGBAFormat, UnsignedByteType);\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.minFilter = NearestFilter;\n texture.needsUpdate = true;\n\n return texture;\n};\n","import * as THREE from 'three';\nimport { Easing, EasingFunction } from '../constants/Easing';\nimport { crossfadeShader } from '../shaders/crossfadeShader';\n\nexport interface CameraTransitionOptions {\n duration?: number;\n easing?: EasingFunction | keyof typeof Easing;\n onUpdate?: (progress: number) => void;\n onComplete?: () => void;\n}\n\n/**\n * CameraTransition provides smooth animated transitions between perspective and orthographic cameras.\n *\n * The transition works by rendering both camera views to separate render targets and blending between them.\n * This provides a true, accurate transition between the two camera types.\n *\n * @example\n * ```typescript\n * const transition = new CameraTransition(\n * perspectiveCamera,\n * orthographicCamera,\n * renderer\n * );\n *\n * transition.transitionTo(orthographicCamera, {\n * duration: 1000,\n * easing: 'easeInOutCubic'\n * });\n * ```\n */\nexport class CameraTransition {\n private perspectiveCamera: THREE.PerspectiveCamera;\n private orthographicCamera: THREE.OrthographicCamera;\n private renderer: THREE.WebGLRenderer;\n\n private scene: THREE.Scene | null = null;\n private currentCamera: THREE.Camera;\n private targetCamera: THREE.Camera | null = null;\n\n private transitionProgress = 0;\n private transitionDuration = 1000;\n private transitionStartTime = 0;\n private isTransitioning = false;\n private easingFunction: EasingFunction;\n\n private renderTargetA: THREE.WebGLRenderTarget;\n private renderTargetB: THREE.WebGLRenderTarget;\n private blendScene: THREE.Scene;\n private blendCamera: THREE.OrthographicCamera;\n private blendMaterial: THREE.ShaderMaterial;\n\n private onUpdateCallback?: (progress: number) => void;\n private onCompleteCallback?: () => void;\n\n constructor(\n perspectiveCamera: THREE.PerspectiveCamera,\n orthographicCamera: THREE.OrthographicCamera,\n renderer: THREE.WebGLRenderer\n ) {\n this.perspectiveCamera = perspectiveCamera;\n this.orthographicCamera = orthographicCamera;\n this.renderer = renderer;\n this.currentCamera = perspectiveCamera;\n this.easingFunction = Easing.cubicInOut;\n\n // Create render targets for dual-camera rendering\n const size = renderer.getSize(new THREE.Vector2());\n this.renderTargetA = new THREE.WebGLRenderTarget(size.x, size.y);\n this.renderTargetB = new THREE.WebGLRenderTarget(size.x, size.y);\n\n // Create blend scene and shader material for crossfading\n this.blendScene = new THREE.Scene();\n this.blendCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n\n this.blendMaterial = new THREE.ShaderMaterial({\n uniforms: {\n tDiffuseA: { value: this.renderTargetA.texture },\n tDiffuseB: { value: this.renderTargetB.texture },\n mixRatio: { value: 0.0 },\n },\n vertexShader: crossfadeShader.vertexShader,\n fragmentShader: crossfadeShader.fragmentShader,\n });\n\n const blendPlane = new THREE.PlaneGeometry(2, 2);\n const blendMesh = new THREE.Mesh(blendPlane, this.blendMaterial);\n this.blendScene.add(blendMesh);\n }\n\n /**\n * Start a transition to the target camera\n */\n transitionTo(\n targetCamera: THREE.PerspectiveCamera | THREE.OrthographicCamera,\n options: CameraTransitionOptions = {}\n ): void {\n if (this.currentCamera === targetCamera) {\n return; // Already at target camera\n }\n\n this.targetCamera = targetCamera;\n this.transitionDuration = options.duration ?? 1000;\n this.transitionStartTime = performance.now();\n this.transitionProgress = 0;\n this.isTransitioning = true;\n this.onUpdateCallback = options.onUpdate;\n this.onCompleteCallback = options.onComplete;\n\n // Set easing function\n if (options.easing) {\n if (typeof options.easing === 'string') {\n this.easingFunction = Easing[options.easing];\n } else {\n this.easingFunction = options.easing;\n }\n }\n }\n\n /**\n * Update the transition. Call this in your render loop.\n */\n update(scene: THREE.Scene): THREE.Camera {\n this.scene = scene;\n\n if (!this.isTransitioning) {\n return this.currentCamera;\n }\n\n const now = performance.now();\n const elapsed = now - this.transitionStartTime;\n const linearProgress = Math.min(elapsed / this.transitionDuration, 1);\n this.transitionProgress = this.easingFunction(linearProgress);\n\n if (this.onUpdateCallback) {\n this.onUpdateCallback(this.transitionProgress);\n }\n\n if (linearProgress >= 1) {\n // Transition complete\n this.isTransitioning = false;\n this.currentCamera = this.targetCamera!;\n this.targetCamera = null;\n\n if (this.onCompleteCallback) {\n this.onCompleteCallback();\n }\n\n return this.currentCamera;\n }\n\n // Return the current camera during transition (render method handles blending)\n return this.currentCamera;\n }\n\n /**\n * Render the scene with camera transition blending\n */\n render(scene: THREE.Scene): void {\n if (!this.isTransitioning || !this.targetCamera) {\n // No transition, render normally\n this.renderer.render(scene, this.currentCamera);\n return;\n }\n\n // Render both cameras to separate render targets\n this.renderer.setRenderTarget(this.renderTargetA);\n this.renderer.render(scene, this.currentCamera);\n\n this.renderer.setRenderTarget(this.renderTargetB);\n this.renderer.render(scene, this.targetCamera);\n\n // Blend the two renders\n this.blendMaterial.uniforms.mixRatio.value = this.transitionProgress;\n this.renderer.setRenderTarget(null);\n this.renderer.render(this.blendScene, this.blendCamera);\n }\n\n /**\n * Get the current active camera\n */\n getCurrentCamera(): THREE.Camera {\n return this.currentCamera;\n }\n\n /**\n * Check if a transition is currently in progress\n */\n getIsTransitioning(): boolean {\n return this.isTransitioning;\n }\n\n /**\n * Get the current transition progress (0-1)\n */\n getProgress(): number {\n return this.transitionProgress;\n }\n\n /**\n * Resize the render targets when the renderer size changes\n */\n setSize(width: number, height: number): void {\n this.renderTargetA.setSize(width, height);\n this.renderTargetB.setSize(width, height);\n }\n\n /**\n * Dispose of resources\n */\n dispose(): void {\n this.renderTargetA.dispose();\n this.renderTargetB.dispose();\n this.blendMaterial.dispose();\n }\n}\n","import * as THREE from 'three';\nimport { Easing, EasingFunction } from '../constants/Easing';\nimport { crossfadeShader } from '../shaders/crossfadeShader';\nimport { fadeTransitionSceneShader } from '../shaders/fadeTransitionSceneShader';\n\nexport interface SceneTransitionOptions {\n duration?: number;\n easing?: EasingFunction | keyof typeof Easing;\n onUpdate?: (progress: number) => void;\n onComplete?: () => void;\n}\n\nexport interface FadeTransitionOptions extends SceneTransitionOptions {\n color?: THREE.ColorRepresentation;\n}\n\n/**\n * SceneTransition provides smooth animated transitions between Three.js scenes.\n *\n * Supports multiple transition types:\n * - Fade: Fade to a color (black, white, etc.) and back\n * - Crossfade: Directly blend from one scene to another\n * - Blur: Blur out the first scene and blur in the second\n *\n * @example\n * ```typescript\n * const sceneTransition = new SceneTransition(renderer);\n *\n * // Fade to black transition\n * sceneTransition.fade(sceneA, sceneB, camera, {\n * duration: 1000,\n * color: 0x000000,\n * easing: 'easeInOutCubic'\n * });\n *\n * // Direct crossfade\n * sceneTransition.crossfade(sceneA, sceneB, camera, {\n * duration: 1500\n * });\n * ```\n */\nexport class SceneTransition {\n private renderer: THREE.WebGLRenderer;\n\n private currentScene: THREE.Scene | null = null;\n private targetScene: THREE.Scene | null = null;\n private camera: THREE.Camera | null = null;\n\n private transitionProgress = 0;\n private transitionDuration = 1000;\n private transitionStartTime = 0;\n private isTransitioning = false;\n private transitionType: 'fade' | 'crossfade' | 'blur' | null = null;\n private easingFunction: EasingFunction;\n\n private renderTargetA: THREE.WebGLRenderTarget;\n private renderTargetB: THREE.WebGLRenderTarget;\n private blendScene: THREE.Scene;\n private blendCamera: THREE.OrthographicCamera;\n private fadeMaterial: THREE.ShaderMaterial;\n private crossfadeMaterial: THREE.ShaderMaterial;\n\n private fadeColor: THREE.Color = new THREE.Color(0x000000);\n\n private onUpdateCallback?: (progress: number) => void;\n private onCompleteCallback?: () => void;\n\n constructor(renderer: THREE.WebGLRenderer) {\n this.renderer = renderer;\n this.easingFunction = Easing.cubicInOut;\n\n // Create render targets for dual-scene rendering\n const size = renderer.getSize(new THREE.Vector2());\n this.renderTargetA = new THREE.WebGLRenderTarget(size.x, size.y);\n this.renderTargetB = new THREE.WebGLRenderTarget(size.x, size.y);\n\n // Create blend scene\n this.blendScene = new THREE.Scene();\n this.blendCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n\n // Fade material (fade to color and back)\n this.fadeMaterial = new THREE.ShaderMaterial({\n uniforms: {\n tDiffuseA: { value: this.renderTargetA.texture },\n tDiffuseB: { value: this.renderTargetB.texture },\n mixRatio: { value: 0.0 },\n fadeColor: { value: new THREE.Color(0x000000) },\n },\n vertexShader: fadeTransitionSceneShader.vertexShader,\n fragmentShader: fadeTransitionSceneShader.fragmentShader,\n });\n\n // Crossfade material (direct blend)\n this.crossfadeMaterial = new THREE.ShaderMaterial({\n uniforms: {\n tDiffuseA: { value: this.renderTargetA.texture },\n tDiffuseB: { value: this.renderTargetB.texture },\n mixRatio: { value: 0.0 },\n },\n vertexShader: crossfadeShader.vertexShader,\n fragmentShader: crossfadeShader.fragmentShader,\n });\n\n const blendPlane = new THREE.PlaneGeometry(2, 2);\n const blendMesh = new THREE.Mesh(blendPlane, this.fadeMaterial);\n this.blendScene.add(blendMesh);\n }\n\n /**\n * Fade transition: Fades to a color and then fades in the new scene\n */\n fade(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n options: FadeTransitionOptions = {}\n ): void {\n this.startTransition(fromScene, toScene, camera, 'fade', options);\n\n if (options.color !== undefined) {\n this.fadeColor.set(options.color);\n this.fadeMaterial.uniforms.fadeColor.value.copy(this.fadeColor);\n }\n\n // Switch to fade material\n const mesh = this.blendScene.children[0] as THREE.Mesh;\n mesh.material = this.fadeMaterial;\n }\n\n /**\n * Crossfade transition: Directly blends from one scene to another\n */\n crossfade(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n options: SceneTransitionOptions = {}\n ): void {\n this.startTransition(fromScene, toScene, camera, 'crossfade', options);\n\n // Switch to crossfade material\n const mesh = this.blendScene.children[0] as THREE.Mesh;\n mesh.material = this.crossfadeMaterial;\n }\n\n /**\n * Blur transition: Blurs out first scene, then blurs in second scene\n * Note: This uses the fade material with a neutral gray for a blur-like effect\n * For true blur, you'd need post-processing passes\n */\n blur(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n options: SceneTransitionOptions = {}\n ): void {\n // For now, use fade with gray as a simple approximation\n // A full blur implementation would require post-processing\n this.fade(fromScene, toScene, camera, { ...options, color: 0x808080 });\n }\n\n /**\n * Internal method to start a transition\n */\n private startTransition(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n type: 'fade' | 'crossfade' | 'blur',\n options: SceneTransitionOptions\n ): void {\n this.currentScene = fromScene;\n this.targetScene = toScene;\n this.camera = camera;\n this.transitionType = type;\n this.transitionDuration = options.duration ?? 1000;\n this.transitionStartTime = performance.now();\n this.transitionProgress = 0;\n this.isTransitioning = true;\n this.onUpdateCallback = options.onUpdate;\n this.onCompleteCallback = options.onComplete;\n\n // Set easing function\n if (options.easing) {\n if (typeof options.easing === 'string') {\n this.easingFunction = Easing[options.easing];\n } else {\n this.easingFunction = options.easing;\n }\n }\n }\n\n /**\n * Update the transition. Call this in your render loop.\n */\n update(): void {\n if (!this.isTransitioning) {\n return;\n }\n\n const now = performance.now();\n const elapsed = now - this.transitionStartTime;\n const linearProgress = Math.min(elapsed / this.transitionDuration, 1);\n this.transitionProgress = this.easingFunction(linearProgress);\n\n if (this.onUpdateCallback) {\n this.onUpdateCallback(this.transitionProgress);\n }\n\n if (linearProgress >= 1) {\n // Transition complete\n this.isTransitioning = false;\n this.currentScene = this.targetScene;\n this.targetScene = null;\n\n if (this.onCompleteCallback) {\n this.onCompleteCallback();\n }\n }\n }\n\n /**\n * Render the scene with transition blending\n */\n render(): void {\n if (!this.isTransitioning || !this.currentScene || !this.targetScene || !this.camera) {\n // No transition, render current scene normally\n if (this.currentScene && this.camera) {\n this.renderer.setRenderTarget(null);\n this.renderer.render(this.currentScene, this.camera);\n }\n return;\n }\n\n // Render both scenes to separate render targets\n this.renderer.setRenderTarget(this.renderTargetA);\n this.renderer.render(this.currentScene, this.camera);\n\n this.renderer.setRenderTarget(this.renderTargetB);\n this.renderer.render(this.targetScene, this.camera);\n\n // Update blend material uniforms\n if (this.transitionType === 'fade') {\n this.fadeMaterial.uniforms.mixRatio.value = this.transitionProgress;\n } else if (this.transitionType === 'crossfade') {\n this.crossfadeMaterial.uniforms.mixRatio.value = this.transitionProgress;\n }\n\n // Blend the two renders\n this.renderer.setRenderTarget(null);\n this.renderer.render(this.blendScene, this.blendCamera);\n }\n\n /**\n * Get the current active scene\n */\n getCurrentScene(): THREE.Scene | null {\n return this.currentScene;\n }\n\n /**\n * Check if a transition is currently in progress\n */\n getIsTransitioning(): boolean {\n return this.isTransitioning;\n }\n\n /**\n * Get the current transition progress (0-1)\n */\n getProgress(): number {\n return this.transitionProgress;\n }\n\n /**\n * Set the current scene (useful for initialization)\n */\n setCurrentScene(scene: THREE.Scene): void {\n this.currentScene = scene;\n }\n\n /**\n * Resize the render targets when the renderer size changes\n */\n setSize(width: number, height: number): void {\n this.renderTargetA.setSize(width, height);\n this.renderTargetB.setSize(width, height);\n }\n\n /**\n * Dispose of resources\n */\n dispose(): void {\n this.renderTargetA.dispose();\n this.renderTargetB.dispose();\n this.fadeMaterial.dispose();\n this.crossfadeMaterial.dispose();\n }\n}\n","import * as THREE from 'three';\nimport { Easing, EasingFunction } from '../constants/Easing';\nimport { blurTransitionShader } from '../shaders/blurTransitionShader';\nimport { fadeShader } from '../shaders/fadeShader';\n\nexport interface SceneTransitionFXOptions {\n duration?: number;\n easing?: EasingFunction | keyof typeof Easing;\n onUpdate?: (progress: number) => void;\n onComplete?: () => void;\n}\n\nexport interface BloomTransitionOptions extends SceneTransitionFXOptions {\n maxBloom?: number;\n}\n\nexport interface BlurTransitionOptions extends SceneTransitionFXOptions {\n maxBlur?: number;\n kernelSize?: number;\n}\n\nexport interface GlitchTransitionOptions extends SceneTransitionFXOptions {\n maxIntensity?: number;\n}\n\nexport interface FadeTransitionOptions extends SceneTransitionFXOptions {\n color?: THREE.ColorRepresentation;\n}\n\n/**\n * SceneTransitionFX provides advanced post-processing transitions between Three.js scenes.\n *\n * Uses EffectComposer for sophisticated visual effects:\n * - Bloom: Bright bloom effect that peaks at transition midpoint, washing out to white\n * - Blur: Progressive blur effect that peaks at midpoint, blurring scenes to oblivion\n * - Fade: Classic fade through a color (black, white, or custom)\n * - Glitch: Digital distortion/glitch effect with heavy artifacts\n *\n * Built-in shader passes for blur and fade are automatically created. For bloom and glitch\n * effects, you'll need to provide those passes manually.\n *\n * Note: Requires post-processing imports from three/addons\n *\n * @example\n * ```typescript\n * import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';\n * import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';\n * import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';\n * import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';\n *\n * const composer = new EffectComposer(renderer);\n * const renderPass = new RenderPass(sceneA, camera);\n * composer.addPass(renderPass);\n *\n * // Pass ShaderPass to enable built-in blur and fade effects\n * const sceneTransitionFX = new SceneTransitionFX(renderer, composer, ShaderPass);\n *\n * // Blur and fade transitions work out of the box\n * sceneTransitionFX.blur(sceneA, sceneB, camera, { duration: 2000 });\n * sceneTransitionFX.fade(sceneA, sceneB, camera, { duration: 2000, color: 0x000000 });\n *\n * // For bloom, provide the pass manually\n * const bloomPass = new UnrealBloomPass(new THREE.Vector2(width, height), 0, 0.4, 0.85);\n * bloomPass.enabled = false;\n * composer.addPass(bloomPass);\n * sceneTransitionFX.setBloomPass(bloomPass);\n * sceneTransitionFX.bloom(sceneA, sceneB, camera, { duration: 2000, maxBloom: 15.0 });\n * ```\n */\nexport class SceneTransitionFX {\n private renderer: THREE.WebGLRenderer;\n private composer: any; // EffectComposer type\n\n private currentScene: THREE.Scene | null = null;\n private targetScene: THREE.Scene | null = null;\n private camera: THREE.Camera | null = null;\n\n private transitionProgress = 0;\n private transitionDuration = 1000;\n private transitionStartTime = 0;\n private isTransitioning = false;\n private transitionType: 'blur' | 'bloom' | 'fade' | 'glitch' | null = null;\n private easingFunction: EasingFunction;\n\n private renderPass: any; // RenderPass\n private bloomPass: any; // UnrealBloomPass\n private glitchPass: any; // GlitchPass\n private blurPass: any; // ShaderPass for blur effect\n private fadePass: any; // ShaderPass for fade effect\n\n private maxBloomStrength = 3.0;\n private maxBlurAmount = 10.0;\n private maxGlitchIntensity = 1.0;\n private fadeColor = new THREE.Color(0x000000);\n\n private onUpdateCallback?: (progress: number) => void;\n private onCompleteCallback?: () => void;\n\n constructor(renderer: THREE.WebGLRenderer, composer: any, ShaderPass?: any) {\n this.renderer = renderer;\n this.composer = composer;\n this.easingFunction = Easing.cubicInOut;\n\n // Get existing passes (assumes user has set up RenderPass)\n this.renderPass = composer.passes.find((pass: any) => pass.constructor.name === 'RenderPass');\n\n // Create default blur and fade passes if ShaderPass is provided\n if (ShaderPass) {\n this.createDefaultPasses(ShaderPass);\n }\n }\n\n /**\n * Create default shader passes for blur and fade effects\n */\n private createDefaultPasses(ShaderPass: any): void {\n try {\n // Create blur pass with proper uniforms\n const blurShaderCopy = {\n uniforms: {\n tDiffuse: { value: null },\n kernelSize: { value: 0.0 },\n resolution: {\n value: new THREE.Vector2(\n this.renderer.domElement.width,\n this.renderer.domElement.height\n )\n }\n },\n vertexShader: blurTransitionShader.vertexShader,\n fragmentShader: blurTransitionShader.fragmentShader,\n };\n this.blurPass = new ShaderPass(blurShaderCopy);\n this.blurPass.enabled = false;\n this.composer.addPass(this.blurPass);\n\n // Create fade pass with proper uniforms\n const fadeShaderCopy = {\n uniforms: {\n tDiffuse: { value: null },\n fadeAmount: { value: 0.0 },\n fadeColor: { value: new THREE.Color(0x000000) },\n },\n vertexShader: fadeShader.vertexShader,\n fragmentShader: fadeShader.fragmentShader,\n };\n this.fadePass = new ShaderPass(fadeShaderCopy);\n this.fadePass.enabled = false;\n this.composer.addPass(this.fadePass);\n } catch (e) {\n console.warn('SceneTransitionFX: Could not create default passes:', e);\n }\n }\n\n /**\n * Set the bloom pass for bloom transitions\n */\n setBloomPass(bloomPass: any): void {\n this.bloomPass = bloomPass;\n }\n\n /**\n * Set the glitch pass for glitch transitions\n */\n setGlitchPass(glitchPass: any): void {\n this.glitchPass = glitchPass;\n }\n\n /**\n * Set the blur pass for blur transitions\n */\n setBlurPass(blurPass: any): void {\n this.blurPass = blurPass;\n }\n\n /**\n * Set the fade pass for fade transitions\n */\n setFadePass(fadePass: any): void {\n this.fadePass = fadePass;\n }\n\n /**\n * Bloom transition: Bright bloom effect that peaks at transition midpoint\n */\n bloom(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n options: BloomTransitionOptions = {}\n ): void {\n if (!this.bloomPass) {\n console.warn('SceneTransitionFX: Bloom pass not set. Call setBloomPass() first.');\n return;\n }\n\n this.maxBloomStrength = options.maxBloom ?? 3.0;\n this.startTransition(fromScene, toScene, camera, 'bloom', options);\n this.bloomPass.enabled = true;\n }\n\n /**\n * Blur transition: Progressively blur scenes to oblivion and back\n */\n blur(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n options: BlurTransitionOptions = {}\n ): void {\n if (!this.blurPass) {\n console.warn('SceneTransitionFX: Blur pass not set. Call setBlurPass() first.');\n return;\n }\n\n this.maxBlurAmount = options.maxBlur ?? 10.0;\n this.startTransition(fromScene, toScene, camera, 'blur', options);\n this.blurPass.enabled = true;\n }\n\n /**\n * Fade transition: Classic fade through a color (black, white, or custom)\n */\n fade(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n options: FadeTransitionOptions = {}\n ): void {\n if (!this.fadePass) {\n console.warn('SceneTransitionFX: Fade pass not set. Call setFadePass() first.');\n return;\n }\n\n if (options.color !== undefined) {\n this.fadeColor.set(options.color);\n this.fadePass.uniforms.fadeColor.value.copy(this.fadeColor);\n }\n\n this.startTransition(fromScene, toScene, camera, 'fade', options);\n this.fadePass.enabled = true;\n }\n\n /**\n * Glitch transition: Digital distortion effect\n */\n glitch(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n options: GlitchTransitionOptions = {}\n ): void {\n if (!this.glitchPass) {\n console.warn('SceneTransitionFX: Glitch pass not set. Call setGlitchPass() first.');\n return;\n }\n\n this.maxGlitchIntensity = options.maxIntensity ?? 1.0;\n this.startTransition(fromScene, toScene, camera, 'glitch', options);\n this.glitchPass.enabled = true;\n }\n\n /**\n * Internal method to start a transition\n */\n private startTransition(\n fromScene: THREE.Scene,\n toScene: THREE.Scene,\n camera: THREE.Camera,\n type: 'blur' | 'bloom' | 'fade' | 'glitch',\n options: SceneTransitionFXOptions\n ): void {\n this.currentScene = fromScene;\n this.targetScene = toScene;\n this.camera = camera;\n this.transitionType = type;\n this.transitionDuration = options.duration ?? 1000;\n this.transitionStartTime = performance.now();\n this.transitionProgress = 0;\n this.isTransitioning = true;\n this.onUpdateCallback = options.onUpdate;\n this.onCompleteCallback = options.onComplete;\n\n // Set easing function\n if (options.easing) {\n if (typeof options.easing === 'string') {\n this.easingFunction = Easing[options.easing];\n } else {\n this.easingFunction = options.easing;\n }\n }\n\n // Update render pass to use current scene\n if (this.renderPass) {\n this.renderPass.scene = fromScene;\n this.renderPass.camera = camera;\n }\n }\n\n /**\n * Update the transition. Call this in your render loop.\n */\n update(): void {\n if (!this.isTransitioning) {\n return;\n }\n\n const now = performance.now();\n const elapsed = now - this.transitionStartTime;\n const linearProgress = Math.min(elapsed / this.transitionDuration, 1);\n this.transitionProgress = this.easingFunction(linearProgress);\n\n // Update effect parameters based on transition type\n if (this.transitionType === 'bloom' && this.bloomPass) {\n // Bloom peaks at midpoint (0 -> max -> 0)\n const bloomCurve = 1 - Math.abs(this.transitionProgress * 2 - 1);\n this.bloomPass.strength = bloomCurve * this.maxBloomStrength;\n } else if (this.transitionType === 'blur' && this.blurPass) {\n // Blur peaks at midpoint (0 -> max -> 0)\n const blurCurve = 1 - Math.abs(this.transitionProgress * 2 - 1);\n this.blurPass.uniforms.kernelSize.value = blurCurve * this.maxBlurAmount;\n } else if (this.transitionType === 'fade' && this.fadePass) {\n // Fade: fade out first half (0 -> 1), fade in second half (1 -> 0)\n const fadeAmount = this.transitionProgress < 0.5\n ? this.transitionProgress * 2 // Fade out: 0 -> 1\n : 2 - this.transitionProgress * 2; // Fade in: 1 -> 0\n this.fadePass.uniforms.fadeAmount.value = fadeAmount;\n } else if (this.transitionType === 'glitch' && this.glitchPass) {\n // Glitch peaks at midpoint\n const glitchCurve = 1 - Math.abs(this.transitionProgress * 2 - 1);\n // GlitchPass doesn't have a strength property, so we enable/disable based on intensity\n this.glitchPass.enabled = glitchCurve > 0.3; // Only show glitch when intensity is high\n }\n\n // Switch scenes at midpoint\n if (this.transitionProgress >= 0.5 && this.renderPass && this.renderPass.scene === this.currentScene) {\n this.renderPass.scene = this.targetScene;\n }\n\n if (this.onUpdateCallback) {\n this.onUpdateCallback(this.transitionProgress);\n }\n\n if (linearProgress >= 1) {\n // Transition complete\n this.isTransitioning = false;\n this.currentScene = this.targetScene;\n this.targetScene = null;\n\n // Update render pass to use the new current scene\n if (this.renderPass && this.currentScene) {\n this.renderPass.scene = this.currentScene;\n }\n\n // Disable effects\n if (this.bloomPass) {\n this.bloomPass.enabled = false;\n this.bloomPass.strength = 0;\n }\n if (this.blurPass) {\n this.blurPass.enabled = false;\n this.blurPass.uniforms.kernelSize.value = 0;\n }\n if (this.fadePass) {\n this.fadePass.enabled = false;\n this.fadePass.uniforms.fadeAmount.value = 0;\n }\n if (this.glitchPass) {\n this.glitchPass.enabled = false;\n }\n\n if (this.onCompleteCallback) {\n this.onCompleteCallback();\n }\n }\n }\n\n /**\n * Render using the effect composer\n */\n render(): void {\n this.composer.render();\n }\n\n /**\n * Get the current active scene\n */\n getCurrentScene(): THREE.Scene | null {\n return this.currentScene;\n }\n\n /**\n * Check if a transition is currently in progress\n */\n getIsTransitioning(): boolean {\n return this.isTransitioning;\n }\n\n /**\n * Get the current transition progress (0-1)\n */\n getProgress(): number {\n return this.transitionProgress;\n }\n\n /**\n * Set the current scene (useful for initialization)\n */\n setCurrentScene(scene: THREE.Scene): void {\n this.currentScene = scene;\n if (this.renderPass) {\n this.renderPass.scene = scene;\n }\n }\n\n /**\n * Resize the composer when the renderer size changes\n */\n setSize(width: number, height: number): void {\n this.composer.setSize(width, height);\n\n // Update blur pass resolution uniform if it exists\n if (this.blurPass && this.blurPass.uniforms && this.blurPass.uniforms.resolution) {\n this.blurPass.uniforms.resolution.value.set(width, height);\n }\n }\n\n /**\n * Dispose of resources\n */\n dispose(): void {\n // Composer cleanup is handled externally\n }\n}\n","import { Box3, Object3D, Vector3 } from \"three\";\nimport { BoxSide } from \"../constants/BoxSide\";\n\n/**\n * Aligns an array of Object3D objects (or subclasses) to a specified side\n * (left, right, top, bottom, front, or back) based on their world-space bounding boxes.\n */\nexport function alignToEdge<T extends Object3D>(objects: T[], side: BoxSide): void {\n if (objects.length === 0) {\n throw new Error(\"No objects provided for alignment.\");\n }\n\n const worldBoundingBox = new Box3();\n const worldPosition = new Vector3();\n\n // Precompute world-space bounding boxes and positions for all objects\n const objectData = objects.map((object) => {\n worldBoundingBox.setFromObject(object); // Accounts for scale and rotation\n object.getWorldPosition(worldPosition);\n\n return {\n object,\n boundingBox: worldBoundingBox.clone(), // Clone to avoid overwriting\n worldPosition: worldPosition.clone(),\n };\n });\n\n // Compute the reference alignment value based on the specified side\n const referenceValue = objectData.reduce(\n (acc, { boundingBox }) => {\n switch (side) {\n case BoxSide.LEFT:\n return Math.min(acc, boundingBox.min.x);\n case BoxSide.RIGHT:\n return Math.max(acc, boundingBox.max.x);\n case BoxSide.BOTTOM:\n return Math.min(acc, boundingBox.min.y);\n case BoxSide.TOP:\n return Math.max(acc, boundingBox.max.y);\n case BoxSide.BACK:\n return Math.min(acc, boundingBox.min.z);\n case BoxSide.FRONT:\n return Math.max(acc, boundingBox.max.z);\n default:\n throw new Error(`Unsupported side type: ${side}`);\n }\n },\n side === BoxSide.RIGHT || side === BoxSide.TOP || side === BoxSide.FRONT ? -Infinity : Infinity,\n );\n\n // Align each object to the computed reference value\n objectData.forEach(({ object, boundingBox }) => {\n switch (side) {\n case BoxSide.LEFT:\n object.position.x += referenceValue - boundingBox.min.x;\n break;\n case BoxSide.RIGHT:\n object.position.x += referenceValue - boundingBox.max.x;\n break;\n case BoxSide.BOTTOM:\n object.position.y += referenceValue - boundingBox.min.y;\n break;\n case BoxSide.TOP:\n object.position.y += referenceValue - boundingBox.max.y;\n break;\n case BoxSide.BACK:\n object.position.z += referenceValue - boundingBox.min.z;\n break;\n case BoxSide.FRONT:\n object.position.z += referenceValue - boundingBox.max.z;\n break;\n }\n });\n}\n","import { Direction } from \"../constants/Direction\";\nimport { Box3, Object3D, Vector3 } from \"three\";\n\n/**\n * Aligns an array of `Object3D` objects along a specified direction with optional spacing.\n */\nexport function alignToRow<T extends Object3D>(\n objects: T[],\n direction: Vector3 = Direction.RIGHT,\n spacing: number = 0,\n): void {\n // Ensure the direction vector is normalized\n const alignmentDirection = direction.clone().normalize();\n\n // Start the position tracker for alignment\n let currentPosition = new Vector3();\n const worldBoundingBox = new Box3();\n\n // Align each object\n objects.forEach((object) => {\n // Compute the world-space bounding box\n worldBoundingBox.setFromObject(object); // Accounts for scale and rotation\n\n // Calculate the object's size along the alignment direction\n const sizeVector = new Vector3(\n worldBoundingBox.max.x - worldBoundingBox.min.x,\n worldBoundingBox.max.y - worldBoundingBox.min.y,\n worldBoundingBox.max.z - worldBoundingBox.min.z,\n );\n const size = sizeVector.dot(alignmentDirection);\n\n // Compute the object's center in world space\n const objectCenter = new Vector3();\n worldBoundingBox.getCenter(objectCenter);\n\n // Adjust the object's position so its center aligns with the current position\n const offset = alignmentDirection.clone().multiplyScalar(size / 2);\n object.position.copy(currentPosition.clone().add(offset).sub(objectCenter).add(object.position));\n\n // Update the position tracker for the next object\n currentPosition.add(alignmentDirection.clone().multiplyScalar(size + spacing));\n });\n}\n","import { Box3, BufferGeometry, Float32BufferAttribute, InstancedMesh, Matrix4, Object3D, Quaternion, Vector3 } from \"three\";\n\n//------------------------------\n// Object3D\n//------------------------------\n\n/**\n * Align an Object3D to a surface by adjusting its position.\n */\nexport function alignObjectToSurface(object: Object3D, targetPosition: Vector3, offset: Vector3 = new Vector3(0, 0, 0)): void {\n const boundingBox = new Box3().setFromObject(object);\n\n if (!boundingBox.isEmpty()) {\n const min = boundingBox.min;\n\n // Compute bottom center in world space\n const bottomCenter = new Vector3((min.x + boundingBox.max.x) / 2, min.y, (min.z + boundingBox.max.z) / 2);\n object.localToWorld(bottomCenter);\n\n // Calculate adjustment vector in world space\n const adjustment = targetPosition.clone().sub(bottomCenter).add(offset);\n\n // Transform adjustment to local space and apply\n const localAdjustment = object.worldToLocal(adjustment.clone());\n object.position.add(localAdjustment);\n } else {\n console.warn(\"The object has no geometry or is not visible.\");\n }\n}\n\n//------------------------------\n// Buffer Geometry\n//------------------------------\n\n/**\n * Align a BufferGeometry to a surface by adjusting its vertices.\n */\nexport function alignBufferGeometryToSurface(geometry: BufferGeometry, targetPositionY: number): void {\n const boundingBox = new Box3().setFromBufferAttribute(new Float32BufferAttribute(geometry.attributes.position.array, 3));\n\n if (!boundingBox.isEmpty()) {\n const minY = boundingBox.min.y;\n\n // Translate the geometry to align the bottom to the target position\n geometry.translate(0, targetPositionY - minY, 0);\n } else {\n console.warn(\"The geometry is empty or invalid.\");\n }\n}\n\n//------------------------------\n// Instanced Mesh\n//------------------------------\n\n/**\n * Align an InstancedMesh to a surface.\n */\nexport function alignInstancedMeshToSurface(\n instancedMesh: InstancedMesh,\n targetPosition: Vector3,\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n // Compute the bounding box for the entire InstancedMesh\n const boundingBox = new Box3().setFromObject(instancedMesh);\n\n if (!boundingBox.isEmpty()) {\n // Find the bottom Y coordinate of the bounding box\n const minY = boundingBox.min.y;\n\n // Compute the adjustment needed to align the bottom of the InstancedMesh to the target position\n const adjustment = new Vector3(0, targetPosition.y - minY, 0).add(offset);\n\n // Transform adjustment to local space and apply to position\n const localAdjustment = instancedMesh.worldToLocal(adjustment.clone());\n instancedMesh.position.add(localAdjustment);\n } else {\n console.warn(\"The InstancedMesh has no geometry or is not visible.\");\n }\n}\n\n/**\n * Align a specific instance in an InstancedMesh to a surface.\n */\nexport function alignInstancedMeshIndexToSurface(\n instancedMesh: InstancedMesh,\n targetPosition: Vector3,\n instanceIndex: number,\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n const boundingBox = new Box3().setFromObject(instancedMesh);\n\n if (!boundingBox.isEmpty()) {\n const minY = boundingBox.min.y;\n\n // Get the instance's current transformation matrix\n const matrix = new Matrix4();\n instancedMesh.getMatrixAt(instanceIndex, matrix);\n\n // Decompose the matrix to extract position, rotation, and scale\n const position = new Vector3();\n const quaternion = new Quaternion();\n const scale = new Vector3();\n matrix.decompose(position, quaternion, scale);\n\n // Transform targetPosition to the instanced mesh's local space\n const localTargetPosition = instancedMesh.worldToLocal(targetPosition.clone());\n\n // Adjust the position of the instance\n position.y = localTargetPosition.y - minY + offset.y;\n\n // Recompose the matrix and update the instance\n matrix.compose(position, quaternion, scale);\n instancedMesh.setMatrixAt(instanceIndex, matrix);\n\n // Mark the instance matrix as needing an update\n instancedMesh.instanceMatrix.needsUpdate = true;\n } else {\n console.warn(\"The instanced mesh has invalid geometry.\");\n }\n}\n","import { Box3, Mesh, Object3D, Vector3 } from \"three\";\n\n//------------------------------\n// Object3D\n//------------------------------\n\n/**\n * Centers an `Object3D` relative to a specified target position with an optional offset.\n *\n * This function calculates the bounding box center of the given `Object3D` and adjusts\n * its position so that it is centered at the specified target position, with an optional\n * offset applied. The centering respects the object's current transformation, including\n * its scale and rotation.\n */\nexport function centerObject<T extends Object3D>(object: T, target = new Vector3(0, 0, 0), offset = new Vector3(0, 0, 0)) {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n const totalOffset = new Vector3().addVectors(target, offset);\n const adjustment = new Vector3().subVectors(totalOffset, center);\n\n object.position.add(adjustment);\n}\n\n/**\n * Centers the geometry of an `Object3D` relative to a target position with an optional offset.\n *\n * This function calculates the bounding box center of the given `Object3D` and adjusts its\n * geometry's position by translating it such that the geometry is centered at the specified\n * target position, with an optional offset applied. Unlike modifying the `position` property,\n * this function directly translates the geometry within the object's local space.\n */\nexport function centerObjectGeometry<T extends Object3D>(\n object: T,\n target: Vector3 = new Vector3(0, 0, 0),\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n const totalTarget = new Vector3().addVectors(target, offset);\n\n object.translateX(totalTarget.x - center.x);\n object.translateY(totalTarget.y - center.y);\n object.translateZ(totalTarget.z - center.z);\n object.updateMatrixWorld(true);\n}\n\n//------------------------------\n// Mesh\n//------------------------------\n\n/**\n * Centers the geometry of a `Mesh` relative to a target position with an optional offset.\n *\n * This function calculates the bounding box center of the `Mesh` geometry and adjusts its\n * position by translating the geometry such that it is centered at the specified target\n * position, with an optional offset applied. The function modifies the geometry directly,\n * leaving the `Mesh`'s transformation properties (`position`, `rotation`, `scale`) unchanged.\n */\nexport function centerMeshGeometry<T extends Mesh>(\n mesh: T,\n target: Vector3 = new Vector3(0, 0, 0),\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n // Compute the bounding box for the geometry\n mesh.geometry.computeBoundingBox();\n const box = mesh.geometry.boundingBox;\n\n if (box) {\n const center = box.getCenter(new Vector3());\n const totalTarget = new Vector3().addVectors(target, offset);\n const translationOffset = new Vector3().subVectors(totalTarget, center);\n\n mesh.geometry.translate(translationOffset.x, translationOffset.y, translationOffset.z);\n }\n}\n\nexport const Center = {\n object: centerObject,\n objectGeometry: centerObjectGeometry,\n meshGeometry: centerMeshGeometry,\n};\n","//------------------------------\n// Hex\n//------------------------------\n\n/**\n * Convert hex color code color string to RGB array\n */\nexport function parseHexCode(hex: string): [number, number, number] {\n const bigint = parseInt(hex.slice(1), 16);\n return [\n (bigint >> 16) & 255, // r\n (bigint >> 8) & 255, // g\n bigint & 255, // b\n ];\n}\n\nexport function hexToHsl(hex: number): [number, number, number] {\n const [r, g, b] = hexToRgb(hex);\n return rgbToHsl(r, g, b);\n}\n\n/**\n * Convert hexadecimal literal numeric color value to RGB array\n * @param hex\n */\nexport function hexToRgb(hex: number): [number, number, number] {\n const r = (hex >> 16) & 0xff;\n const g = (hex >> 8) & 0xff;\n const b = hex & 0xff;\n\n return [r, g, b];\n}\n\n//------------------------------\n// HSL\n//------------------------------\n\n/**\n * Example usage:\n * ```\n * const h = 200; // Hue\n * const s = 75; // Saturation\n * const l = 50; // Lightness\n *\n * const [ r, g, b ] = hslToHex(h, s, l);\n * ```\n */\nexport function hslToHex(h: number, s: number, l: number): [number, number, number] {\n s /= 100;\n l /= 100;\n\n function hueToRgb(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n }\n\n let r: number, g: number, b: number;\n\n if (s === 0) {\n r = g = b = l; // Achromatic (grey)\n } else {\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n r = hueToRgb(p, q, h / 360 + 1 / 3);\n g = hueToRgb(p, q, h / 360);\n b = hueToRgb(p, q, h / 360 - 1 / 3);\n }\n\n // Convert RGB to hex\n const toHexValue = (x: number): number => Math.round(x * 255);\n\n return [\n toHexValue(r),\n toHexValue(g),\n toHexValue(b),\n ];\n}\n\nexport function hslToRgb(h: number, s: number, l: number): [number, number, number] {\n s /= 100;\n l /= 100;\n const k = (n: number) => (n + h / 30) % 12;\n const a = s * Math.min(l, 1 - l);\n const f = (n: number) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));\n\n return [f(0) * 255, f(8) * 255, f(4) * 255];\n}\n\n//------------------------------\n// RGB\n//------------------------------\n\nexport function normalizeRgb(r: number, g: number, b: number): [number, number, number] {\n return [r / 255, g / 255, b / 255];\n}\n\nexport function rgbToHex(r: number, g: number, b: number): number {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n\n return (r << 16) + (g << 8) + b;\n}\n\n/**\n * Converts an RGB color to HSL.\n *\n * Example usage:\n * ```\n * const rgbColor = { r: 255, g: 0, b: 0 }; // Red\n * const hslColor = rgbToHsl(rgbColor.r, rgbColor.g, rgbColor.b);\n * console.log(hslColor); // Output: { h: 0, s: 100, l: 50 }\n * ```\n */\nexport function rgbToHsl(r: number, g: number, b: number): [number, number, number] {\n // Normalize r, g, b values to the range 0–1\n r /= 255;\n g /= 255;\n b /= 255;\n\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const delta = max - min;\n\n let h = 0;\n let s = 0;\n const l = (max + min) / 2;\n\n // Calculate hue\n if (delta !== 0) {\n if (max === r) {\n h = ((g - b) / delta + (g < b ? 6 : 0)) * 60;\n } else if (max === g) {\n h = ((b - r) / delta + 2) * 60;\n } else if (max === b) {\n h = ((r - g) / delta + 4) * 60;\n }\n }\n\n // Calculate saturation\n if (delta !== 0) {\n s = delta / (1 - Math.abs(2 * l - 1));\n }\n\n // Convert h and s to percentages\n h = Math.round(h);\n s = Math.round(s * 100);\n const lPercent = Math.round(l * 100);\n\n return [ h, s, lPercent ];\n}\n\n//------------------------------\n// Distance functions\n//------------------------------\n\n/**\n * Calculate the Euclidean distance between two colors in RGB space\n * distance = sqrt((r1 - r2)^2 + (g1 - g2)^2 + (b1 - b2)^2)\n */\nexport function calculateDistance(color1: [number, number, number], color2: [number, number, number]): number {\n return Math.sqrt(\n Math.pow(color1[0] - color2[0], 2) +\n Math.pow(color1[1] - color2[1], 2) +\n Math.pow(color1[2] - color2[2], 2),\n );\n}\n\n/**\n * Calculate the sum of absolute differences for each channel\n * difference = |r1 - r2| + |g1 - g2| + |b1 - b2|\n */\nexport function calculateChannelDifference(color1: [number, number, number], color2: [number, number, number]): number {\n return (\n Math.abs(color1[0] - color2[0]) + //\n Math.abs(color1[1] - color2[1]) +\n Math.abs(color1[2] - color2[2])\n );\n}\n\nexport function findClosestColor(inputColor: number, dataset: number[]): number | null {\n const inputRgb = hexToRgb(inputColor);\n let closestColor = null;\n let smallestDistance = Infinity;\n\n for (const entry of dataset) {\n const colorRgb = hexToRgb(entry);\n const distance = calculateDistance(inputRgb, colorRgb);\n\n if (distance < smallestDistance) {\n smallestDistance = distance;\n closestColor = entry;\n }\n }\n\n return closestColor;\n}\n\nexport function findClosestColorChannelWise(inputColor: number, dataset: number[]): number | null {\n const inputRgb = hexToRgb(inputColor);\n let closestColor = null;\n let smallestDifference = Infinity;\n\n for (const entry of dataset) {\n const colorRgb = hexToRgb(entry);\n const difference = calculateChannelDifference(inputRgb, colorRgb);\n\n if (difference < smallestDifference) {\n smallestDifference = difference;\n closestColor = entry;\n }\n }\n\n return closestColor;\n}\n\n//------------------------------\n// Palette generation\n//------------------------------\n\n/**\n * Example usage:\n * ```\n * const baseHue = Math.floor(Math.random() * 360);\n * const color1 = getAnalogousColors(baseHue);\n * const color2 = getAnalogousColors(baseHue);\n * ```\n */\nexport function getAnalogousColors(baseHue: number): [number, number, number] {\n const h = (baseHue + Math.floor(-30 + Math.random() * 61)) % 360; // ±30 degrees from baseHue\n const s = Math.floor(60 + Math.random() * 21); // Saturation: 60 - 80\n const l = Math.floor(50 + Math.random() * 21); // Lightness: 50 - 70\n return hslToRgb(h, s, l);\n}\n","import { Mesh, Vector3 } from \"three\";\n\n/**\n * Get the closest point on a mesh to a specified point.\n *\n * Example usage:\n * ```ts\n * const point = new Vector3(5, 2, 1); // The point to check against the mesh\n * const closestPoint = getClosestPointOnMesh(point, targetMesh);\n * ```\n */\nexport function findClosestPoint(point: Vector3, mesh: Mesh) {\n if (!mesh.geometry.isBufferGeometry) {\n throw new Error(\"Mesh must have a BufferGeometry.\");\n }\n\n const geometry = mesh.geometry;\n const positionAttribute = geometry.getAttribute(\"position\");\n const closestPoint = new Vector3();\n const tempPoint = new Vector3();\n let minDistance = Infinity;\n\n for (let i = 0; i < positionAttribute.count; i++) {\n tempPoint.fromBufferAttribute(positionAttribute, i);\n const distance = tempPoint.distanceTo(point);\n\n if (distance < minDistance) {\n minDistance = distance;\n closestPoint.copy(tempPoint);\n }\n }\n\n // Transform the closest point to world space (if the mesh is transformed)\n mesh.localToWorld(closestPoint);\n\n return closestPoint;\n}\n","import { Vector2 } from \"three\";\n\n/**\n * Normalizes a time value `t` between a minimum and maximum value.\n * @param t - The value to normalize.\n * @param min - The minimum value of the range.\n * @param max - The maximum value of the range.\n * @returns A normalized value between 0 and 1.\n */\nfunction normalizeT(t: number, min: number, max: number): number {\n return Math.max(0, Math.min(1, (t - min) / (max - min)));\n}\n\n/**\n * Generates an array of interpolated 2D points using an easing function.\n * @param curveFunction - The easing function to apply to the normalized value.\n * @param startRadius - The starting radius for interpolation.\n * @param endRadius - The ending radius for interpolation.\n * @param startHeight - The starting height for interpolation.\n * @param endHeight - The ending height for interpolation.\n * @param segments - The number of segments for interpolation (default is 20).\n * @param min - The minimum value of the normalization range (default is 0).\n * @param max - The maximum value of the normalization range (default is 1).\n * @returns An array of `Vector2` points representing the interpolated curve.\n */\nexport function interpolateCurve(\n curveFunction: (t: number) => number,\n startRadius: number,\n endRadius: number,\n startHeight: number,\n endHeight: number,\n segments: number = 20,\n min: number = 0,\n max: number = 1\n): Vector2[] {\n const points: Vector2[] = [];\n\n for (let i = 0; i <= segments; i++) {\n const t = i / segments; // Normalized value between 0 and 1\n const easedT = curveFunction(normalizeT(t, min, max));\n const x = startRadius + easedT * (endRadius - startRadius);\n const y = startHeight + t * (endHeight - startHeight);\n points.push(new Vector2(x, y));\n }\n\n return points;\n}\n","import { ParametricCurve } from \"../constants/ParametricCurve\";\nimport { Vector2 } from \"three\";\n\n/**\n * Function to create cubic Bezier curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createCubicCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the cubic curve\n * new THREE.Vector2(1.5, 3), // First control point (outward curve)\n * new THREE.Vector2(1.5, 4), // Second control point (outward curve)\n * new THREE.Vector2(0.5, 5), // End of the curve\n * 24, // Resolution of the quadratic curve\n * ),\n * ]\n * ```\n */\nexport const createCubicCurvePoints = (start: Vector2, control1: Vector2, control2: Vector2, end: Vector2, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.cubic(t, start.x, control1.x, control2.x, end.x);\n const y = ParametricCurve.cubic(t, start.y, control1.y, control2.y, end.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create damped curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createDampedCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the damped curve\n * new THREE.Vector2(1.5, 5), // End of the damped curve\n * 5, // Damping factor\n * 24, // Resolution of the damped curve\n * ),\n * ]\n * ```\n */\nexport const createDampedCurvePoints = (start: Vector2, end: Vector2, damping: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.damped(t, damping) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create exponential curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createExponentialCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the exponential curve\n * new THREE.Vector2(1.5, 5), // End of the exponential curve\n * 0.5, // Base of the exponential function\n * 2, // Exponential factor\n * 24 // Resolution of the exponential curve\n * ),\n * ]\n * ```\n */\nexport const createExponentialCurvePoints = (start: Vector2, end: Vector2, base: number, factor: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.exponential(t, base, factor) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create logarithmic curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createLogarithmicCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the logarithmic curve\n * new THREE.Vector2(1.5, 5), // End of the logarithmic curve\n * 0.5, // Base of the logarithmic function\n * 10, // Logarithmic factor\n * 24, // Resolution of the logarithmic curve\n * ),\n * ]\n * ```\n */\nexport const createLogarithmicCurvePoints = (start: Vector2, end: Vector2, base: number, factor: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.logarithmic(t, base, factor) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create parabolic curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createParabolicCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start point\n * new THREE.Vector2(0.5, 5), // End point\n * 1, // Coefficient for t^2 (controls curvature)\n * 0, // Coefficient for t (linear component)\n * 0, // Constant term (vertical offset)\n * 24, // Resolution\n * ),\n * ]\n * ```\n */\nexport const createParabolicCurvePoints = (start: Vector2, end: Vector2, a: number, b: number, c: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = a * t * t + b * t + c + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create quadratic Bezier curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createQuadraticCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the quadratic curve\n * new THREE.Vector2(1.5, 5), // Control point (outward curve)\n * new THREE.Vector2(0.5, 5), // End of the curve\n * 24, // Resolution of the quadratic curve\n * ),\n * ]\n * ```\n */\nexport const createQuadraticCurvePoints = (start: Vector2, control: Vector2, end: Vector2, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.quadratic(t, start.x, control.x, end.x);\n const y = ParametricCurve.quadratic(t, start.y, control.y, end.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create sigmoid curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createSigmoidCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the sigmoid curve\n * new THREE.Vector2(1.5, 5), // End of the sigmoid curve\n * 20, // Sigmoid steepness factor\n * 24, // Resolution of the sigmoid curve\n * ),\n * ]\n */\nexport const createSigmoidCurvePoints = (start: Vector2, end: Vector2, a: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.sigmoid(t, a) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\nexport const ParametricCurveUtils = {\n createCubicCurvePoints,\n createDampedCurvePoints,\n createExponentialCurvePoints,\n createLogarithmicCurvePoints,\n createParabolicCurvePoints,\n createQuadraticCurvePoints,\n createSigmoidCurvePoints,\n};\n","/**\n * Generates vertices for two triangles based upon a quad.\n *\n * Example usages:\n *\n * Create a face of a box:\n * ```\n * const frontQuad = createQuad(\n * [-1, -1, 1], // Bottom-left\n * [ 1, -1, 1], // Bottom-right\n * [-1, 1, 1], // Top-left\n * [ 1, 1, 1], // Top-right\n * [ 0, 0, 1] // Normal (facing forward)\n * );\n * ```\n *\n * Assembling a box:\n * ```\n * const vertices = [\n * ...createQuad([-1, -1, 1], [1, -1, 1], [-1, 1, 1], [1, 1, 1], [0, 0, 1]), // Front face\n * ...createQuad([1, -1, -1], [-1, -1, -1], [1, 1, -1], [-1, 1, -1], [0, 0, -1]), // Back face\n * ...createQuad([-1, 1, 1], [1, 1, 1], [-1, 1, -1], [1, 1, -1], [0, 1, 0]), // Top face\n * ...createQuad([-1, -1, -1], [1, -1, -1], [-1, -1, 1], [1, -1, 1], [0, -1, 0]), // Bottom face\n * ...createQuad([-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1], [-1, 0, 0]), // Left face\n * ...createQuad([1, -1, 1], [1, -1, -1], [1, 1, 1], [1, 1, -1], [1, 0, 0]), // Right face\n * ];\n * ```\n *\n * Generating Buffer Geometry:\n * ```\n * const positions = [];\n * const normals = [];\n * const uvs = [];\n *\n * for (const vertex of vertices) {\n * positions.push(...vertex.pos);\n * normals.push(...vertex.norm);\n * uvs.push(...vertex.uv);\n * }\n *\n * const geometry = new THREE.BufferGeometry();\n * geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3));\n * geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(normals), 3));\n * geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2));\n * ```\n */\nexport function createQuad(\n p1: [number, number, number], //\n p2: [number, number, number],\n p3: [number, number, number],\n p4: [number, number, number],\n normal?: [number, number, number],\n uv1: [number, number] = [0, 0],\n uv2: [number, number] = [1, 0],\n uv3: [number, number] = [0, 1],\n uv4: [number, number] = [1, 1],\n) {\n const normalVector = normal || calculateNormal(p1, p2, p3);\n\n return [\n // Triangle 1\n { pos: p1, norm: normalVector, uv: uv1 },\n { pos: p2, norm: normalVector, uv: uv2 },\n { pos: p4, norm: normalVector, uv: uv4 },\n // Triangle 2\n { pos: p1, norm: normalVector, uv: uv1 },\n { pos: p4, norm: normalVector, uv: uv4 },\n { pos: p3, norm: normalVector, uv: uv3 },\n ];\n}\n\n/**\n * Compute normal based on the quad’s vertices (using the cross product of two edges).\n */\nexport function calculateNormal(\n p1: [number, number, number],\n p2: [number, number, number],\n p3: [number, number, number],\n): [number, number, number] {\n // Edge vectors\n const u: [number, number, number] = [\n p2[0] - p1[0],\n p2[1] - p1[1],\n p2[2] - p1[2],\n ];\n const v: [number, number, number] = [\n p3[0] - p1[0],\n p3[1] - p1[1],\n p3[2] - p1[2],\n ];\n\n // Cross product to calculate normal\n const normal: [number, number, number] = [\n u[1] * v[2] - u[2] * v[1],\n u[2] * v[0] - u[0] * v[2],\n u[0] * v[1] - u[1] * v[0],\n ];\n\n // Normalize the normal vector\n const length = Math.sqrt(normal[0] ** 2 + normal[1] ** 2 + normal[2] ** 2);\n return normal.map((val) => val / length) as [number, number, number];\n}\n","/**\n * Set a random timeout that will call the callback function with a random delay between minDelay and maxDelay.\n *\n * Example usage:\n * ```\n * setRandomTimeout(() => {\n * console.log(`Callback ${i} executed!`);\n * }, 100, 500); // Random timeout between 100ms and 500ms\n * ```\n */\nexport function setRandomTimeout(callback: () => void, minDelay: number, maxDelay: number) {\n const delay = minDelay + Math.random() * (maxDelay - minDelay);\n\n return setTimeout(callback, delay);\n}\n\n/**\n * Set a random interval that will call the callback function with a random delay between minDelay and maxDelay.\n *\n * Example usage:\n * ```\n * const clearRandomInterval = setRandomInterval(() => {\n * console.log('Random interval executed!');\n * }, 500, 1500); // Random delay between 500ms and 1500ms\n * ```\n */\nexport function setRandomInterval(callback: () => void, minDelay: number, maxDelay: number): () => void {\n let timeoutId: ReturnType<typeof setTimeout>;\n\n function scheduleNext() {\n const delay = minDelay + Math.random() * (maxDelay - minDelay);\n timeoutId = setTimeout(() => {\n callback();\n scheduleNext(); // Schedule the next execution\n }, delay);\n }\n\n scheduleNext();\n\n // Return a function to allow clearing the interval\n return () => clearTimeout(timeoutId);\n}\n","/**\n * Planar UV Mapping\n * Projects UVs onto the geometry from a single direction (like shining a projector onto a surface).\n *\n * Example:\n * ```\n * const vertices = [\n * [-1, -1, 1],\n * [1, -1, 1],\n * [-1, 1, 1],\n * [1, 1, 1],\n * ];\n *\n * const uvs = planarUVMapping(vertices, 'z'); // Project onto the Z-axis\n */\nexport function planarUVMapping(vertices: [number, number, number][], axis: 'x' | 'y' | 'z'): [number, number][] {\n return vertices.map(([x, y, z]) => {\n switch (axis) {\n case 'x': return [y, z]; // Use Y and Z for X-axis projection\n case 'y': return [x, z]; // Use X and Z for Y-axis projection\n case 'z': return [x, y]; // Use X and Y for Z-axis projection\n default: throw new Error(`Invalid axis: ${axis}`);\n }\n });\n}\n\n/**\n * Cubic UV Mapping\n * Applies a texture by projecting UVs along each face of a cube.\n *\n * Example usage:\n * ```\n * const cubeVertices = [\n * [-1, -1, 1],\n * [1, -1, 1],\n * [-1, 1, 1],\n * [1, 1, 1],\n * ];\n *\n * const cubeUVs = cubicUVMappingBatch(cubeVertices);\n * ```\n */\nexport function cubicUVMapping(vertex: [number, number, number]): [number, number] {\n const [x, y, z] = vertex;\n const absX = Math.abs(x), absY = Math.abs(y), absZ = Math.abs(z);\n\n if (absX >= absY && absX >= absZ) { // X face\n return [z > 0 ? z : -z, y];\n } else if (absY >= absX && absY >= absZ) { // Y face\n return [x, z > 0 ? z : -z];\n } else { // Z face\n return [x, y];\n }\n}\n\nexport function cubicUVMappingBatch(vertices: [number, number, number][]): [number, number][] {\n return vertices.map((vertex) => cubicUVMapping(vertex));\n}\n\n/**\n * Spherical UV Mapping\n * Wraps UVs around the geometry as if the texture were projected from a globe.\n *\n * Example usage:\n * ```\n * const sphereVertices = [\n * [1, 0, 0],\n * [0, 1, 0],\n * [0, 0, 1],\n * ];\n *\n * const sphereUVs = sphericalUVMapping(sphereVertices);\n * ```\n */\nexport function sphericalUVMapping(vertices: [number, number, number][]): [number, number][] {\n return vertices.map(([x, y, z]) => {\n const theta = Math.atan2(z, x); // Angle around the Y-axis\n const phi = Math.acos(y / Math.sqrt(x ** 2 + y ** 2 + z ** 2)); // Angle from the Y-axis\n const u = (theta / (2 * Math.PI)) + 0.5; // Map theta to [0, 1]\n const v = 1 - (phi / Math.PI); // Map phi to [0, 1]\n return [u, v];\n });\n}\n\n/**\n * Cylindrical UV Mapping\n * Projects UV coordinates onto the surface as though the texture is\n * wrapped around the cylinder's height and circumference.\n *\n * Example usage:\n * ```\n * const cylinderVertices = [\n * [1, 0, 0], // Vertex on the \"equator\"\n * [0, 1, 0], // Vertex on the top\n * [0, -1, 1], // Vertex on the bottom\n * [-1, 0, 0], // Opposite side of the equator\n * ];\n *\n * const cylinderUVs = cylindricalUVMapping(cylinderVertices);\n * ```\n */\nexport function cylindricalUVMapping(vertices: [number, number, number][]): [number, number][] {\n return vertices.map(([x, y, z]) => {\n const theta = Math.atan2(z, x); // Angle around the Y-axis (circumference)\n const u = (theta / (2 * Math.PI)) + 0.5; // Map theta to [0, 1]\n const v = y; // Use Y-axis as the vertical component (height)\n return [u, v];\n });\n}\n\n/**\n * Polar UV Mapping\n * Map textures onto circular or radial geometries, such as discs or dome-like structures.\n * Maps the radial distance from the center of the geometry to the v coordinate\n * and the angular position to the u coordinate.\n *\n * const discVertices = [\n * [1, 0, 0], // Vertex at (1, 0, 0)\n * [0, 0, 1], // Vertex at (0, 0, 1)\n * [-1, 0, 0], // Vertex at (-1, 0, 0)\n * [0, 0, -1], // Vertex at (0, 0, -1)\n * ];\n *\n * const polarUVs = polarUVMapping(discVertices);\n */\nexport function polarUVMapping(vertices: [number, number, number][]): [number, number][] {\n return vertices.map(([x, y, z]) => {\n const radius = Math.sqrt(x ** 2 + z ** 2); // Distance from the Y-axis (polar radius)\n const theta = Math.atan2(z, x); // Angle around the Y-axis (polar angle)\n\n const u = (theta / (2 * Math.PI)) + 0.5; // Map angle to [0, 1]\n const v = radius; // Use radial distance for v\n return [u, v];\n });\n}\n\n/**\n * Generic Normalization Function\n * This function will normalize 2D UV coordinates based on given bounds.\n *\n * Full pipeline:\n * - Compute UVs\n * - Calculate bounds\n * - Normalize UVs\n *\n * Example usage:\n * ```\n * const planarMapping = (vertex: [number, number, number]) => [vertex[0], vertex[1]];\n * const uvs = vertices.map(mappingFunction);\n * const { minBounds, maxBounds } = calculateUVBounds(uvs);\n * const normalizedUVs = normalizeUVBatch(uvs, minBounds, maxBounds);\n * ```\n */\nexport function normalizeUV(\n uv: [number, number],\n minU: number,\n maxU: number,\n minV: number,\n maxV: number\n): [number, number] {\n return [\n (uv[0] - minU) / (maxU - minU),\n (uv[1] - minV) / (maxV - minV),\n ];\n}\n\n/**\n * Batch Normalization for Multiple UVs\n * If you have multiple UVs, normalize them all based on the overall min/max bounds.\n */\nexport function normalizeUVBatch(\n uvs: [number, number][],\n minBounds: [number, number],\n maxBounds: [number, number]\n): [number, number][] {\n const [minU, minV] = minBounds;\n const [maxU, maxV] = maxBounds;\n\n return uvs.map((uv) => normalizeUV(uv, minU, maxU, minV, maxV));\n}\n\n/**\n * Finding Bounds for a List of UVs\n * calculate the min and max values dynamically.\n */\nexport function calculateUVBounds(uvs: [number, number][]): { minBounds: [number, number]; maxBounds: [number, number] } {\n const minU = Math.min(...uvs.map((uv) => uv[0]));\n const maxU = Math.max(...uvs.map((uv) => uv[0]));\n const minV = Math.min(...uvs.map((uv) => uv[1]));\n const maxV = Math.max(...uvs.map((uv) => uv[1]));\n\n return {\n minBounds: [minU, minV],\n maxBounds: [maxU, maxV],\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.iife.js","names":[],"sources":["../src/animators/cameraClip.ts","../src/animators/CameraPlayback.ts","../src/constants/Easing.ts","../src/animators/cameraClips.ts","../src/constants/Direction.ts","../src/constants/Falloff.ts","../src/brushes/DisplacementBrush.ts","../src/brushes/FlattenBrush.ts","../src/brushes/NoiseBrush.ts","../src/brushes/SmoothBrush.ts","../src/brushes/SpikeBrush.ts","../src/brushes/TwistBrush.ts","../src/constants/Axis.ts","../src/constants/BoxSide.ts","../src/constants/ColorPalette.ts","../src/constants/ParametricCurve.ts","../src/utils/Random.ts","../src/utils/RandomNumberUtils.ts","../src/effects/DustMotesEffect.ts","../src/effects/EffervescenceEffect.ts","../src/effects/EmissivePulseEffect.ts","../src/effects/FlameFlickerEffect.ts","../src/effects/GlowHalo.ts","../src/effects/GroundFogEffect.ts","../src/effects/LightningEffect.ts","../src/geometry/leafs/EllipticLeafGeometry.ts","../src/effects/PetalDriftEffect.ts","../src/effects/RainEffect.ts","../src/shapes/BurstShape.ts","../src/geometry/shapes/BurstGeometry.ts","../src/effects/StarFieldEffect.ts","../src/effects/WispEffect.ts","../src/geometry/books/BookGeometry.ts","../src/factory/BookFactory.ts","../src/utils/CoherentNoise.ts","../src/geometry/rocks/BoulderGeometry.ts","../src/factory/BoulderFactory.ts","../src/shapes/HexagonShape.ts","../src/geometry/shapes/HexagonGeometry.ts","../src/factory/HexagonalTileFactory.ts","../src/geometry/rocks/MossyRockGeometry.ts","../src/utils/VertexUtils.ts","../src/geometry/rocks/RockGeometry.ts","../src/factory/RockFactory.ts","../src/geometry/architecture/diamondLattice.ts","../src/geometry/architecture/ArchedDiamondLatticeWindowGeometry.ts","../src/geometry/architecture/DiamondLatticeWindowGeometry.ts","../src/geometry/architecture/gregorianLattice.ts","../src/geometry/architecture/GregorianLatticeWindowGeometry.ts","../src/geometry/architecture/staircaseQuad.ts","../src/geometry/architecture/LShapedStaircaseGeometry.ts","../src/geometry/architecture/SpiralStaircaseGeometry.ts","../src/geometry/architecture/StaircaseGeometry.ts","../src/geometry/bottles/JarGeometry.ts","../src/utils/LineEquations.ts","../src/geometry/bottles/PotionBottleGeometry.ts","../src/geometry/bottles/WineBottleGeometry.ts","../src/geometry/cemetery/CrossHeadstoneGeometry.ts","../src/geometry/cemetery/MausoleumGeometry.ts","../src/geometry/cemetery/ObeliskHeadstoneGeometry.ts","../src/geometry/cemetery/RoundedHeadstoneGeometry.ts","../src/geometry/cemetery/SquareHeadstoneGeometry.ts","../src/geometry/fence/StoneFencePostGeometry.ts","../src/geometry/fence/WroughtIronBarGeometry.ts","../src/geometry/fence/WroughtIronFenceGeometry.ts","../src/geometry/furniture/BookshelfGeometry.ts","../src/geometry/furniture/DeskGeometry.ts","../src/geometry/leafs/LeafGeometry.ts","../src/geometry/lighting/FlameGeometry.ts","../src/geometry/lighting/CandleGeometry.ts","../src/geometry/lighting/LanternGeometry.ts","../src/geometry/lighting/barBetween.ts","../src/geometry/lighting/HangingLanternGeometry.ts","../src/geometry/lighting/WallSconceGeometry.ts","../src/geometry/primitives/ParallelogramBoxGeometry.ts","../src/shapes/GearShape.ts","../src/geometry/shapes/GearGeometry.ts","../src/shapes/HeartShape.ts","../src/geometry/shapes/HeartGeometry.ts","../src/shapes/StarShape.ts","../src/geometry/shapes/StarGeometry.ts","../src/geometry/skeleton/BoneGeometry.ts","../src/geometry/science/ErlenmeyerFlaskGeometry.ts","../src/utils/SphericalGeometryUtils.ts","../src/utils/SphericalCurve.ts","../src/geometry/science/FlorenceFlaskGeometry.ts","../src/geometry/science/MortarGeometry.ts","../src/geometry/science/StandGeometry.ts","../src/geometry/science/TeslaCoilGeometry.ts","../src/geometry/science/TestTubeGeometry.ts","../src/geometry/terrain/TerrainMoundGeometry.ts","../src/geometry/terrain/TerrainPlaneGeometry.ts","../src/geometry/trees/TreeGeometry.ts","../src/models/architecture/LShapedStaircase.ts","../src/models/architecture/SpiralStaircase.ts","../src/models/architecture/Staircase.ts","../src/models/architecture/ArchedDiamondLatticeWindow.ts","../src/models/architecture/DiamondLatticeWindow.ts","../src/models/architecture/GregorianLatticeWindow.ts","../src/models/books/Book.ts","../src/models/bottles/Jar.ts","../src/models/bottles/PotionBottle.ts","../src/models/bottles/WineBottle.ts","../src/models/cemetery/CrossHeadstone.ts","../src/models/cemetery/Mausoleum.ts","../src/models/cemetery/ObeliskHeadstone.ts","../src/models/cemetery/RoundedHeadstone.ts","../src/models/cemetery/SquareHeadstone.ts","../src/models/fence/StoneFencePost.ts","../src/models/fence/WroughtIronBar.ts","../src/models/fence/WroughtIronFence.ts","../src/models/furniture/Bookshelf.ts","../src/models/furniture/Desk.ts","../src/models/leafs/Leaf.ts","../src/models/lighting/Candle.ts","../src/models/lighting/Flame.ts","../src/models/lighting/HangingLantern.ts","../src/models/lighting/WallSconce.ts","../src/models/lighting/Lantern.ts","../src/models/rocks/Boulder.ts","../src/models/rocks/MossyRock.ts","../src/models/rocks/Rock.ts","../src/models/science/BunsenBurner.ts","../src/models/science/ElectricPanel.ts","../src/models/science/ErlenmeyerFlask.ts","../src/models/science/FlorenceFlask.ts","../src/models/science/LeverPanel.ts","../src/models/science/Microscope.ts","../src/models/science/MortarAndPestle.ts","../src/models/science/Panel.ts","../src/models/science/PanelLight.ts","../src/models/science/SpiralTube.ts","../src/models/science/Stand.ts","../src/models/science/TeslaCoil.ts","../src/models/science/TestTube.ts","../src/models/science/TestTubeRack.ts","../src/models/shapes/Burst.ts","../src/models/shapes/Gear.ts","../src/models/shapes/Heart.ts","../src/models/shapes/Hexagon.ts","../src/models/shapes/Star.ts","../src/models/skeleton/Bone.ts","../src/models/trees/Tree.ts","../src/models/terrain/TerrainMound.ts","../src/models/terrain/TerrainPlane.ts","../src/textures/checkerboard.ts","../src/utils/AlignToEdge.ts","../src/utils/AlignToRow.ts","../src/utils/AlignToSurface.ts","../src/utils/Center.ts","../src/utils/ColorUtils.ts","../src/utils/FindClosestPoint.ts","../src/utils/InterpolateCurve.ts","../src/utils/ParametricCurveUtils.ts","../src/utils/QuadUtils.ts","../src/utils/RandomTimer.ts","../src/utils/UVUtils.ts"],"sourcesContent":["import { PerspectiveCamera, Quaternion, Vector3 } from \"three\";\nimport type { OrbitControls } from \"three/addons/controls/OrbitControls.js\";\nimport type { EasingFunction } from \"../constants/Easing\";\n\nexport type ClipPhase = \"running\" | \"complete\";\n\n/** Rest pose captured when playback is constructed or reset. */\nexport interface CameraSnapshot {\n position: Vector3;\n quaternion: Quaternion;\n fov: number;\n target: Vector3;\n}\n\n/** Per-frame mutable state shared with the active clip. */\nexport interface ClipRuntime {\n camera: PerspectiveCamera;\n controls: OrbitControls | null;\n /** Seconds elapsed in the active clip. */\n elapsed: number;\n /** Clip duration in seconds. */\n duration: number;\n /** Look-at point the clip is focused on — synced to OrbitControls on complete. */\n focus: Vector3;\n}\n\nexport interface CameraClip {\n readonly label: string;\n readonly duration: number;\n start(runtime: ClipRuntime): void;\n update(runtime: ClipRuntime, dt: number): ClipPhase;\n /** Called when playback is cancelled mid-clip. */\n cancel?(runtime: ClipRuntime): void;\n}\n\nexport interface CameraClipTiming {\n /** Duration in seconds. */\n duration: number;\n /** Progress easing for normalized time `t` in [0, 1]. Defaults to smoothstep. */\n ease?: EasingFunction;\n}\n\nexport function captureSnapshot(\n camera: PerspectiveCamera,\n controls?: OrbitControls,\n): CameraSnapshot {\n const target = controls?.target.clone() ?? new Vector3();\n if (!controls) {\n const dir = new Vector3();\n camera.getWorldDirection(dir);\n target.copy(camera.position).add(dir);\n }\n return {\n position: camera.position.clone(),\n quaternion: camera.quaternion.clone(),\n fov: camera.fov,\n target,\n };\n}\n\nexport function applySnapshot(\n camera: PerspectiveCamera,\n controls: OrbitControls | undefined,\n snapshot: CameraSnapshot,\n): void {\n camera.position.copy(snapshot.position);\n camera.quaternion.copy(snapshot.quaternion);\n camera.fov = snapshot.fov;\n camera.updateProjectionMatrix();\n if (controls) {\n controls.target.copy(snapshot.target);\n controls.update();\n }\n}\n\nexport function normalizedTime(runtime: ClipRuntime, ease: EasingFunction): number {\n const t = Math.min(1, runtime.elapsed / runtime.duration);\n return ease(t);\n}","import { PerspectiveCamera, Vector3 } from \"three\";\nimport type { OrbitControls } from \"three/addons/controls/OrbitControls.js\";\nimport {\n applySnapshot,\n captureSnapshot,\n type CameraClip,\n type CameraSnapshot,\n type ClipRuntime,\n} from \"./cameraClip\";\n\n/**\n * Single director for camera showcase clips — Unity demo-scene style playback.\n *\n * One active clip at a time, driven by {@link update} with elapsed seconds (`dt`),\n * not nested `requestAnimationFrame` loops. Disables OrbitControls while playing;\n * re-enables and syncs `controls.target` to the clip focus on complete.\n *\n * @example\n * ```ts\n * const playback = new CameraPlayback(camera, controls);\n * playback.setRest(); // snapshot current pose as Reset target\n *\n * onFrame((dt) => {\n * playback.update(dt);\n * controls.update();\n * renderer.render(scene, camera);\n * });\n *\n * playback.play(createOrbitClip({ target, radius: 10, duration: 8 }));\n * ```\n */\nexport class CameraPlayback {\n private active: CameraClip | null = null;\n private elapsed = 0;\n private readonly focus = new Vector3();\n private rest: CameraSnapshot;\n\n constructor(\n private readonly camera: PerspectiveCamera,\n private readonly controls?: OrbitControls,\n ) {\n const snap = captureSnapshot(camera, controls);\n this.focus.copy(snap.target);\n this.rest = snap;\n }\n\n /** Whether a clip is actively playing. */\n get isPlaying(): boolean {\n return this.active !== null;\n }\n\n /** Snapshot the current camera + controls pose as the Reset/rest pose. */\n setRest(): void {\n this.rest = captureSnapshot(this.camera, this.controls);\n }\n\n /** Replace the rest pose without stopping playback. */\n setRestSnapshot(snapshot: CameraSnapshot): void {\n this.rest = {\n position: snapshot.position.clone(),\n quaternion: snapshot.quaternion.clone(),\n fov: snapshot.fov,\n target: snapshot.target.clone(),\n };\n }\n\n /**\n * Begin a clip. Cancels any active clip first.\n * OrbitControls are disabled until the clip completes or {@link stop} is called.\n */\n play(clip: CameraClip): void {\n this.cancelActive();\n applySnapshot(this.camera, this.controls, this.rest);\n this.active = clip;\n this.elapsed = 0;\n if (this.controls) this.controls.enabled = false;\n clip.start(this.runtime());\n }\n\n /** Cancel the active clip and restore the rest pose. */\n stop(): void {\n this.cancelActive();\n applySnapshot(this.camera, this.controls, this.rest);\n if (this.controls) {\n this.controls.enabled = true;\n this.controls.update();\n }\n }\n\n /** Alias for {@link stop} — return to the rest pose. */\n reset(): void {\n this.stop();\n }\n\n /**\n * Advance the active clip. Call from the scene `onFrame` callback each frame.\n * @param dt Elapsed seconds since last frame.\n */\n update(dt: number): void {\n if (!this.active) return;\n\n this.elapsed += dt;\n const phase = this.active.update(this.runtime(), dt);\n\n if (phase === \"complete\") {\n this.active = null;\n this.elapsed = 0;\n if (this.controls) {\n this.controls.target.copy(this.focus);\n this.controls.enabled = true;\n this.controls.update();\n }\n }\n }\n\n /** Release references; call from example dispose. */\n dispose(): void {\n this.stop();\n }\n\n private cancelActive(): void {\n if (!this.active) return;\n this.active.cancel?.(this.runtime());\n this.active = null;\n this.elapsed = 0;\n }\n\n private runtime(): ClipRuntime {\n return {\n camera: this.camera,\n controls: this.controls ?? null,\n elapsed: this.elapsed,\n duration: this.active?.duration ?? 0,\n focus: this.focus,\n };\n }\n}","/**\n * Easing function type for interpolating values over time.\n * @param t - Progress value between 0 and 1\n * @returns Eased value between 0 and 1\n */\nexport type EasingFunction = (t: number) => number;\n\n/**\n * Easing functions for interpolating values over time.\n *\n * Use these functions to create smooth animations and transitions.\n * All easing functions take a value t between 0 and 1 and return an eased value between 0 and 1.\n *\n * @example\n * ```typescript\n * import { Easing } from 'three-low-poly';\n *\n * // Using with transitions (namespace)\n * cameraTransition.transitionTo(camera, {\n * duration: 1000,\n * easing: Easing.cubicInOut // Function reference\n * });\n *\n * // Or using string reference\n * cameraTransition.transitionTo(camera, {\n * duration: 1000,\n * easing: 'cubicInOut' // String reference\n * });\n *\n * // Using the function directly in custom animation\n * const progress = 0.5;\n * const easedValue = Easing.cubicInOut(progress);\n *\n * // Custom animation loop\n * const startValue = 0;\n * const endValue = 100;\n * const t = elapsedTime / duration;\n * const easedT = Easing.sineInOut(t);\n * const currentValue = startValue + (endValue - startValue) * easedT;\n * ```\n */\nexport const Easing = {\n // Sine\n sineIn: (t: number) => 1 - Math.cos((t * Math.PI) / 2),\n sineOut: (t: number) => Math.sin((t * Math.PI) / 2),\n sineInOut: (t: number) => -0.5 * (Math.cos(Math.PI * t) - 1),\n\n // Quadratic\n quadIn: (t: number) => t * t,\n quadOut: (t: number) => 1 - Math.pow(1 - t, 2),\n quadInOut: (t: number) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),\n\n // Cubic\n cubicIn: (t: number) => t * t * t,\n cubicOut: (t: number) => 1 - Math.pow(1 - t, 3),\n cubicInOut: (t: number) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2),\n\n // Quartic\n quartIn: (t: number) => t * t * t * t,\n quartOut: (t: number) => 1 - Math.pow(1 - t, 4),\n quartInOut: (t: number) => (t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2),\n\n // Quintic\n quintIn: (t: number) => t * t * t * t * t,\n quintOut: (t: number) => 1 - Math.pow(1 - t, 5),\n quintInOut: (t: number) => (t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2),\n\n // Exponential\n expoIn: (t: number) => (t === 0 ? 0 : Math.pow(2, 10 * t - 10)),\n expoOut: (t: number) => (t === 1 ? 1 : 1 - Math.pow(2, -10 * t)),\n expoInOut: (t: number) => {\n if (t === 0) return 0;\n if (t === 1) return 1;\n return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;\n },\n\n // Circular\n circIn: (t: number) => 1 - Math.sqrt(1 - Math.pow(t, 2)),\n circOut: (t: number) => Math.sqrt(1 - Math.pow(t - 1, 2)),\n circInOut: (t: number) => t < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2,\n\n // Special\n linear: (t: number) => t,\n smoothstep: (t: number) => t * t * (3 - 2 * t),\n concave: (t: number) => 1 - Math.pow(1 - t, 0.3),\n convex: (t: number) => Math.pow(t, 0.3),\n logarithmic: (t: number) => Math.log(Math.max(0.01, t)) / Math.log(2),\n squareRoot: (t: number) => Math.sqrt(t),\n inverse: (t: number) => 1 - t,\n gaussian: (t: number) => {\n const sigma = 0.5;\n return Math.exp(-Math.pow(t - 0.5, 2) / (2 * sigma));\n },\n};\n","import { MathUtils, Vector3 } from \"three\";\nimport { Easing, type EasingFunction } from \"../constants/Easing\";\nimport {\n normalizedTime,\n type CameraClip,\n type CameraClipTiming,\n type ClipRuntime,\n} from \"./cameraClip\";\n\nconst tmp = new Vector3();\nconst tmp2 = new Vector3();\n\nexport interface OrbitClipOptions extends CameraClipTiming {\n target: Vector3;\n /** Horizontal distance from target. Defaults to current camera distance. */\n radius?: number;\n /** Elevation above target Y in radians. Defaults to current camera elevation. */\n elevation?: number;\n /** Revolutions over the clip. Defaults to `1`. */\n revolutions?: number;\n}\n\n/** Circle the scene — showcase reel orbit. */\nexport function createOrbitClip(options: OrbitClipOptions): CameraClip {\n const {\n target,\n duration,\n ease = Easing.smoothstep,\n revolutions = 1,\n } = options;\n const startAzimuth = { value: 0 };\n const radius = { value: options.radius ?? 10 };\n const elevation = { value: options.elevation ?? 0.4 };\n\n return {\n label: \"Orbit\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n tmp.subVectors(runtime.camera.position, target);\n radius.value = options.radius ?? tmp.length();\n elevation.value = options.elevation ?? Math.asin(MathUtils.clamp(tmp.y / radius.value, -1, 1));\n startAzimuth.value = Math.atan2(tmp.z, tmp.x);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) return \"complete\";\n\n const azimuth = startAzimuth.value + t * Math.PI * 2 * revolutions;\n const horiz = radius.value * Math.cos(elevation.value);\n runtime.camera.position.set(\n target.x + horiz * Math.cos(azimuth),\n target.y + radius.value * Math.sin(elevation.value),\n target.z + horiz * Math.sin(azimuth),\n );\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface PendulumClipOptions extends CameraClipTiming {\n target: Vector3;\n /** Distance from target. Defaults to current camera distance. */\n distance?: number;\n /** Peak azimuth swing in radians — keep small for Ken Burns mood (e.g. `0.12`). */\n azimuthAmplitude?: number;\n /** Slow back-and-forth cycles over the clip. Defaults to `2`. */\n oscillations?: number;\n ease?: EasingFunction;\n}\n\n/**\n * Atmospheric focus drift — slow Ken Burns sway while locked on a subject.\n * Not a full orbit; subtle back-and-forth for mood and screen capture.\n */\nexport function createPendulumClip(options: PendulumClipOptions): CameraClip {\n const {\n target,\n duration,\n azimuthAmplitude = 0.14,\n oscillations = 2,\n ease = Easing.linear,\n } = options;\n const baseAzimuth = { value: 0 };\n const distance = { value: options.distance ?? 8 };\n const elevation = { value: 0.35 };\n\n return {\n label: \"Pendulum\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n tmp.subVectors(runtime.camera.position, target);\n distance.value = options.distance ?? tmp.length();\n elevation.value = Math.asin(MathUtils.clamp(tmp.y / distance.value, -1, 1));\n baseAzimuth.value = Math.atan2(tmp.z, tmp.x);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) return \"complete\";\n\n const sway = Math.sin(t * Math.PI * 2 * oscillations) * azimuthAmplitude;\n const azimuth = baseAzimuth.value + sway;\n const horiz = distance.value * Math.cos(elevation.value);\n runtime.camera.position.set(\n target.x + horiz * Math.cos(azimuth),\n target.y + distance.value * Math.sin(elevation.value),\n target.z + horiz * Math.sin(azimuth),\n );\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface FlythroughClipOptions extends CameraClipTiming {\n waypoints: Vector3[];\n /** Optional look-at points per waypoint; defaults to next waypoint. */\n lookAt?: Vector3[];\n ease?: EasingFunction;\n}\n\n/** Waypoint tour through a sequence of positions. */\nexport function createFlythroughClip(options: FlythroughClipOptions): CameraClip {\n const { waypoints, duration, ease = Easing.cubicInOut } = options;\n if (waypoints.length < 2) throw new Error(\"Flythrough clip requires at least two waypoints\");\n\n const lookAt = options.lookAt ?? waypoints.slice(1).concat(waypoints[waypoints.length - 1]!);\n const segments = waypoints.length - 1;\n\n return {\n label: \"Flythrough\",\n duration,\n start(runtime) {\n runtime.focus.copy(lookAt[0] ?? waypoints[0]!);\n runtime.camera.position.copy(waypoints[0]!);\n runtime.camera.lookAt(runtime.focus);\n },\n update(runtime) {\n const t = normalizedTime(runtime, Easing.linear);\n if (t >= 1) {\n runtime.camera.position.copy(waypoints[waypoints.length - 1]!);\n runtime.focus.copy(lookAt[lookAt.length - 1] ?? waypoints[waypoints.length - 1]!);\n runtime.camera.lookAt(runtime.focus);\n return \"complete\";\n }\n\n const scaled = t * segments;\n const seg = Math.min(segments - 1, Math.floor(scaled));\n const localT = ease(scaled - seg);\n\n runtime.camera.position.lerpVectors(waypoints[seg]!, waypoints[seg + 1]!, localT);\n const lookFrom = lookAt[seg] ?? waypoints[seg + 1]!;\n const lookTo = lookAt[seg + 1] ?? waypoints[seg + 1]!;\n runtime.focus.lerpVectors(lookFrom, lookTo, localT);\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface DollyClipOptions extends CameraClipTiming {\n /** Distance along view axis — positive pulls back, negative pushes in. */\n distance: number;\n ease?: EasingFunction;\n}\n\n/** Dolly in or out along the current view direction. */\nexport function createDollyClip(options: DollyClipOptions): CameraClip {\n const { distance, duration, ease = Easing.cubicInOut } = options;\n const startPos = new Vector3();\n const endPos = new Vector3();\n const viewDir = new Vector3();\n\n return {\n label: \"Dolly\",\n duration,\n start(runtime) {\n startPos.copy(runtime.camera.position);\n runtime.camera.getWorldDirection(viewDir);\n endPos.copy(startPos).addScaledVector(viewDir, distance);\n runtime.focus.copy(runtime.controls?.target ?? startPos).addScaledVector(viewDir, 10);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) {\n runtime.camera.position.copy(endPos);\n return \"complete\";\n }\n runtime.camera.position.lerpVectors(startPos, endPos, t);\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface SpiralClipOptions extends CameraClipTiming {\n /** Ground point to look down at (typically scene center, `y = 0`). */\n target: Vector3;\n /** Orbit radius at the start of the clip. */\n radius: number;\n /** Optional wider radius at the end — pulls back as you rise. Defaults to `radius`. */\n endRadius?: number;\n /** Total vertical rise over the clip. */\n height: number;\n revolutions: number;\n ease?: EasingFunction;\n}\n\n/**\n * Scene-transition spiral — orbit upward while looking down at the scene.\n * Camera rises and optionally widens its orbit; `lookAt` stays on the ground\n * target so the view pitches into a bird's-eye survey (not a horizontal orbit).\n */\nexport function createSpiralClip(options: SpiralClipOptions): CameraClip {\n const {\n target,\n radius,\n endRadius = radius,\n height,\n revolutions,\n duration,\n ease = Easing.smoothstep,\n } = options;\n const startY = { value: 0 };\n const startAzimuth = { value: 0 };\n\n return {\n label: \"Spiral\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n startY.value = runtime.camera.position.y;\n tmp.subVectors(runtime.camera.position, target);\n startAzimuth.value = Math.atan2(tmp.z, tmp.x);\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) return \"complete\";\n\n const angle = startAzimuth.value + t * Math.PI * 2 * revolutions;\n const orbitRadius = MathUtils.lerp(radius, endRadius, t);\n runtime.camera.position.set(\n target.x + orbitRadius * Math.cos(angle),\n startY.value + height * t,\n target.z + orbitRadius * Math.sin(angle),\n );\n runtime.camera.lookAt(runtime.focus);\n return \"running\";\n },\n };\n}\n\nexport interface ZoomClipOptions extends CameraClipTiming {\n target: Vector3;\n /** Narrower FOV at the end of the clip (e.g. `35` from `75`). */\n endFov: number;\n ease?: EasingFunction;\n}\n\n/** Focus punch — smooth FOV narrow toward a target. Restores FOV on cancel; keeps end FOV on complete. */\nexport function createZoomClip(options: ZoomClipOptions): CameraClip {\n const { target, endFov, duration, ease = Easing.cubicInOut } = options;\n const startFov = { value: 75 };\n\n return {\n label: \"Zoom\",\n duration,\n start(runtime) {\n runtime.focus.copy(target);\n startFov.value = runtime.camera.fov;\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n runtime.camera.fov = MathUtils.lerp(startFov.value, endFov, Math.min(1, t));\n runtime.camera.updateProjectionMatrix();\n runtime.camera.lookAt(runtime.focus);\n return t >= 1 ? \"complete\" : \"running\";\n },\n cancel(runtime) {\n runtime.camera.fov = startFov.value;\n runtime.camera.updateProjectionMatrix();\n },\n };\n}\n\nexport interface WobbleClipOptions extends CameraClipTiming {\n /** Peak positional shake in world units. */\n intensity: number;\n ease?: EasingFunction;\n}\n\n/**\n * Impact wobble — short head-shake / recovery shake (gameplay feedback).\n * Decaying sinusoidal offset, not random noise. For showcase orbit rigs use\n * {@link createPendulumClip} instead.\n */\nexport function createWobbleClip(options: WobbleClipOptions): CameraClip {\n const { intensity, duration, ease = Easing.linear } = options;\n const origin = new Vector3();\n const seed = { value: 0 };\n\n return {\n label: \"Wobble\",\n duration,\n start(runtime) {\n origin.copy(runtime.camera.position);\n seed.value = runtime.camera.position.x * 17.3 + runtime.camera.position.z * 9.1;\n },\n update(runtime) {\n const t = normalizedTime(runtime, ease);\n if (t >= 1) {\n runtime.camera.position.copy(origin);\n return \"complete\";\n }\n\n const decay = 1 - t;\n const w = runtime.elapsed * 28 + seed.value;\n runtime.camera.position.set(\n origin.x + Math.sin(w * 1.7) * intensity * decay,\n origin.y + Math.sin(w * 2.3) * intensity * 0.6 * decay,\n origin.z + Math.cos(w * 1.9) * intensity * decay,\n );\n return \"running\";\n },\n cancel(runtime) {\n runtime.camera.position.copy(origin);\n },\n };\n}","import { Vector3 } from \"three\";\n\n/**\n * Movement or orientation in a specific direction.\n *\n * Example usages:\n *\n * Moving an Object Along a Direction\n * ```\n * const speed = 1; // Movement speed\n * const direction = Direction.FORWARD; // Choose a direction\n *\n * object.position.add(direction.clone().multiplyScalar(speed * deltaTime));\n * ```\n *\n * Snapping Positions to a Direction\n * ```\n * const targetPosition = new Vector3(5, 0, 3);\n * const snapDirection = Direction.UP; // Align upwards\n *\n * object.position.copy(targetPosition.clone().add(snapDirection.clone().multiplyScalar(10)));\n * ```\n *\n * Animating Along a Direction\n * ```\n * const distance = 10; // Total distance to travel\n * const duration = 2; // Animation duration in seconds\n * const startPosition = object.position.clone();\n * const targetPosition = startPosition.clone().add(Direction.BACKWARD.clone().multiplyScalar(distance));\n *\n * let elapsed = 0;\n * function animate(deltaTime) {\n * elapsed += deltaTime;\n * const t = Math.min(elapsed / duration, 1); // Normalize time to [0, 1]\n * object.position.lerpVectors(startPosition, targetPosition, t);\n * }\n * ```\n *\n * Shader Uniforms\n * ```\n * material.uniforms.uDirection.value = Direction.FORWARD; // Use as light or flow direction\n * ```\n *\n * Particle Systems\n * ```\n * particles.forEach(particle => {\n * particle.velocity.add(Direction.FORWARD.clone().multiplyScalar(0.1));\n * });\n * ```\n *\n * Directional Raycasting\n * ```\n * const rayOrigin = new Vector3(0, 0, 0);\n * const rayDirection = Direction.FORWARD;\n * const raycaster = new THREE.Raycaster(rayOrigin, rayDirection);\n *\n * // Find intersected objects\n * const intersects = raycaster.intersectObjects(scene.children);\n * ```\n *\n * Physics Forces\n * ```\n * const forceDirection = Direction.UP; // Push upwards\n * const forceMagnitude = 50;\n *\n * rigidBody.applyForce(forceDirection.clone().multiplyScalar(forceMagnitude));\n * ```\n */\nexport const Direction = {\n UP: new Vector3(0, 1, 0),\n DOWN: new Vector3(0, -1, 0),\n LEFT: new Vector3(-1, 0, 0),\n RIGHT: new Vector3(1, 0, 0),\n FORWARD: new Vector3(0, 0, 1),\n BACKWARD: new Vector3(0, 0, -1),\n};\n","export type FalloffFunction = (distance: number, radius: number) => number;\n\nexport const Falloff = {\n linear: (distance: number, radius: number): number => 1 - distance / radius,\n quadratic: (distance: number, radius: number): number => Math.pow(1 - distance / radius, 2),\n squareRoot: (distance: number, radius: number): number => Math.pow(1 - distance / radius, 0.5),\n logarithmic: (distance: number, radius: number): number => Math.log(1 + (radius - distance)) / Math.log(1 + radius),\n sine: (distance: number, radius: number): number => Math.cos(((distance / radius) * Math.PI) / 2),\n exponential: (distance: number, radius: number): number => Math.exp(-distance / radius),\n cubic: (distance: number, radius: number): number => Math.pow(1 - distance / radius, 3),\n gaussian: (distance: number, radius: number): number => Math.exp(-Math.pow(distance, 2) / (2 * Math.pow(radius / 3, 2))),\n inverse: (distance: number, radius: number): number => radius / (radius + distance),\n smoothstep: (distance: number, radius: number): number => {\n const t = Math.max(0, Math.min(1, 1 - distance / radius));\n return t * t * (3 - 2 * t);\n },\n};\n","import { BufferGeometry, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Moves vertices within a specified radius around a target position along a given direction\n */\nexport const displacementBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear,\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n // Calculate falloff\n const falloff = falloffFn(distance, radius);\n const influence = falloff * strength;\n\n // Apply the effect (e.g., pulling the vertex upwards)\n vertex.add(direction.clone().multiplyScalar(influence));\n\n // Update the vertex position\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Flattens vertices to a given plane defined by a target height or normal direction.\n */\nexport const flattenBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n targetHeight: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n const falloff = falloffFn(distance, radius);\n const influence = falloff * strength;\n\n // Project vertex onto flatten plane\n const projectedHeight = vertex.dot(direction.normalize());\n const delta = targetHeight - projectedHeight;\n\n vertex.add(direction.clone().multiplyScalar(delta * influence));\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, MathUtils, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Adds random noise to the vertices within the specified radius to create a more rugged or natural look.\n */\nexport const noiseBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n const falloff = falloffFn(distance, radius);\n const noiseStrength = strength * falloff;\n\n // Generate random noise in the direction specified\n const noise = direction.clone().normalize();\n vertex.x += MathUtils.randFloatSpread(noiseStrength) * noise.x;\n vertex.y += MathUtils.randFloatSpread(noiseStrength) * noise.y;\n vertex.z += MathUtils.randFloatSpread(noiseStrength) * noise.z;\n\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Vector3 } from \"three\";\n\n/**\n * Smooths out the vertices by averaging their positions with neighboring vertices within a given radius.\n */\nexport const smoothBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number\n): void => {\n const positions = geometry.attributes.position;\n const tempPosition = new Vector3();\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n let averagePosition = new Vector3();\n let count = 0;\n\n // Average position of nearby vertices\n for (let j = 0; j < positions.count; j++) {\n tempPosition.fromBufferAttribute(positions, j);\n if (tempPosition.distanceTo(vertex) < radius) {\n averagePosition.add(tempPosition);\n count++;\n }\n }\n\n if (count > 0) {\n averagePosition.divideScalar(count);\n vertex.lerp(averagePosition, strength); // Blend between current and average\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Vector3 } from \"three\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Creates spikes or depressions centered on the target position, pushing vertices away or pulling them towards the center.\n */\nexport const spikeBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n inward: boolean = false,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n // Calculate falloff\n const falloff = falloffFn(distance, radius);\n const influence = falloff * strength * (inward ? -1 : 1);\n\n // Move the vertex along the direction from the center\n const direction = vertex.clone().sub(position).normalize();\n vertex.add(direction.multiplyScalar(influence));\n\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { BufferGeometry, Quaternion, Vector3 } from \"three\";\nimport { Direction } from \"../constants/Direction\";\nimport { Falloff } from \"../constants/Falloff\";\n\n/**\n * Applies a twisting force to the vertices, rotating them around the direction defined by the target position.\n */\nexport const twistBrush = <T extends BufferGeometry>(\n geometry: T,\n position: Vector3,\n radius: number,\n strength: number,\n direction: Vector3 = Direction.UP,\n falloffFn: (distance: number, radius: number) => number = Falloff.linear\n): void => {\n const positions = geometry.attributes.position;\n const quaternion = new Quaternion();\n\n for (let i = 0; i < positions.count; i++) {\n const vertex = new Vector3();\n vertex.fromBufferAttribute(positions, i);\n const distance = vertex.distanceTo(position);\n\n if (distance < radius) {\n // Calculate falloff and rotation angle\n const falloff = falloffFn(distance, radius);\n const angle = falloff * strength;\n\n // Create quaternion for rotation around the axis\n quaternion.setFromAxisAngle(direction, angle);\n\n // Apply twist rotation\n vertex.sub(position).applyQuaternion(quaternion).add(position);\n positions.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n }\n positions.needsUpdate = true;\n};\n","import { Vector3 } from \"three\";\n\n/**\n * Geometric and mathematical role of the vectors as axes in 3D space.\n *\n * Example usages:\n *\n * Defining a geometry's up vector:\n * ```\n * const upVector = Axis.Z; // Set the Z-axis as the \"up\" direction\n * object.up.copy(upVector);\n * ```\n *\n * Rotating or Orienting an Object\n * ```\n * const axis = Axis.XY; // Diagonal upward\n * object.lookAt(object.position.clone().add(axis));\n * ```\n *\n * Rotate around axis:\n * ```\n * const angle = Math.PI / 4; // 45-degree rotation\n * const rotationAxis = Axis.Y; // Rotate around the Y-axis\n *\n * object.rotateOnAxis(rotationAxis, angle);\n * ```\n *\n * Scaling along an axis:\n * ```\n * const scalingAxis = Axis.XZ; // Scale equally along X and Z\n * const scaleFactor = 2;\n *\n * object.scale.multiply(scalingAxis.clone().multiplyScalar(scaleFactor));\n * ```\n *\n * Aligning a Camera\n * ```\n * const cameraAxis = Axis.XZ; // Align the camera diagonally on the XZ plane\n *\n * camera.lookAt(camera.position.clone().add(cameraAxis));\n * ```\n *\n * Directional lighting\n * ```\n * const lightDirection = Axis.YZ; // Diagonal light along Y and Z axes\n * directionalLight.position.copy(lightDirection.clone().multiplyScalar(10));\n * ```\n *\n * Aligning an Object\n * ```\n * const axis = Axis.X; // Align object to the X-axis\n * object.lookAt(object.position.clone().add(axis));\n * ```\n *\n * Spawning objects along an axis\n * ```\n * const spawnAxis = Axis.XZ; // Arrange objects diagonally on XZ\n * const count = 10;\n * const spacing = 5;\n *\n * for (let i = 0; i < count; i++) {\n * const position = spawnAxis.clone().multiplyScalar(i * spacing);\n * const newObject = object.clone();\n * newObject.position.copy(position);\n * scene.add(newObject);\n * }\n * ```\n *\n * Vector projections\n * ```\n * const vector = new Vector3(3, 5, 7);\n * const projectionAxis = Axis.Z; // Project the vector onto the Z-axis\n *\n * const projection = vector.clone().projectOnVector(projectionAxis);\n * ```\n *\n * Plane definitions\n * ```\n * const normal = Axis.Y; // Y-axis is the normal for a horizontal plane\n * const distanceFromOrigin = 5;\n *\n * const plane = new THREE.Plane(normal, distanceFromOrigin);\n * ```\n *\n * Plane intersections\n * ```\n * const planeNormal = Axis.Y; // Define a plane normal (horizontal plane)\n * const plane = new THREE.Plane(planeNormal);\n *\n * const rayDirection = Axis.Z; // Ray pointing along Z-axis\n * const rayOrigin = new Vector3(0, 5, 0);\n * const ray = new THREE.Ray(rayOrigin, rayDirection);\n *\n * // Find intersection point\n * const intersectionPoint = new Vector3();\n * plane.intersectLine(new THREE.Line3(rayOrigin, rayOrigin.clone().add(rayDirection)), intersectionPoint);\n * ```\n *\n * Defining bounds\n * ```\n * const boundsAxis = Axis.XY; // Restrict an object’s movement within XY bounds\n * const maxBounds = 10;\n *\n * object.position.clamp(\n * new Vector3(-maxBounds, -maxBounds, -Infinity),\n * new Vector3(maxBounds, maxBounds, Infinity)\n * );\n * ```\n *\n * Procedural Geometry\n * ```\n * const vertex = new Vector3(0, 0, 0);\n * const axis = Axis.XZ; // Diagonal axis on XZ plane\n *\n * const offset = axis.clone().multiplyScalar(5);\n * vertex.add(offset); // Move vertex in axis\n * geometry.vertices.push(vertex);\n * ```\n */\nexport const Axis = {\n X: new Vector3(1, 0, 0),\n Y: new Vector3(0, 1, 0),\n Z: new Vector3(0, 0, 1),\n XY: new Vector3(1, 1, 0).normalize(),\n XZ: new Vector3(1, 0, 1).normalize(),\n YZ: new Vector3(0, 1, 1).normalize(),\n XYZ: new Vector3(1, 1, 1).normalize(),\n};\n","export enum BoxSide {\n LEFT = \"left\",\n RIGHT = \"right\",\n TOP = \"top\",\n BOTTOM = \"bottom\",\n FRONT = \"front\",\n BACK = \"back\",\n}\n","export const ColorPalette = {\n // Red\n CADMIUM_RED: 0xe60026, // Cadmium Red or Bright Red. Vivid, bold red shade with warm undertones.\n CARDINAL_RED: 0xc61416, // Bright Crimson or Cardinal Red. It’s a vivid, bold red shade with warm undertones.\n CHERRY_RED: 0xd82424, // Bold red with slightly warm undertones.\n CRIMSON: 0xc62828, // Crimson Red or Firebrick Red. It’s a bold, deep red with a slightly cool undertone.\n ALIZARIN_CRIMSON: 0xb22222, // Deep, rich red with cool undertones.\n DARK_RED: 0x8b0000, // Dark Red. It’s a deep, rich red shade resembling the color of garnets or dried blood.\n RUST: 0xc2452d, // Red clay or Brick Red. It’s a warm, earthy red-orange shade, often associated with weathered metal, autumn leaves, or natural clay tones.\n\n // Orange\n CORAL_ORANGE: 0xff5733, // Bold red-orange hue.\n TANGERINE: 0xff5500, // Tangerine or Bright Orange-Red. It’s a vibrant, warm shade of orange with red undertones with a tropical feel.\n ORANGE_PEEL: 0xff6600, // Orange Peel or Bright Orange. It’s a vivid, energetic orange.\n CADMIUM_ORANGE: 0xff7f24, // warm orange with strong red undertones, giving it a slightly richer and darker appearance.\n ORANGE: 0xffa500, // Bright, vibrant hue associated with sunsets, citrus fruits, and autumn tones.\n\n // Yellow\n AMBER: 0xffaa00, // Bright Orange. It’s a warm, vibrant shade of orange with golden-yellow undertones, associated with autumn hues.\n CADMIUM_YELLOW: 0xffd700, // Bright golden yellow with warm undertones.\n GOLD: 0xffd700, // Rich, vibrant yellow with warm undertones, resembling the color of metallic gold.\n YELLOW: 0xffff00, // Bright, pure yellow shade.\n\n // Green\n LIME_GREEN: 0xa4c400, // Lime Green or Bright Chartreuse. It’s a vivid, energetic yellow-green shade\n SPRING_GREEN: 0x88cc55, // Fresh, vibrant appearance, resembling new leaves or spring foliage\n MOSS_GREEN: 0x88aa33, // Medium-light shade of green with yellow undertones, often seen in natural foliage.\n FERN_GREEN: 0x4b8b3b, // It's a natural, medium-dark green with slightly muted tones, resembling the lush greenery of ferns or foliage.\n FOREST_GREEN: 0x228b22, // Rich, deep green shade, often associated with dense woodland and nature.\n SAP_GREEN: 0x507d2a, // Natural green with a muted tone.\n OLIVE_DRAB: 0x556b2f, // Muted earthy green with brownish undertones.\n VIRIDIAN_GREEN: 0x00a86b, // Vibrant cool green.\n MINT_GREEN: 0x88ccaa, // Mint Green or Light Jade. It’s a soft, pastel green with subtle blue undertones.\n AQUAMARINE: 0x00ffaa, // Aquamarine or Mint Green. It’s a bright, vibrant turquoise shade that blends green and blue.\n\n // Blue\n PHTHALO_BLUE: 0x000f89, // Phthalo Blue or Bright Navy. Intense, rich blue with a slightly greenish cool undertone.\n AETHER_BLUE: 0x3498db, // Bright and vivid shade of blue, sitting between the airy Sky Blue and rich Cerulean.\n SKY_BLUE: 0x88ccff, // Sky Blue or Baby Blue. It’s a light, cheerful shade of blue with a slightly soft and pastel tone.\n CERULEAN_BLUE: 0x5dade2, // Cerulean Blue or Sky Blue. It’s a bright, vivid shade of blue with a slightly cool undertone.\n AZURE: 0x0077ff, // Azure Blue or Bright Blue. It’s a vibrant, rich shade of blue with a cool undertone.\n OCEAN_BLUE: 0x0077be, // Ocean Blue or Azure Blue. It’s a vibrant medium blue shade with a slight teal undertone.\n ROYAL_BLUE: 0x5555ff, // Royal Blue or Bright Indigo. It’s a vibrant medium blue shade with a slightly cool and saturated tone.\n MIDNIGHT_BLUE: 0x000033, // A very deep, dark blue shade that evokes the feeling of a starless night sky or deep ocean depths, with subtle blue undertones.\n ULTRAMARINE_BLUE: 0x3f51b5, // Deep, rich blue with a slightly cool undertone.\n\n // Purple\n COBALT_VIOLET: 0x6a0dad, // Soft, purple tone.\n DEEP_VIOLET: 0xaa00ff, // Electric Purple or Deep Violet. It’s a bright, vibrant shade of purple with a strong blue undertone.\n CORAL_PINK: 0xff3366, // Bright Rose or Coral Pink. It’s a vivid, bold pinkish-red shade with warm undertones.\n VIVID_MAGENTA: 0xff22ff, // It's an intense, electric shade of pink with equal parts red and blue.\n MAGENTA: 0xff00ff, // Bright, vivid hue that is a mix of equal parts red and blue, sometimes called Fuchsia.\n HOT_PINK: 0xff00aa, // Hot Pink or Fuchsia Rose. It’s a vivid and bold pink with a magenta undertone.\n PINK_SHERBET: 0xff99cc, // Pink Sherbet or Light Pink. It’s a soft, playful pink shade with a hint of warmth.\n SOFT_PINK: 0xffc7c7, // Blush Pink or Soft Pink. It’s a pale, delicate pink with warm undertones.\n\n // Brown\n BURNT_SIENNA: 0xe97451, // warm, earthy brown with reddish undertones.\n BURNT_UMBER: 0x8a3324, // Dark brown with red undertones.\n SIENNA: 0x8b5a2b, // Dark Goldenrod Brown. It’s a warm, earthy brown with reddish and golden undertones, often associated with natural clay or autumn leaves.\n SADDLE_BROWN: 0x8b4513, // Rich, earthy brown with reddish undertones, often associated with leather, wood, or other natural materials.\n COFFEE_BROWN: 0x5c4033, // Rich, earthy tone with hints of red and gray, resembling the color of natural wood or dark leather.\n DARK_UMBER: 0x4b3621, // Coffee Brown or Dark Umber. It’s a deep, rich brown with warm, earthy undertones, often resembling dark wood or roasted coffee beans.\n RAW_UMBER: 0x826644, // Cool, muted brown.\n YELLOW_OCHRE: 0xc5a16f, // Warm, muted yellow-brown\n RAW_SIENNA: 0xd2b48c, // Light, golden brown.\n TAUPE: 0x8b7d7b, // Rosy Brown or Taupe Gray. It’s a muted, earthy tone with a mix of brown and gray.\n\n // Gray\n ONYX: 0x030303, // Extremely deep, almost black shade with a neutral tone.\n CARBON: 0x2e2e2e, // Deep, neutral gray.\n CHARCOAL: 0x333333, // Rich, neutral gray.\n SLATE_GRAY: 0x404040, // Medium-dark shade of gray\n ASH_GRAY: 0x444444, // Ash Gray or Dark Slate Gray.\n GRAPHITE: 0x505050, // Medium-dark, neutral Graphite Gray or Smoky Gray shadowy muted depth.\n STEEL_GRAY: 0x555555, // Medium Gray or Steel Gray.\n DIM_GRAY: 0x696969, // Medium-dark neutral gray with a muted, balanced tone\n IRON: 0x777777, // It’s a medium gray neutral.\n GRAY: 0x808080, // It is a neutral, medium-gray tone that sits exactly halfway between black and white.\n STONE: 0x888888, // It’s a medium-light neutral.\n SILVER: 0xaaaaaa, // Light Gray. It’s a soft, pale gray shade with a slightly metallic undertone.\n LIGHT_GRAY: 0xcccccc, // Light, neutral Gray, sits between medium grays and white.\n PALE_GRAY: 0xeeeeee, // Very Light Gray or Soft Gray. It’s a pale, almost white shade of gray.\n WHITE_SMOKE: 0xf5f5f5, // White Smoke or Light Gray. It’s a soft, pale gray shade with a hint of warmth.\n TITANIUM_WHITE: 0xffffff, // Pure white, the brightest color possible.\n };\n","export const ParametricCurve = {\n cubic: (t: number, p0: number, p1: number, p2: number, p3: number): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n const oneMinusT = 1 - clampedT;\n return (\n oneMinusT * oneMinusT * oneMinusT * p0 +\n 3 * oneMinusT * oneMinusT * clampedT * p1 +\n 3 * oneMinusT * clampedT * clampedT * p2 +\n clampedT * clampedT * clampedT * p3\n );\n },\n damped: (t: number, damping: number = 1): number => {\n const clampedDamping = Math.max(0.001, damping); // Avoid zero or negative damping\n return (1 - Math.exp(-clampedDamping * t)) / (1 - Math.exp(-clampedDamping));\n },\n exponential: (t: number, base: number = 1, factor: number = 1): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n return base * Math.pow(clampedT, factor);\n },\n logarithmic: (t: number, base: number = 1, factor: number = 1): number => {\n const clampedT = Math.max(0.001, Math.min(1, t)); // Avoid log(0)\n return base * Math.log(factor * clampedT + 1);\n },\n parabolic: (t: number, a: number = 1, b: number = 0, c: number = 0): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n return a * clampedT * clampedT + b * clampedT + c;\n },\n quadratic: (t: number, p0: number, p1: number, p2: number): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n const oneMinusT = 1 - clampedT;\n return oneMinusT * oneMinusT * p0 + 2 * oneMinusT * clampedT * p1 + clampedT * clampedT * p2;\n },\n sigmoid: (t: number, a: number = 10): number => {\n const clampedT = Math.max(0, Math.min(1, t));\n return 1 / (1 + Math.exp(-a * (clampedT - 0.5)));\n },\n sinusoidal: (t: number): number => {\n return Math.sin(t * Math.PI * 0.5);\n },\n};\n","/**\n * Randomness for procedural generation — unseeded by default, reproducible on demand.\n *\n * ---\n *\n * ### Layer 1 — stream primitive (portfolio parity)\n *\n * - {@link mulberry32} — fast seeded PRNG; returns a `() => number` closure yielding\n * floats in `[0, 1)`. Same algorithm as Gotham/Water on the portfolio site.\n *\n * ### Seed mixing\n *\n * - {@link splitmix32} — mixer only, **not** a stream. Maps one 32-bit value to another.\n * - {@link deriveSubSeed} — `splitmix32(masterSeed ^ salt)`. Fan one user-facing master\n * seed into independent sub-streams per subsystem. Use stable hex salts per domain\n * (`0x101` books, `0x202` fog, `0x303` windows, …) instead of `seed + n` offsets.\n *\n * ### Layer 2 — library ergonomics\n *\n * - {@link createRandom} — **no seed** → wraps `Math.random()`, unique every runtime\n * (showcase default). **With seed** → {@link mulberry32} stream, same seed ⇒ same sequence.\n * - Returns a {@link RandomSource}: `next`, `float`, `int`, `pick`, `boolean`, `skewMax`, `skewMin`.\n * - {@link Random} namespace — grouped exports, same API as standalone functions (like {@link Easing}).\n *\n * ### Layer 3 — {@link RandomNumberUtils}\n *\n * Existing helpers (`randomFloat`, `logarithmicRandomMax`, …) accept an optional\n * {@link RandomSource} as their last argument. Omit it for unseeded default behavior.\n *\n * ---\n *\n * @example Unique runtime (default)\n * ```ts\n * const rng = createRandom();\n * rng.float(0, 10); // different every page load\n * ```\n *\n * @example Reproducible layout with sub-seeds\n * ```ts\n * const master = 1337;\n * const books = createRandom(deriveSubSeed(master, 0x101));\n * const fog = createRandom(deriveSubSeed(master, 0x202));\n * ```\n *\n * @example Namespace import\n * ```ts\n * const rng = Random.create(deriveSubSeed(1337, 0x101));\n * ```\n */\n\n/** Callable stream returning floats in [0, 1). */\nexport type RandomStream = () => number;\n\n/**\n * Random source — a stream plus distribution helpers.\n * Returned by {@link createRandom}; also accepted by {@link RandomNumberUtils}.\n */\nexport interface RandomSource {\n /** `true` when backed by {@link mulberry32}; `false` when using `Math.random()`. */\n readonly seeded: boolean;\n /** Next float in [0, 1). */\n next(): number;\n /** Float in [min, max). */\n float(min?: number, max?: number): number;\n /** Integer in [min, max] (inclusive). */\n int(min?: number, max?: number): number;\n /** Uniform element from a non-empty array. */\n pick<T>(arr: readonly T[]): T;\n /** `true` with given probability (default 0.5). */\n boolean(probability?: number): boolean;\n /**\n * Skew toward `max`. Lower `exponent` = stronger bias.\n * Mirrors {@link logarithmicRandomMax}.\n */\n skewMax(exponent?: number, min?: number, max?: number): number;\n /**\n * Skew toward `min`. Lower `exponent` = stronger bias.\n * Mirrors {@link logarithmicRandomMin}.\n */\n skewMin(exponent?: number, min?: number, max?: number): number;\n}\n\n/**\n * Fast seeded PRNG — portfolio Gotham/Water parity.\n * Returns a closure yielding floats in [0, 1).\n */\nexport function mulberry32(seed: number): RandomStream {\n let a = seed >>> 0;\n return () => {\n a |= 0;\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/**\n * Seed mixer — maps one 32-bit value to another well-distributed value.\n * Use with {@link deriveSubSeed}, not as a drop-in stream replacement for\n * {@link mulberry32}.\n */\nexport function splitmix32(seed: number): number {\n let z = (seed >>> 0) + 0x9e3779b9;\n z = Math.imul(z ^ (z >>> 16), 0x85ebca6b);\n z ^= z >>> 13;\n z = Math.imul(z ^ (z >>> 16), 0xc2b2ae35);\n return (z ^ (z >>> 16)) >>> 0;\n}\n\n/**\n * Derive an independent sub-stream seed from a master seed and domain salt.\n *\n * XOR the salt before mixing so each subsystem gets its own mulberry32 stream\n * without sequential `seed + 1` collision risk. Use stable hex constants per\n * domain (`0x101` books, `0x202` fog, `0x303` windows, …).\n *\n * @example\n * ```ts\n * const master = 1337;\n * const bookRng = createRandom(deriveSubSeed(master, 0x101));\n * const fogRng = createRandom(deriveSubSeed(master, 0x202));\n * ```\n */\nexport function deriveSubSeed(masterSeed: number, salt: number): number {\n return splitmix32((masterSeed >>> 0) ^ (salt >>> 0));\n}\n\nfunction buildSource(stream: RandomStream, seeded: boolean): RandomSource {\n return {\n seeded,\n next: stream,\n float(min = 0, max = 1) {\n return min + (max - min) * stream();\n },\n int(min = 0, max = 1) {\n return Math.floor(this.float(min, max + 1));\n },\n pick<T>(arr: readonly T[]): T {\n if (!arr.length) throw new Error(\"RandomSource.pick() requires a non-empty array\");\n return arr[this.int(0, arr.length - 1)]!;\n },\n boolean(probability = 0.5) {\n return stream() < probability;\n },\n skewMax(exponent = 0.5, min = 0, max = 1) {\n return min + (max - min) * Math.pow(stream(), exponent);\n },\n skewMin(exponent = 0.5, min = 0, max = 1) {\n return min + (max - min) * Math.pow(1 - stream(), exponent);\n },\n };\n}\n\n/**\n * Create a random source.\n *\n * - **No seed** — wraps `Math.random()`. Unique every runtime; default for examples.\n * - **With seed** — {@link mulberry32} stream. Same seed ⇒ same sequence.\n */\nexport function createRandom(seed?: number): RandomSource {\n if (seed === undefined) return buildSource(Math.random, false);\n return buildSource(mulberry32(seed >>> 0), true);\n}\n\n/** Float in [min, max) from any stream — website `range()` parity. */\nexport function randomRange(stream: RandomStream, min: number, max: number): number {\n return min + (max - min) * stream();\n}\n\n/** Pick from a non-empty array using any stream — website `pick()` parity. */\nexport function randomPick<T>(stream: RandomStream, arr: readonly T[]): T {\n if (!arr.length) throw new Error(\"randomPick() requires a non-empty array\");\n return arr[Math.floor(stream() * arr.length)]!;\n}\n\n/**\n * Grouped exports — same function API, namespace import like {@link Easing}.\n *\n * @example\n * ```ts\n * import { Random } from \"three-low-poly\";\n * const rng = Random.create(deriveSubSeed(1337, 0x101));\n * ```\n */\nexport const Random = {\n create: createRandom,\n mulberry32,\n splitmix32,\n deriveSubSeed,\n range: randomRange,\n pick: randomPick,\n} as const;","import { createRandom, type RandomSource } from \"./Random\";\n\n/** Unseeded default — unique each runtime. Pass a {@link RandomSource} to override. */\nconst defaultSource = createRandom();\n\n/**\n * Generates a random number between `min` and `max`.\n */\nexport function randomFloat(min = 0, max = 1, source: RandomSource = defaultSource) {\n return source.float(min, max);\n}\n\n/**\n * Generates a random integer between `min` and `max`.\n */\nexport function randomInteger(min = 0, max = 1, source: RandomSource = defaultSource) {\n return source.int(min, max);\n}\n\n/**\n * Generates a random number skewed towards the maximum value.\n *\n * @param {number} [exponent=0.5] - Controls the skew of the distribution.\n * A smaller value (e.g., 0.3) skews the values towards the max.\n * A larger value (e.g., 0.8) creates a more even distribution.\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards `max`.\n */\nexport function logarithmicRandomMax(\n exponent = 0.5,\n min = 0,\n max = 1,\n source: RandomSource = defaultSource,\n) {\n return source.skewMax(exponent, min, max);\n}\n\n/**\n * Generates a random number skewed towards the minimum value.\n *\n * @param {number} [exponent=0.5] - Controls the skew of the distribution.\n * A smaller value (e.g., 0.3) skews the values towards the min.\n * A larger value (e.g., 0.8) creates a more even distribution.\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards `min`.\n */\nexport function logarithmicRandomMin(\n exponent = 0.5,\n min = 0,\n max = 1,\n source: RandomSource = defaultSource,\n) {\n return source.skewMin(exponent, min, max);\n}\n\n/**\n * Generates a random number with an inverse logarithmic distribution, biased towards the maximum value.\n *\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards the maximum.\n */\n\nfunction inverseLogarithmicRandomMax(min = 0, max = 1, source: RandomSource = defaultSource) {\n const randomValue = 1 - Math.log(1 - source.next()) / Math.log(2);\n return min + (max - min) * randomValue;\n}\n\n/**\n * Generates a random number with an inverse logarithmic distribution, biased towards the minimum value.\n *\n * @param {number} [min=0] - Minimum value of the range.\n * @param {number} [max=1] - Maximum value of the range.\n * @returns {number} A random number between `min` and `max`, skewed towards the minimum.\n */\nfunction inverseLogarithmicRandomMin(min = 0, max = 1, source: RandomSource = defaultSource) {\n const randomValue = Math.log(1 - source.next()) / Math.log(2);\n const adjustedValue = -randomValue;\n const clampedValue = Math.min(Math.max(adjustedValue, 0), 1);\n return min + (max - min) * clampedValue;\n}","import {\n AdditiveBlending,\n Color,\n ColorRepresentation,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n MeshBasicMaterial,\n Object3D,\n SphereGeometry,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface DustMotesEffectOptions {\n /** Number of dust instances. Defaults to `150`. */\n count?: number;\n /** Horizontal spread (world units). Defaults to `12`. */\n width?: number;\n /** Vertical spawn span (world units). Defaults to `8`. */\n height?: number;\n /** Depth spread (world units). Defaults to `12`. */\n depth?: number;\n /** World Y of the volume floor; motes respawn at the top after settling past it. Defaults to `0`. */\n floorY?: number;\n /** Speck tint. Defaults to `#aebfe6`. */\n color?: ColorRepresentation;\n /** Speck radius (world units). Defaults to `0.02`. */\n radius?: number;\n /** Base material opacity. Defaults to `0.9`. */\n opacity?: number;\n /** Override the default additive speck material. */\n material?: Material;\n /** Minimum settle (fall) speed (units/s). Defaults to `0.1`. */\n settleMin?: number;\n /** Maximum settle (fall) speed (units/s). Defaults to `0.35`. */\n settleMax?: number;\n /** Lateral waft amplitude (units/s). Defaults to `0.08`. */\n waft?: number;\n /** Smallest twinkle scale multiplier. Defaults to `0.6`. */\n scaleMin?: number;\n /** Largest twinkle scale multiplier. Defaults to `1.2`. */\n scaleMax?: number;\n /** Minimum twinkle frequency (rad/s). Defaults to `0.7`. */\n twinkleMin?: number;\n /** Maximum twinkle frequency (rad/s). Defaults to `1.6`. */\n twinkleMax?: number;\n}\n\n/**\n * Fine dust drifting through a lit interior — tiny additive specks slowly\n * settling and wafting, twinkling as they catch the light and all but vanishing\n * in shadow. This is the thing that sells a light shaft as volumetric. Additive\n * spheres read the same from any angle, so no billboarding is needed.\n *\n * Call {@link DustMotesEffect.update} each frame with elapsed time in seconds.\n *\n * @example\n * ```typescript\n * const dust = new DustMotesEffect({\n * count: 150,\n * width: 8,\n * height: 9,\n * depth: 8,\n * color: \"#aebfe6\",\n * });\n * scene.add(dust);\n *\n * onFrame((dt) => dust.update(dt));\n * ```\n */\nexport class DustMotesEffect extends InstancedMesh {\n private readonly width: number;\n private readonly height: number;\n private readonly depth: number;\n private readonly floorY: number;\n private readonly waft: number;\n private readonly scaleMin: number;\n private readonly scaleMax: number;\n private readonly px: Float32Array;\n private readonly py: Float32Array;\n private readonly pz: Float32Array;\n private readonly settle: Float32Array;\n private readonly twinkle: Float32Array;\n private readonly phase: Float32Array;\n private readonly dummy = new Object3D();\n private clock = 0;\n\n constructor(options: DustMotesEffectOptions = {}) {\n const {\n count = 150,\n width = 12,\n height = 8,\n depth = 12,\n floorY = 0,\n color = \"#aebfe6\",\n radius = 0.02,\n opacity = 0.9,\n material,\n settleMin = 0.1,\n settleMax = 0.35,\n waft = 0.08,\n scaleMin = 0.6,\n scaleMax = 1.2,\n twinkleMin = 0.7,\n twinkleMax = 1.6,\n } = options;\n\n const dustMaterial =\n material ??\n new MeshBasicMaterial({\n color: new Color(color),\n transparent: true,\n opacity,\n blending: AdditiveBlending,\n depthWrite: false,\n toneMapped: false,\n });\n\n super(new SphereGeometry(radius, 5, 5), dustMaterial, count);\n this.instanceMatrix.setUsage(DynamicDrawUsage);\n this.frustumCulled = false;\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.floorY = floorY;\n this.waft = waft;\n this.scaleMin = scaleMin;\n this.scaleMax = scaleMax;\n\n this.px = new Float32Array(count);\n this.py = new Float32Array(count);\n this.pz = new Float32Array(count);\n this.settle = new Float32Array(count);\n this.twinkle = new Float32Array(count);\n this.phase = new Float32Array(count);\n\n for (let i = 0; i < count; i++) {\n this.respawn(i, true);\n this.settle[i] = randomFloat(settleMin, settleMax);\n this.twinkle[i] = randomFloat(twinkleMin, twinkleMax);\n this.phase[i] = randomFloat(0, Math.PI * 2);\n }\n\n this.writeMatrices();\n }\n\n /**\n * Advance the drift and twinkle. Pass elapsed frame time in seconds.\n */\n update(dt: number): void {\n this.clock += dt;\n\n for (let i = 0; i < this.count; i++) {\n // Slow settle plus a gentle lateral waft on both axes so the field reads\n // as air movement from any viewing angle, not a single-axis slide.\n this.py[i] -= this.settle[i] * dt;\n this.px[i] += Math.sin(this.clock * 0.3 + this.phase[i]) * this.waft * dt;\n this.pz[i] += Math.cos(this.clock * 0.24 + this.phase[i]) * this.waft * dt;\n\n if (this.py[i] < this.floorY) this.respawn(i, false);\n }\n\n this.writeMatrices();\n }\n\n /** Release geometry and materials held by the field. */\n dispose(): this {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n return this;\n }\n\n private respawn(index: number, randomHeight: boolean): void {\n this.px[index] = randomFloat(-this.width * 0.5, this.width * 0.5);\n this.pz[index] = randomFloat(-this.depth * 0.5, this.depth * 0.5);\n this.py[index] = randomHeight\n ? this.floorY + randomFloat(0, this.height)\n : this.floorY + this.height;\n }\n\n private writeMatrices(): void {\n const d = this.dummy;\n for (let i = 0; i < this.count; i++) {\n const t = Math.abs(Math.sin(this.clock * this.twinkle[i] + this.phase[i]));\n const s = this.scaleMin + (this.scaleMax - this.scaleMin) * t;\n d.position.set(this.px[i], this.py[i], this.pz[i]);\n d.scale.setScalar(s);\n d.updateMatrix();\n this.setMatrixAt(i, d.matrix);\n }\n this.instanceMatrix.needsUpdate = true;\n }\n}\n","import {\n BufferGeometry,\n ColorRepresentation,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n MeshStandardMaterial,\n Object3D,\n SphereGeometry,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface EffervescenceEffectOptions {\n /** Override bubble geometry. Defaults to a small `SphereGeometry`. */\n geometry?: BufferGeometry;\n /** Override the default bubble material. */\n material?: Material;\n /** Number of bubble instances. Defaults to `24`. */\n count?: number;\n /** Horizontal spread (world units). Defaults to `1.5`. */\n width?: number;\n /** Vertical column height (world units). Defaults to `3`. */\n height?: number;\n /** Depth spread (world units). Defaults to `1.5`. */\n depth?: number;\n /**\n * Horizontal spawn inset (0–1). Scales width/depth spawn area inward so a\n * square volume fits round vessels. `1` = full box; `0.88` (default) trims corners.\n */\n spread?: number;\n /** World Y where bubbles spawn when they recycle. Defaults to `0`. */\n baseY?: number;\n /** Minimum rise speed (units/s). Defaults to `0.35`. */\n speedMin?: number;\n /** Maximum rise speed (units/s). Defaults to `0.85`. */\n speedMax?: number;\n /** Bubble tint when using the default material. Defaults to `0xffffff`. */\n color?: ColorRepresentation;\n /** Default material opacity. Defaults to `0.6`. */\n opacity?: number;\n /** Default material emissive intensity. Defaults to `0`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Carbonation bubbles rising through a bounded volume — seltzer, soda, or\n * brewing liquid. Each instance drifts upward at its own speed and respawns\n * near {@link EffervescenceEffectOptions.baseY} after reaching the top.\n *\n * Spawn positions use a square footprint (`width` × `depth`). {@link EffervescenceEffectOptions.spread}\n * pulls that box inward so round jars do not get occasional corner outliers.\n * Position and scale the effect to sit inside a jar, flask, or panel viewport.\n * Call {@link EffervescenceEffect.update} each frame with elapsed time in seconds.\n *\n * @example\n * ```typescript\n * const fizz = new EffervescenceEffect({ width: 1.2, height: 2.5, count: 30 });\n * fizz.position.set(0, 1.2, 0);\n * scene.add(fizz);\n *\n * onFrame((dt) => fizz.update(dt));\n * ```\n */\nexport class EffervescenceEffect extends InstancedMesh {\n private readonly width: number;\n private readonly height: number;\n private readonly depth: number;\n private readonly baseY: number;\n private readonly spread: number;\n private readonly px: Float32Array;\n private readonly py: Float32Array;\n private readonly pz: Float32Array;\n private readonly speed: Float32Array;\n private readonly dummy = new Object3D();\n\n constructor(options: EffervescenceEffectOptions = {}) {\n const {\n count = 24,\n width = 1.5,\n height = 3,\n depth = 1.5,\n spread = 0.88,\n baseY = 0,\n speedMin = 0.35,\n speedMax = 0.85,\n color = 0xffffff,\n opacity = 0.6,\n emissiveIntensity = 0,\n geometry = new SphereGeometry(0.08, 6, 6),\n material,\n } = options;\n\n const bubbleMaterial =\n material ??\n new MeshStandardMaterial({\n color,\n emissive: color,\n emissiveIntensity,\n transparent: true,\n opacity,\n roughness: 0.3,\n metalness: 0.1,\n });\n\n super(geometry, bubbleMaterial, count);\n this.instanceMatrix.setUsage(DynamicDrawUsage);\n this.frustumCulled = false;\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.baseY = baseY;\n this.spread = Math.min(1, Math.max(0, spread));\n\n this.px = new Float32Array(count);\n this.py = new Float32Array(count);\n this.pz = new Float32Array(count);\n this.speed = new Float32Array(count);\n\n for (let i = 0; i < count; i++) {\n this.respawn(i, true);\n this.speed[i] = randomFloat(speedMin, speedMax);\n }\n\n this.writeMatrices();\n }\n\n /**\n * Advance bubble positions. Pass elapsed frame time in seconds (e.g. from\n * `createScene`'s `onFrame` callback).\n */\n update(dt: number): void {\n const ceiling = this.baseY + this.height;\n for (let i = 0; i < this.count; i++) {\n this.py[i] += this.speed[i] * dt;\n if (this.py[i] > ceiling) this.respawn(i, false);\n }\n this.writeMatrices();\n }\n\n /** Release geometry and materials held by the field. */\n dispose(): this {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n return this;\n }\n\n private respawn(index: number, randomHeight: boolean): void {\n const halfX = this.width * 0.5 * this.spread;\n const halfZ = this.depth * 0.5 * this.spread;\n this.px[index] = randomFloat(-halfX, halfX);\n this.pz[index] = randomFloat(-halfZ, halfZ);\n this.py[index] = randomHeight\n ? this.baseY + Math.random() * this.height\n : this.baseY + randomFloat(0, this.height * 0.15);\n }\n\n private writeMatrices(): void {\n const d = this.dummy;\n for (let i = 0; i < this.count; i++) {\n d.position.set(this.px[i], this.py[i], this.pz[i]);\n d.updateMatrix();\n this.setMatrixAt(i, d.matrix);\n }\n this.instanceMatrix.needsUpdate = true;\n }\n}","import { MeshLambertMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial } from \"three\";\n\nexport type EmissivePulseMaterial =\n | MeshStandardMaterial\n | MeshPhysicalMaterial\n | MeshLambertMaterial\n | MeshPhongMaterial;\n\nexport interface EmissivePulseEffectOptions {\n /** Material whose `emissiveIntensity` will oscillate. Must have emissive set. */\n material: EmissivePulseMaterial;\n /**\n * Pulse frequency in radians per second (`abs(sin(elapsed * speed))`).\n * Defaults to `2`. Primary differentiator when many LEDs share one color.\n */\n speed?: number;\n /** Lower bound of the pulse. Defaults to `0.2`. */\n minIntensity?: number;\n /** Upper bound of the pulse. Defaults to `0.8`. */\n maxIntensity?: number;\n}\n\n/**\n * Smooth emissive pulse for fake LEDs — animates `emissiveIntensity` on an existing\n * mesh material without adding geometry or scene lights.\n *\n * Pair with a prefab such as {@link PanelLight}: place the mesh, pass its material\n * here, call `update(dt)` each frame. For a bank of same-color LEDs, give each\n * instance a different `speed` so they breathe out of sync.\n *\n * @example\n * ```ts\n * const led = new PanelLight({ emissive: 0xff0000 });\n * scene.add(led);\n *\n * const pulse = new EmissivePulseEffect({\n * material: led.material,\n * speed: 1.4,\n * minIntensity: 0.05,\n * maxIntensity: 2,\n * });\n *\n * onFrame((dt) => pulse.update(dt));\n * ```\n */\nexport class EmissivePulseEffect {\n public speed: number;\n public minIntensity: number;\n public maxIntensity: number;\n public readonly material: EmissivePulseMaterial;\n\n private elapsed = 0;\n\n constructor({\n material,\n speed = 2,\n maxIntensity = 0.8,\n minIntensity = 0.2,\n }: EmissivePulseEffectOptions) {\n this.material = material;\n this.speed = speed;\n this.maxIntensity = maxIntensity;\n this.minIntensity = minIntensity;\n }\n\n /** Advance the pulse by `dt` seconds (elapsed time, not frame index). */\n update(dt: number): void {\n this.elapsed += dt;\n const t = Math.abs(Math.sin(this.elapsed * this.speed));\n this.material.emissiveIntensity = this.minIntensity + t * (this.maxIntensity - this.minIntensity);\n }\n}","import { Color, ColorRepresentation, MeshBasicMaterial, PointLight, Vector3 } from \"three\";\nimport { GlowHalo } from \"./GlowHalo\";\n\nexport interface FlameFlickerEffectOptions {\n /**\n * Desyncs multiple instances. Defaults to `Math.random() * 100`.\n */\n seed?: number;\n /** Optional real light — use sparingly; casts on geometry but counts against light limits. */\n light?: PointLight;\n /** Base intensity when `light` is set. Defaults to `4`. */\n lightIntensity?: number;\n /** Optional flame core material (e.g. `MeshBasicMaterial` on a small sphere). */\n flame?: MeshBasicMaterial;\n /** Flame tint when `flame` is set. Defaults to `0xffaa44`. */\n flameColor?: ColorRepresentation;\n /** Optional {@link GlowHalo}; opacity scales with the flicker factor. */\n halo?: GlowHalo;\n /** Halo opacity multiplier at flicker peak. Defaults to `0.75`. */\n haloOpacity?: number;\n}\n\n/**\n * Calm flame flicker from detuned sines — drives optional real lights, flame\n * materials, and {@link GlowHalo} opacity in sync. Time-based (`update(dt)`).\n *\n * Use without a `light` for mass candlefields (halo + bloom only). Add a\n * `light` for hero sconces that must cast on walls and props.\n */\nexport class FlameFlickerEffect {\n public readonly seed: number;\n public light?: PointLight;\n public lightIntensity: number;\n public flame?: MeshBasicMaterial;\n public halo?: GlowHalo;\n public haloOpacity: number;\n\n private readonly flameColor = new Color();\n private elapsed = 0;\n\n constructor({\n seed = Math.random() * 100,\n light,\n lightIntensity = 4,\n flame,\n flameColor = 0xffaa44,\n halo,\n haloOpacity = 0.75,\n }: FlameFlickerEffectOptions = {}) {\n this.seed = seed;\n this.light = light;\n this.lightIntensity = lightIntensity;\n this.flame = flame;\n this.flameColor.set(flameColor);\n this.halo = halo;\n this.haloOpacity = haloOpacity;\n }\n\n /**\n * Flicker factor at elapsed time — lazy sum of detuned sines (~0.5–1.1).\n */\n static factor(elapsed: number, seed: number): number {\n return 0.8 + 0.2 * Math.sin(elapsed * 9 + seed) + 0.08 * Math.sin(elapsed * 23 + seed * 2);\n }\n\n /** Current flicker factor after the last `update`. */\n get level(): number {\n return FlameFlickerEffect.factor(this.elapsed, this.seed);\n }\n\n update(dt: number): void {\n this.elapsed += dt;\n const f = FlameFlickerEffect.factor(this.elapsed, this.seed);\n\n if (this.light) {\n this.light.intensity = this.lightIntensity * f;\n }\n\n if (this.flame) {\n this.flame.color.copy(this.flameColor).multiplyScalar(0.8 + 0.4 * f);\n }\n\n if (this.halo) {\n this.halo.setOpacity(this.haloOpacity * f);\n }\n }\n\n /** Billboard linked halo toward the eye, if present. */\n faceCamera(eye: Vector3): void {\n this.halo?.faceCamera(eye);\n }\n}","import {\n AdditiveBlending,\n CanvasTexture,\n Color,\n ColorRepresentation,\n Mesh,\n MeshBasicMaterial,\n Object3D,\n PlaneGeometry,\n SRGBColorSpace,\n Vector3,\n} from \"three\";\n\nexport interface GlowHaloOptions {\n /** Warm glow tint. Defaults to `0xffaa44`. */\n color?: ColorRepresentation;\n /** Billboard plane edge length in world units. Defaults to `1.2`. */\n size?: number;\n /** Base opacity before flicker scaling. Defaults to `0.75`. */\n opacity?: number;\n}\n\nfunction createGlowTexture(color: Color): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = canvas.height = 128;\n const ctx = canvas.getContext(\"2d\")!;\n const hex = `#${color.getHexString()}`;\n const gradient = ctx.createRadialGradient(64, 64, 2, 64, 64, 64);\n gradient.addColorStop(0, `${hex}ff`);\n gradient.addColorStop(0.25, `${hex}aa`);\n gradient.addColorStop(1, `${hex}00`);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, 128, 128);\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\n/**\n * Soft additive glow billboard — reads as light without a {@link PointLight}.\n * Pair with {@link FlameFlickerEffect} for organic pulse, or use alone for\n * cheap mass lighting (many halos + bloom, no light-count limit).\n *\n * Call `faceCamera(camera.position)` each frame so the card faces the eye.\n */\nexport class GlowHalo extends Object3D {\n public readonly mesh: Mesh<PlaneGeometry, MeshBasicMaterial>;\n private texture: CanvasTexture;\n private readonly baseColor: Color;\n\n constructor({\n color = 0xffaa44,\n size = 1.2,\n opacity = 0.75,\n }: GlowHaloOptions = {}) {\n super();\n\n this.baseColor = new Color(color);\n this.texture = createGlowTexture(this.baseColor);\n const material = new MeshBasicMaterial({\n map: this.texture,\n color: this.baseColor,\n transparent: true,\n opacity,\n blending: AdditiveBlending,\n depthWrite: false,\n toneMapped: false,\n });\n\n this.mesh = new Mesh(new PlaneGeometry(size, size), material);\n this.add(this.mesh);\n }\n\n /** Billboard toward the camera (or any eye position). */\n faceCamera(eye: Vector3): void {\n this.mesh.lookAt(eye);\n }\n\n /** Set halo opacity (e.g. scaled each frame by {@link FlameFlickerEffect}). */\n setOpacity(opacity: number): void {\n this.mesh.material.opacity = opacity;\n }\n\n get opacity(): number {\n return this.mesh.material.opacity;\n }\n\n setColor(color: ColorRepresentation): void {\n this.baseColor.set(color);\n this.mesh.material.color.copy(this.baseColor);\n this.texture.dispose();\n this.texture = createGlowTexture(this.baseColor);\n this.mesh.material.map = this.texture;\n }\n\n dispose(): void {\n this.mesh.geometry.dispose();\n this.mesh.material.dispose();\n this.texture.dispose();\n }\n}","import {\n CanvasTexture,\n Color,\n ColorRepresentation,\n Mesh,\n MeshBasicMaterial,\n Object3D,\n PlaneGeometry,\n SRGBColorSpace,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\ntype Edge = \"n\" | \"s\" | \"e\" | \"w\";\n\ninterface FogPatch {\n mesh: Mesh<PlaneGeometry, MeshBasicMaterial>;\n driftX: number;\n driftZ: number;\n spin: number;\n baseOpacity: number;\n phase: number;\n perimeter?: {\n edge: Edge;\n plotHalf: number;\n terrainHalf: number;\n };\n}\n\nexport interface GroundFogEffectOptions {\n /** Interior mist cards scattered across the plot. Defaults to `14`. */\n count?: number;\n /** Half-extent of the interior scatter (world units). Defaults to `16`. */\n area?: number;\n /**\n * Large cards hugging the plot perimeter — softens terrain cutoffs on the\n * horizons opposite the camera. Defaults to `0` (interior only).\n */\n perimeterCount?: number;\n /** Half-extent of the inner bounded plot (fence, wall, scene edge, etc.). Defaults to `12`. */\n plotHalf?: number;\n /** Terrain half-extent; perimeter cards spill outward toward this edge. Defaults to `16`. */\n terrainHalf?: number;\n /**\n * Horizontal direction from plot center toward the camera. Perimeter patches\n * concentrate on the opposite edges. Defaults to `{ x: 1, z: 1 }`.\n */\n cameraFacing?: { x: number; z: number };\n /** Mist tint. Defaults to `#9fb0c8`. */\n color?: ColorRepresentation;\n /**\n * Sample ground height at world (x, z). Defaults to flat `y = 0`.\n * Portfolio graveyard uses undulating terrain via the same callback.\n */\n heightAt?: (x: number, z: number) => number;\n}\n\n/**\n * Creeping ground mist — soft horizontal cards drifting above the floor.\n * Interior patches wrap toroidally within `area`; optional perimeter patches\n * sit on/outside the fence on edges opposite the camera. One texture, one\n * `update(dt)` — perimeter is placement logic, not a separate effect.\n */\nexport class GroundFogEffect extends Object3D {\n private readonly patches: FogPatch[] = [];\n private readonly area: number;\n private readonly heightAt: (x: number, z: number) => number;\n private readonly texture: CanvasTexture;\n private elapsed = 0;\n\n constructor({\n count = 14,\n area = 16,\n perimeterCount = 0,\n plotHalf = 12,\n terrainHalf = 16,\n cameraFacing = { x: 1, z: 1 },\n color = \"#9fb0c8\",\n heightAt = () => 0,\n }: GroundFogEffectOptions = {}) {\n super();\n\n this.area = area;\n this.heightAt = heightAt;\n this.texture = createFogTexture(color);\n const focus = focusEdges(cameraFacing);\n\n for (let i = 0; i < count; i++) {\n this.patches.push(this.makeInteriorPatch());\n }\n for (let i = 0; i < perimeterCount; i++) {\n this.patches.push(this.makePerimeterPatch(plotHalf, terrainHalf, focus));\n }\n }\n\n update(dt: number): void {\n this.elapsed += dt;\n\n for (const patch of this.patches) {\n const mesh = patch.mesh;\n mesh.position.x += patch.driftX * dt;\n mesh.position.z += patch.driftZ * dt;\n mesh.rotation.z += patch.spin * dt;\n\n if (patch.perimeter) {\n constrainPerimeter(mesh, patch.perimeter.edge, patch.perimeter.plotHalf, patch.perimeter.terrainHalf);\n mesh.position.y =\n this.heightAt(mesh.position.x, mesh.position.z) +\n 0.15 +\n 0.35 * (0.5 + 0.5 * Math.sin(this.elapsed * 0.22 + patch.phase));\n } else {\n if (mesh.position.x > this.area) mesh.position.x -= this.area * 2;\n if (mesh.position.x < -this.area) mesh.position.x += this.area * 2;\n if (mesh.position.z > this.area) mesh.position.z -= this.area * 2;\n if (mesh.position.z < -this.area) mesh.position.z += this.area * 2;\n }\n\n mesh.material.opacity = patch.baseOpacity * (0.6 + 0.4 * Math.sin(this.elapsed * 0.3 + patch.phase));\n }\n }\n\n dispose(): void {\n this.texture.dispose();\n for (const patch of this.patches) {\n patch.mesh.geometry.dispose();\n patch.mesh.material.dispose();\n }\n this.patches.length = 0;\n this.clear();\n }\n\n private makeInteriorPatch(): FogPatch {\n const size = randomFloat(8, 16);\n const baseOpacity = randomFloat(0.05, 0.16);\n const x = randomFloat(-this.area, this.area);\n const z = randomFloat(-this.area, this.area);\n const mesh = this.makeMesh(size, baseOpacity);\n mesh.position.set(x, this.heightAt(x, z) + randomFloat(0.3, 1.2), z);\n this.add(mesh);\n\n return {\n mesh,\n driftX: randomFloat(-0.15, 0.15),\n driftZ: randomFloat(-0.15, 0.15),\n spin: randomFloat(-0.03, 0.03),\n baseOpacity,\n phase: randomFloat(0, Math.PI * 2),\n };\n }\n\n private makePerimeterPatch(plotHalf: number, terrainHalf: number, focus: Edge[]): FogPatch {\n const edge = pickEdge(focus);\n const { x, z, driftX, driftZ } = placeOnPerimeter(edge, plotHalf, terrainHalf);\n const size = randomFloat(18, 30);\n const baseOpacity = randomFloat(0.1, 0.26);\n const mesh = this.makeMesh(size, baseOpacity);\n mesh.position.set(x, this.heightAt(x, z) + randomFloat(0.15, 0.55), z);\n this.add(mesh);\n\n return {\n mesh,\n driftX,\n driftZ,\n spin: randomFloat(-0.012, 0.012),\n baseOpacity,\n phase: randomFloat(0, Math.PI * 2),\n perimeter: { edge, plotHalf, terrainHalf },\n };\n }\n\n private makeMesh(size: number, baseOpacity: number): Mesh<PlaneGeometry, MeshBasicMaterial> {\n const mesh = new Mesh(\n new PlaneGeometry(size, size),\n new MeshBasicMaterial({\n map: this.texture,\n transparent: true,\n depthWrite: false,\n opacity: baseOpacity,\n toneMapped: false,\n }),\n );\n mesh.rotation.x = -Math.PI / 2;\n mesh.rotation.z = randomFloat(0, Math.PI * 2);\n return mesh;\n }\n}\n\nfunction createFogTexture(color: ColorRepresentation): CanvasTexture {\n const hex = `#${new Color(color).getHexString()}`;\n const canvas = document.createElement(\"canvas\");\n canvas.width = canvas.height = 256;\n const ctx = canvas.getContext(\"2d\")!;\n const gradient = ctx.createRadialGradient(128, 128, 8, 128, 128, 128);\n gradient.addColorStop(0, `${hex}dd`);\n gradient.addColorStop(0.45, `${hex}66`);\n gradient.addColorStop(1, `${hex}00`);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, 256, 256);\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\nfunction focusEdges(facing: { x: number; z: number }): Edge[] {\n const edges: Edge[] = [];\n if (facing.z > 0) edges.push(\"n\");\n if (facing.z < 0) edges.push(\"s\");\n if (facing.x > 0) edges.push(\"w\");\n if (facing.x < 0) edges.push(\"e\");\n return edges.length ? edges : [\"n\", \"w\"];\n}\n\nfunction pickEdge(focus: Edge[]): Edge {\n if (focus.length === 1) return focus[0]!;\n const r = Math.random();\n const hasN = focus.includes(\"n\");\n const hasW = focus.includes(\"w\");\n if (hasN && hasW) return r < 0.58 ? \"n\" : \"w\";\n return focus[Math.floor(Math.random() * focus.length)]!;\n}\n\nfunction placeOnPerimeter(\n edge: Edge,\n plotHalf: number,\n terrainHalf: number,\n): { x: number; z: number; driftX: number; driftZ: number } {\n const spill = randomFloat(0.6, terrainHalf - plotHalf - 1.5);\n const along = randomFloat(-terrainHalf + 3, terrainHalf - 3);\n const alongSpeed = randomFloat(0.03, 0.09) * (Math.random() < 0.5 ? -1 : 1);\n const outwardSpeed = randomFloat(0.01, 0.04);\n\n switch (edge) {\n case \"n\":\n return { x: along, z: -plotHalf - spill, driftX: alongSpeed, driftZ: -outwardSpeed };\n case \"s\":\n return { x: along, z: plotHalf + spill, driftX: -alongSpeed, driftZ: outwardSpeed };\n case \"e\":\n return { x: plotHalf + spill, z: along, driftX: outwardSpeed, driftZ: -alongSpeed };\n case \"w\":\n return { x: -plotHalf - spill, z: along, driftX: -outwardSpeed, driftZ: alongSpeed };\n }\n}\n\nfunction constrainPerimeter(mesh: Mesh, edge: Edge, plotHalf: number, terrainHalf: number): void {\n const margin = 3;\n const maxSpill = terrainHalf - 1;\n const { x, z } = mesh.position;\n\n switch (edge) {\n case \"n\": {\n mesh.position.z = clamp(z, -maxSpill, -plotHalf + 0.8);\n if (x < -maxSpill + margin) mesh.position.x = maxSpill - margin;\n if (x > maxSpill - margin) mesh.position.x = -maxSpill + margin;\n break;\n }\n case \"s\": {\n mesh.position.z = clamp(z, plotHalf - 0.8, maxSpill);\n if (x < -maxSpill + margin) mesh.position.x = maxSpill - margin;\n if (x > maxSpill - margin) mesh.position.x = -maxSpill + margin;\n break;\n }\n case \"e\": {\n mesh.position.x = clamp(x, plotHalf - 0.8, maxSpill);\n if (z < -maxSpill + margin) mesh.position.z = maxSpill - margin;\n if (z > maxSpill - margin) mesh.position.z = -maxSpill + margin;\n break;\n }\n case \"w\": {\n mesh.position.x = clamp(x, -maxSpill, -plotHalf + 0.8);\n if (z < -maxSpill + margin) mesh.position.z = maxSpill - margin;\n if (z > maxSpill - margin) mesh.position.z = -maxSpill + margin;\n break;\n }\n }\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, v));\n}","import { DirectionalLight } from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface LightningEffectOptions {\n /** Directional light driven by lightning flashes. Start at intensity `0`. */\n light: DirectionalLight;\n /** Peak light intensity at full flash. Defaults to `12`. */\n peak?: number;\n /** Minimum seconds between strikes. Defaults to `3`. */\n minGap?: number;\n /** Maximum seconds between strikes. Defaults to `9`. */\n maxGap?: number;\n}\n\n/**\n * Thunderstorm lightning that drives a {@link DirectionalLight} each frame.\n *\n * Rather than scheduling timeouts (which need careful teardown), each strike\n * enqueues two or three decaying intensity spikes a few frames apart — the\n * characteristic stutter of real lightning. Read {@link LightningEffect.level}\n * after {@link LightningEffect.update} to sync fog, sky, rain, or emissive\n * surfaces with the flash.\n *\n * @example\n * ```typescript\n * const bolt = new DirectionalLight(0xcdd8ff, 0);\n * bolt.position.set(5, 12, -8);\n * bolt.target.position.set(0, 0, 0);\n * scene.add(bolt, bolt.target);\n *\n * const storm = new LightningEffect({ light: bolt, peak: 12, minGap: 3, maxGap: 9 });\n *\n * function animate(delta: number) {\n * storm.update(delta);\n * const flash = storm.level; // 0..~1.2\n * renderer.render(scene, camera);\n * }\n * ```\n */\nexport class LightningEffect {\n /** Current flash level, 0 = dark. Read after each {@link LightningEffect.update}. */\n level = 0;\n\n private readonly light: DirectionalLight;\n private readonly peak: number;\n private readonly minGap: number;\n private readonly maxGap: number;\n private readonly spikes: { at: number; amp: number }[] = [];\n private clock = 0;\n private nextStrike: number;\n\n constructor({ light, peak = 12, minGap = 3, maxGap = 9 }: LightningEffectOptions) {\n this.light = light;\n this.peak = peak;\n this.minGap = minGap;\n this.maxGap = maxGap;\n this.nextStrike = randomFloat(minGap * 0.3, maxGap);\n }\n\n /**\n * Advance the strike schedule and update the driven light intensity. Pass\n * elapsed frame time in seconds.\n */\n update(dt: number): void {\n this.clock += dt;\n if (this.clock >= this.nextStrike) this.strike();\n\n let level = 0;\n for (let i = this.spikes.length - 1; i >= 0; i--) {\n const spike = this.spikes[i];\n const age = this.clock - spike.at;\n if (age < 0) continue;\n const value = spike.amp * Math.exp(-age * 9);\n if (value < 0.002 && age > 0) {\n this.spikes.splice(i, 1);\n } else {\n level += value;\n }\n }\n\n this.level = Math.min(1.2, level);\n this.light.intensity = this.level * this.peak;\n }\n\n /** Force the driven light dark, e.g. when lightning is toggled off. */\n quiet(): void {\n this.level = 0;\n this.light.intensity = 0;\n }\n\n private strike(): void {\n const bursts = Math.random() < 0.5 ? 2 : 3;\n for (let i = 0; i < bursts; i++) {\n this.spikes.push({\n at: this.clock + i * randomFloat(0.04, 0.12),\n amp: randomFloat(0.5, 1),\n });\n }\n this.nextStrike = this.clock + randomFloat(this.minGap, this.maxGap);\n }\n}","import { BufferGeometry, Float32BufferAttribute } from \"three\";\n\nexport class EllipticLeafGeometry extends BufferGeometry {\n constructor(size = 0.1) {\n super();\n\n const vertices = [];\n const indices = [];\n\n // Define vertices to approximate a simple, elongated, oval leaf shape\n const leafPoints = [\n [0, 1], // Top point\n [0.5, 0.75], // Right upper middle\n [0.75, 0.25], // Right lower middle\n [0.5, -0.5], // Right bottom middle\n [0, -1], // Bottom point\n [-0.5, -0.5], // Left bottom middle\n [-0.75, 0.25], // Left lower middle\n [-0.5, 0.75], // Left upper middle\n ];\n\n // Add vertices to the geometry, scaling them with the `size` parameter\n for (let i = 0; i < leafPoints.length; i++) {\n const [x, y] = leafPoints[i];\n vertices.push(x * size, y * size, 0);\n }\n\n // Define indices to form triangular faces of the leaf\n // Create a fan-like structure connecting the top vertex (index 0) to other neighboring vertices\n for (let i = 1; i < leafPoints.length - 1; i++) {\n indices.push(0, i, i + 1);\n }\n // Close the fan with the last triangle\n indices.push(0, leafPoints.length - 1, 1);\n\n // Convert the vertices and indices to buffer attributes\n const positionAttribute = new Float32BufferAttribute(vertices, 3);\n this.setAttribute('position', positionAttribute);\n this.setIndex(indices);\n\n this.computeVertexNormals();\n }\n}\n","import {\n BufferGeometry,\n Color,\n ColorRepresentation,\n DoubleSide,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n MeshStandardMaterial,\n Object3D,\n} from \"three\";\nimport { EllipticLeafGeometry } from \"../geometry/leafs/EllipticLeafGeometry\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface PetalDriftEffectOptions {\n /** Override petal geometry. Defaults to {@link EllipticLeafGeometry}. */\n geometry?: BufferGeometry;\n /** Override the default petal material. */\n material?: Material;\n /** Number of petal instances. Defaults to `120`. */\n count?: number;\n /** Horizontal spread (world units). Defaults to `16`. */\n width?: number;\n /** Vertical spawn span (world units). Defaults to `8`. */\n height?: number;\n /** Depth spread (world units). Defaults to `16`. */\n depth?: number;\n /** World Y where petals respawn after drifting below the floor. Defaults to `0`. */\n floorY?: number;\n /** Minimum fall speed (units/s). Defaults to `0.12`. */\n fallSpeedMin?: number;\n /** Maximum fall speed (units/s). Defaults to `0.28`. */\n fallSpeedMax?: number;\n /** Minimum horizontal drift speed (units/s). Defaults to `0.04`. */\n driftMin?: number;\n /** Maximum horizontal drift speed (units/s). Defaults to `0.14`. */\n driftMax?: number;\n /**\n * Flutter strength (radians). Subtle rotation sway as each petal falls.\n * Defaults to `0.35`.\n */\n flutter?: number;\n /** Single petal color or palette; multiple entries pick a random color per petal. */\n color?: ColorRepresentation | ColorRepresentation[];\n}\n\n/**\n * Soft, slow-drifting petals (or leaves) falling through a bounded volume —\n * cherry-blossom float rather than stiff tumble. Each instance drifts downward\n * with gentle horizontal wander and a light sinusoidal flutter.\n *\n * Call {@link PetalDriftEffect.update} each frame with elapsed time in seconds.\n *\n * @example\n * ```typescript\n * const petals = new PetalDriftEffect({\n * count: 80,\n * color: [0xffd6f0, 0xfff0f8, 0xf8c8e0],\n * flutter: 0.3,\n * });\n * scene.add(petals);\n *\n * onFrame((dt) => petals.update(dt));\n * ```\n */\nexport class PetalDriftEffect extends InstancedMesh {\n private readonly width: number;\n private readonly height: number;\n private readonly depth: number;\n private readonly floorY: number;\n private readonly flutter: number;\n private readonly px: Float32Array;\n private readonly py: Float32Array;\n private readonly pz: Float32Array;\n private readonly fallSpeed: Float32Array;\n private readonly driftX: Float32Array;\n private readonly driftZ: Float32Array;\n private readonly rotX: Float32Array;\n private readonly rotY: Float32Array;\n private readonly rotZ: Float32Array;\n private readonly phase: Float32Array;\n private readonly dummy = new Object3D();\n private clock = 0;\n\n constructor(options: PetalDriftEffectOptions = {}) {\n const {\n count = 120,\n width = 16,\n height = 8,\n depth = 16,\n floorY = 0,\n fallSpeedMin = 0.12,\n fallSpeedMax = 0.28,\n driftMin = 0.04,\n driftMax = 0.14,\n flutter = 0.35,\n color = [0xffd6f0, 0xfff5fa, 0xf0b8d0],\n geometry = new EllipticLeafGeometry(),\n material,\n } = options;\n\n const palette = (Array.isArray(color) ? color : [color]).map((entry) => new Color(entry));\n const petalMaterial =\n material ??\n new MeshStandardMaterial({\n color: palette.length === 1 ? palette[0].getHex() : 0xffffff,\n metalness: 0.05,\n roughness: 0.85,\n flatShading: true,\n side: DoubleSide,\n });\n\n super(geometry, petalMaterial, count);\n this.instanceMatrix.setUsage(DynamicDrawUsage);\n this.frustumCulled = false;\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.floorY = floorY;\n this.flutter = flutter;\n\n this.px = new Float32Array(count);\n this.py = new Float32Array(count);\n this.pz = new Float32Array(count);\n this.fallSpeed = new Float32Array(count);\n this.driftX = new Float32Array(count);\n this.driftZ = new Float32Array(count);\n this.rotX = new Float32Array(count);\n this.rotY = new Float32Array(count);\n this.rotZ = new Float32Array(count);\n this.phase = new Float32Array(count);\n\n for (let i = 0; i < count; i++) {\n this.respawn(i, true);\n this.fallSpeed[i] = randomFloat(fallSpeedMin, fallSpeedMax);\n const drift = randomFloat(driftMin, driftMax);\n const angle = randomFloat(0, Math.PI * 2);\n this.driftX[i] = Math.cos(angle) * drift;\n this.driftZ[i] = Math.sin(angle) * drift;\n this.phase[i] = randomFloat(0, Math.PI * 2);\n\n if (palette.length > 1) {\n this.setColorAt(i, palette[Math.floor(Math.random() * palette.length)]);\n }\n }\n\n if (this.instanceColor) this.instanceColor.needsUpdate = true;\n this.writeMatrices();\n }\n\n /**\n * Advance petal positions and flutter. Pass elapsed frame time in seconds.\n */\n update(dt: number): void {\n this.clock += dt;\n\n for (let i = 0; i < this.count; i++) {\n const sway = Math.sin(this.clock * 1.6 + this.phase[i]) * this.flutter * 0.12;\n this.px[i] += (this.driftX[i] + sway) * dt;\n this.py[i] -= this.fallSpeed[i] * dt;\n this.pz[i] += (this.driftZ[i] + Math.cos(this.clock * 1.3 + this.phase[i]) * this.flutter * 0.08) * dt;\n\n if (this.py[i] < this.floorY) this.respawn(i, false);\n }\n\n this.writeMatrices();\n }\n\n /** Release geometry and materials held by the field. */\n dispose(): this {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n return this;\n }\n\n private respawn(index: number, randomHeight: boolean): void {\n this.px[index] = randomFloat(-this.width * 0.5, this.width * 0.5);\n this.pz[index] = randomFloat(-this.depth * 0.5, this.depth * 0.5);\n this.py[index] = randomHeight\n ? this.floorY + randomFloat(0, this.height * 1.25)\n : this.floorY + this.height + randomFloat(0, this.height * 0.25);\n this.rotX[index] = randomFloat(-0.6, 0.6);\n this.rotY[index] = randomFloat(-Math.PI, Math.PI);\n this.rotZ[index] = randomFloat(-0.8, 0.8);\n }\n\n private writeMatrices(): void {\n const d = this.dummy;\n for (let i = 0; i < this.count; i++) {\n const flutterX = Math.sin(this.clock * 2.1 + this.phase[i]) * this.flutter;\n const flutterZ = Math.cos(this.clock * 1.7 + this.phase[i]) * this.flutter * 0.6;\n d.position.set(this.px[i], this.py[i], this.pz[i]);\n d.rotation.set(this.rotX[i] + flutterX, this.rotY[i], this.rotZ[i] + flutterZ);\n d.updateMatrix();\n this.setMatrixAt(i, d.matrix);\n }\n this.instanceMatrix.needsUpdate = true;\n }\n}\n","import {\n BufferGeometry,\n CanvasTexture,\n Color,\n ColorRepresentation,\n DoubleSide,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n MeshBasicMaterial,\n Object3D,\n PlaneGeometry,\n Quaternion,\n SRGBColorSpace,\n Vector3,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface RainEffectOptions {\n /** Override the streak quad geometry. Defaults to a thin `PlaneGeometry`. */\n geometry?: BufferGeometry;\n /** Override the default streak material. */\n material?: Material;\n /** Maximum number of streak instances. Defaults to `1400`. */\n count?: number;\n /** Horizontal half-extent of the rainfall area (square centered on the origin). Defaults to `26`. */\n area?: number;\n /** Vertical span above `groundY`. Defaults to `22`. */\n height?: number;\n /** World Y where streaks recycle. Defaults to `0`. */\n groundY?: number;\n /** Streak quad width. Defaults to `0.009`. */\n width?: number;\n /** Streak color. Defaults to `#aebfd6`. */\n color?: ColorRepresentation;\n /** Base material opacity at full intensity. Defaults to `0.16`. */\n opacity?: number;\n /** Minimum streak length. Defaults to `0.18`. */\n lengthMin?: number;\n /** Maximum streak length. Defaults to `0.42`. */\n lengthMax?: number;\n /** Minimum fall speed (units/s). Defaults to `11`. */\n speedMin?: number;\n /** Maximum fall speed (units/s). Defaults to `19`. */\n speedMax?: number;\n /**\n * Horizontal compass direction the wind blows (radians, 0 = +X, π/2 = +Z).\n * Only used when {@link RainEffectOptions.windStrength} is greater than zero.\n * Defaults to `0`.\n */\n windDirection?: number;\n /**\n * How much rain tilts and drifts from vertical, as `tan(angleFromVertical)`.\n * `0` = straight down (default). `0.15` ≈ 8.5° lean with matching horizontal drift.\n */\n windStrength?: number;\n /**\n * Rainfall strength (0–1). Scales visible instance count, fall speed, and opacity.\n * Defaults to `0.5`.\n */\n intensity?: number;\n}\n\nfunction createStreakTexture(): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = 8;\n canvas.height = 64;\n const ctx = canvas.getContext(\"2d\")!;\n const gradient = ctx.createLinearGradient(0, 0, 0, 64);\n gradient.addColorStop(0, \"rgba(255,255,255,0)\");\n gradient.addColorStop(0.42, \"rgba(255,255,255,0.55)\");\n gradient.addColorStop(0.58, \"rgba(255,255,255,0.55)\");\n gradient.addColorStop(1, \"rgba(255,255,255,0)\");\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, 8, 64);\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\n/**\n * Misty rainfall as instanced vertical streaks.\n *\n * Each streak is a thin, gradient-textured quad animated through a bounded\n * volume. By default streaks fall straight down with no rotation. Optional\n * {@link RainEffectOptions.windDirection} / {@link RainEffectOptions.windStrength}\n * tilt streaks **and** drift them horizontally together, so motion matches the\n * visual angle. Streak materials use `DoubleSide` so thin quads stay visible\n * from any camera angle. Scene fog dissolves distant streaks when the material's\n * `fog` flag is enabled.\n *\n * **`intensity`** (0–1) scales how many instances draw, how fast they fall, and\n * their opacity — useful for storm ramps or lightning flashes.\n *\n * @example\n * ```typescript\n * const rain = new RainEffect({ area: 12, height: 16, intensity: 0.4 });\n * scene.add(rain);\n * scene.fog = new Fog(0x0a0a12, 4, 28);\n *\n * function animate(delta: number) {\n * rain.update(delta);\n * renderer.render(scene, camera);\n * }\n * ```\n */\nexport class RainEffect extends InstancedMesh {\n /** Rainfall strength (0–1). Adjust at runtime for storm variation. */\n intensity: number;\n\n private readonly maxCount: number;\n private readonly area: number;\n private readonly height: number;\n private readonly groundY: number;\n private readonly baseOpacity: number;\n private readonly windDirection: number;\n private readonly windStrength: number;\n private readonly fallDirection = new Vector3(0, -1, 0);\n private readonly streakOrientation = new Quaternion();\n private readonly sx: Float32Array;\n private readonly sz: Float32Array;\n private readonly topY: Float32Array;\n private readonly len: Float32Array;\n private readonly speed: Float32Array;\n private readonly streakTexture?: CanvasTexture;\n private readonly dummy = new Object3D();\n private clock = 0;\n\n constructor(options: RainEffectOptions = {}) {\n const {\n count = 1400,\n area = 26,\n height = 22,\n groundY = 0,\n width = 0.009,\n color = \"#aebfd6\",\n opacity = 0.16,\n lengthMin = 0.18,\n lengthMax = 0.42,\n speedMin = 11,\n speedMax = 19,\n windDirection = 0,\n windStrength = 0,\n intensity = 0.5,\n geometry = new PlaneGeometry(width, 1),\n material,\n } = options;\n\n const streakTexture = material ? undefined : createStreakTexture();\n const rainMaterial =\n material ??\n new MeshBasicMaterial({\n color: new Color(color),\n map: streakTexture,\n transparent: true,\n opacity,\n depthWrite: false,\n toneMapped: false,\n fog: true,\n side: DoubleSide,\n });\n\n super(geometry, rainMaterial, count);\n this.instanceMatrix.setUsage(DynamicDrawUsage);\n this.frustumCulled = false;\n\n this.maxCount = count;\n this.area = area;\n this.height = height;\n this.groundY = groundY;\n this.baseOpacity = opacity;\n this.windDirection = windDirection;\n this.windStrength = Math.max(0, windStrength);\n this.updateFallDirection(0);\n this.intensity = intensity;\n this.streakTexture = streakTexture;\n\n this.sx = new Float32Array(count);\n this.sz = new Float32Array(count);\n this.topY = new Float32Array(count);\n this.len = new Float32Array(count);\n this.speed = new Float32Array(count);\n\n for (let i = 0; i < count; i++) {\n this.sx[i] = randomFloat(-area, area);\n this.sz[i] = randomFloat(-area, area);\n this.topY[i] = randomFloat(groundY, groundY + height);\n this.len[i] = randomFloat(lengthMin, lengthMax);\n this.speed[i] = randomFloat(speedMin, speedMax);\n }\n\n this.writeMatrices();\n this.applyIntensity();\n }\n\n /**\n * Advance streak positions and refresh instance transforms. Pass elapsed frame\n * time in seconds (e.g. from `createScene`'s `onFrame` callback).\n */\n update(dt: number): void {\n this.clock += dt;\n\n const gust =\n this.windStrength > 0 ? Math.sin(this.clock * 0.18) * 0.04 * this.windStrength : 0;\n this.updateFallDirection(gust);\n\n const fall = 0.85 + this.intensity * 0.7;\n const top = this.groundY + this.height;\n const driftX = this.fallDirection.x;\n const driftZ = this.fallDirection.z;\n const fallY = -this.fallDirection.y;\n\n for (let i = 0; i < this.maxCount; i++) {\n const travel = this.speed[i] * fall * dt;\n this.sx[i] += driftX * travel;\n this.sz[i] += driftZ * travel;\n this.topY[i] -= fallY * travel;\n\n if (this.topY[i] < this.groundY - this.len[i]) this.topY[i] += this.height;\n if (this.topY[i] > top) this.topY[i] -= this.height;\n\n if (this.sx[i] < -this.area) this.sx[i] += this.area * 2;\n else if (this.sx[i] > this.area) this.sx[i] -= this.area * 2;\n if (this.sz[i] < -this.area) this.sz[i] += this.area * 2;\n else if (this.sz[i] > this.area) this.sz[i] -= this.area * 2;\n }\n\n this.writeMatrices();\n this.applyIntensity();\n }\n\n /** Release geometry, materials, and the procedural streak texture. */\n dispose(): this {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n this.streakTexture?.dispose();\n return this;\n }\n\n private applyIntensity(): void {\n // Light drizzle still reads at low rainfall.\n this.count = Math.round(this.maxCount * Math.min(1, Math.max(0, 0.38 + this.intensity * 0.62)));\n\n const mat = this.material as MeshBasicMaterial;\n mat.opacity = this.baseOpacity * (0.55 + 0.65 * this.intensity);\n }\n\n private updateFallDirection(gust: number): void {\n const lean = this.windStrength + gust;\n if (lean <= 0) {\n this.fallDirection.set(0, -1, 0);\n this.streakOrientation.identity();\n return;\n }\n\n const horizontal = lean;\n const vertical = 1;\n const invLength = 1 / Math.hypot(horizontal, vertical);\n this.fallDirection.set(\n Math.cos(this.windDirection) * horizontal * invLength,\n -vertical * invLength,\n Math.sin(this.windDirection) * horizontal * invLength,\n );\n this.streakOrientation.setFromUnitVectors(new Vector3(0, 1, 0), this.fallDirection);\n }\n\n private writeMatrices(): void {\n const d = this.dummy;\n for (let i = 0; i < this.maxCount; i++) {\n const length = this.len[i];\n d.position.set(this.sx[i], this.topY[i] - length / 2, this.sz[i]);\n d.quaternion.copy(this.streakOrientation);\n d.scale.set(1, length, 1);\n d.updateMatrix();\n this.setMatrixAt(i, d.matrix);\n }\n this.instanceMatrix.needsUpdate = true;\n }\n}","import { Shape } from \"three\";\n\nexport class BurstShape extends Shape {\n constructor(sides = 5, innerRadius = 0.5, outerRadius = 1.0) {\n super();\n\n const step = (Math.PI * 2) / sides;\n const halfStep = step / 2;\n const qtrStep = step / 4;\n\n this.moveTo(Math.cos(0) * outerRadius, -Math.sin(0) * outerRadius);\n\n for (let n = 1; n <= sides; ++n) {\n let cx = Math.cos(step * n - qtrStep * 3) * (innerRadius / Math.cos(qtrStep));\n let cy = -Math.sin(step * n - qtrStep * 3) * (innerRadius / Math.cos(qtrStep));\n let dx = Math.cos(step * n - halfStep) * innerRadius;\n let dy = -Math.sin(step * n - halfStep) * innerRadius;\n this.quadraticCurveTo(cx, cy, dx, dy);\n cx = Math.cos(step * n - qtrStep) * (innerRadius / Math.cos(qtrStep));\n cy = -Math.sin(step * n - qtrStep) * (innerRadius / Math.cos(qtrStep));\n dx = Math.cos(step * n) * outerRadius;\n dy = -Math.sin(step * n) * outerRadius;\n this.quadraticCurveTo(cx, cy, dx, dy);\n }\n\n this.closePath();\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { BurstShape } from \"../../shapes/BurstShape\";\n\nexport interface BurstGeometryOptions {\n /** Number of burst rays. Defaults to `5`. */\n sides?: number;\n /** Inner vertex radius. Defaults to `0.5`. */\n innerRadius?: number;\n /** Outer vertex radius. Defaults to `1`. */\n outerRadius?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded burst / starburst prism.\n */\nexport class BurstGeometry extends ExtrudeGeometry {\n constructor({\n sides = 5,\n innerRadius = 0.5,\n outerRadius = 1.0,\n depth = 0.25,\n }: BurstGeometryOptions = {}) {\n super(new BurstShape(sides, innerRadius, outerRadius), { depth, bevelEnabled: false });\n }\n}","import {\n BufferAttribute,\n BufferGeometry,\n CanvasTexture,\n Color,\n ColorRepresentation,\n DoubleSide,\n DynamicDrawUsage,\n InstancedMesh,\n Material,\n Matrix4,\n MeshBasicMaterial,\n Object3D,\n Points,\n PointsMaterial,\n Quaternion,\n Vector3,\n} from \"three\";\nimport { BurstGeometry } from \"../geometry/shapes/BurstGeometry\";\n\nexport interface StarBurstShapeOptions {\n /** Burst ray count. Defaults to `4`. */\n sides?: number;\n innerRadius?: number;\n outerRadius?: number;\n /** Extrusion depth; keep small for flat starbursts. Defaults to `0.05`. */\n depth?: number;\n}\n\nexport interface StarFieldEffectOptions {\n /**\n * Rendering style.\n *\n * - `points` (default) — billboard sprites with a procedural starburst texture\n * (not the default square `Points` marker).\n * - `burst` — instanced {@link BurstGeometry} meshes oriented toward the shell center.\n */\n style?: \"points\" | \"burst\";\n /** Shape parameters for both styles; `burst` uses them for geometry, `points` for the sprite. */\n burst?: StarBurstShapeOptions;\n /** Override the burst mesh geometry (`style: \"burst\"` only). */\n geometry?: BufferGeometry;\n /** Override the default field material. */\n material?: Material;\n /** Number of stars. Defaults to `1500`. */\n count?: number;\n /** Shell radius when `minRadius` / `maxRadius` are omitted. Defaults to `500`. */\n radius?: number;\n /** Inner shell radius. Defaults to `radius`. */\n minRadius?: number;\n /** Outer shell radius. Defaults to `radius`. */\n maxRadius?: number;\n /**\n * Minimum angular size (radians at 1 unit distance). Scaled by each star's shell distance\n * so apparent size stays consistent. Defaults to `0.008`.\n */\n sizeMin?: number;\n /** Maximum angular size. Defaults to `0.025`. */\n sizeMax?: number;\n /** Single color or palette; multiple entries pick a random color per star. */\n color?: ColorRepresentation | ColorRepresentation[];\n /** Enable pulsing brightness; call {@link StarFieldEffect.update} each frame when `true`. */\n twinkle?: boolean;\n}\n\nconst SHELL_CENTER = new Vector3(0, 0, 0);\n\n/** Canvas sprite matching the burst profile (inner/outer star polygon). */\nfunction createStarSpriteTexture(\n sides: number,\n innerRadius: number,\n outerRadius: number,\n size = 128,\n): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n const ctx = canvas.getContext(\"2d\")!;\n const outer = size * 0.46;\n const inner = outer * (innerRadius / outerRadius);\n\n ctx.translate(size / 2, size / 2);\n ctx.fillStyle = \"#ffffff\";\n ctx.beginPath();\n for (let i = 0; i < sides * 2; i++) {\n const radius = i % 2 === 0 ? outer : inner;\n const angle = (i / (sides * 2)) * Math.PI * 2 - Math.PI / 2;\n const x = Math.cos(angle) * radius;\n const y = Math.sin(angle) * radius;\n if (i === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.closePath();\n ctx.fill();\n\n const texture = new CanvasTexture(canvas);\n texture.needsUpdate = true;\n return texture;\n}\n\nfunction randomUnitVector(target: Vector3): Vector3 {\n const u = Math.random();\n const v = Math.random();\n const theta = Math.PI * 2 * u;\n const phi = Math.acos(2 * v - 1);\n const sinPhi = Math.sin(phi);\n return target.set(sinPhi * Math.cos(theta), Math.cos(phi), sinPhi * Math.sin(theta));\n}\n\nfunction resolvePalette(color: ColorRepresentation | ColorRepresentation[]): Color[] {\n return (Array.isArray(color) ? color : [color]).map((entry) => new Color(entry));\n}\n\n/**\n * Procedural star field distributed on a spherical shell — intended as an infinite sky dome.\n *\n * Stars are placed in world space around the origin. To keep the shell centered on the\n * viewer, add this object to the **scene** (not the camera) and copy the camera position\n * every frame. Parenting to the camera is not supported: Three.js does not render\n * objects attached to the active camera.\n *\n * **Styles**\n *\n * - `points` — lightweight `Points` sprites using a canvas starburst texture.\n * - `burst` — instanced 3D starbursts ({@link BurstGeometry}) that face the shell center.\n * Uses `DoubleSide` so stars remain visible when the camera sits inside the shell.\n *\n * **Sizing** — `sizeMin` / `sizeMax` are angular extents (radians at unit distance),\n * multiplied by each star's distance from the origin so stars look similar regardless\n * of shell depth (`minRadius`–`maxRadius`).\n *\n * **Rendering** — `frustumCulled` is disabled and materials use `depthWrite: false` so\n * the field draws reliably as a background layer. For per-star color variation in burst\n * mode, colors are written via `InstancedMesh.setColorAt`, not `vertexColors` on the\n * base material.\n *\n * @example\n * ```typescript\n * const stars = new StarFieldEffect({\n * style: \"burst\",\n * count: 2500,\n * radius: 480,\n * twinkle: true,\n * });\n *\n * scene.add(stars);\n *\n * function animate() {\n * stars.position.copy(camera.position); // sky dome follows the viewer\n * stars.update(); // no-op when twinkle is false\n * renderer.render(scene, camera);\n * }\n * ```\n *\n * Call {@link dispose} when removing the effect to free geometry, materials, and the\n * points sprite texture.\n */\nexport class StarFieldEffect extends Object3D {\n readonly style: \"points\" | \"burst\";\n\n private readonly field: Points | InstancedMesh;\n private readonly twinkle: boolean;\n private readonly baseSize: number;\n private readonly baseScales?: Float32Array;\n private readonly twinklePhases?: Float32Array;\n /** Untwinkled per-point RGB (points style), multiplied by each star's pulse each frame. */\n private baseColors?: Float32Array;\n private spriteTexture?: CanvasTexture;\n private readonly dummy = new Object3D();\n\n constructor(options: StarFieldEffectOptions = {}) {\n super();\n\n this.style = options.style ?? \"points\";\n const {\n count = 1500,\n radius = 500,\n minRadius = radius,\n maxRadius = radius,\n sizeMin = 0.008,\n sizeMax = 0.025,\n color = [0xffffff, 0xcad7ff, 0xfff4e0],\n twinkle = false,\n material,\n burst = {},\n geometry,\n } = options;\n\n this.frustumCulled = false;\n this.twinkle = twinkle;\n const shellSpan = Math.max(maxRadius - minRadius, 0);\n const meanRadius = minRadius + shellSpan * 0.5;\n const meanAngular = (sizeMin + sizeMax) * 0.5;\n this.baseSize = meanRadius * meanAngular;\n\n const burstShape = {\n sides: burst.sides ?? 4,\n innerRadius: burst.innerRadius ?? 0.6,\n outerRadius: burst.outerRadius ?? 1.9,\n depth: burst.depth ?? 0.05,\n };\n\n if (twinkle) {\n this.twinklePhases = new Float32Array(count);\n }\n\n if (this.style === \"burst\") {\n if (twinkle) {\n this.baseScales = new Float32Array(count);\n }\n const burstGeometry =\n geometry ??\n new BurstGeometry({\n sides: burstShape.sides,\n innerRadius: burstShape.innerRadius,\n outerRadius: burstShape.outerRadius,\n depth: burstShape.depth,\n });\n this.field = this.createBurstField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n geometry: burstGeometry,\n });\n } else {\n this.field = this.createPointsField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n burstShape,\n });\n }\n\n this.add(this.field);\n }\n\n get drawable(): Points | InstancedMesh {\n return this.field;\n }\n\n get geometry(): BufferGeometry {\n return this.field.geometry;\n }\n\n get material(): Material | Material[] {\n return this.field.material;\n }\n\n /** Release GPU resources held by the field (and sprite texture, if any). */\n dispose(): void {\n this.geometry.dispose();\n const materials = Array.isArray(this.material) ? this.material : [this.material];\n for (const entry of materials) entry.dispose();\n this.spriteTexture?.dispose();\n }\n\n /**\n * Animate twinkling. No-op when `twinkle` is `false`.\n *\n * Both styles pulse with a per-star phase offset so stars twinkle out of sync:\n * points modulate per-point brightness (via the color attribute), burst pulses\n * each instance scale. Pass elapsed time in seconds (defaults to `performance.now()`).\n */\n update(elapsed = performance.now() * 0.001): void {\n if (!this.twinkle) return;\n\n if (this.field instanceof Points) {\n if (this.twinklePhases && this.baseColors) {\n // Twinkle brightness per point, each with its own phase, by modulating the\n // color attribute. PointsMaterial.size is a single field-wide uniform, so\n // pulsing it would make every star flash in unison — the desync has to live\n // in per-point data, and color is the per-point channel Points already has.\n const colorAttribute = this.field.geometry.getAttribute(\"color\") as BufferAttribute;\n const array = colorAttribute.array as Float32Array;\n const base = this.baseColors;\n for (let i = 0; i < this.twinklePhases.length; i++) {\n const pulse = 0.65 + 0.35 * Math.sin(elapsed * 2.5 + this.twinklePhases[i]);\n array[i * 3] = base[i * 3] * pulse;\n array[i * 3 + 1] = base[i * 3 + 1] * pulse;\n array[i * 3 + 2] = base[i * 3 + 2] * pulse;\n }\n colorAttribute.needsUpdate = true;\n } else {\n // No per-point color buffer (e.g. a custom material with no color attribute)\n // — fall back to pulsing the shared sprite size.\n (this.field.material as PointsMaterial).size =\n this.baseSize * (0.8 + 0.2 * Math.sin(elapsed * 2.5));\n }\n return;\n }\n\n if (!this.baseScales || !this.twinklePhases) return;\n\n const matrix = new Matrix4();\n const position = new Vector3();\n const quaternion = new Quaternion();\n const scale = new Vector3();\n\n for (let i = 0; i < this.field.count; i++) {\n this.field.getMatrixAt(i, matrix);\n matrix.decompose(position, quaternion, scale);\n\n const pulse = 0.75 + 0.25 * Math.sin(elapsed * 2.5 + this.twinklePhases[i]);\n const s = this.baseScales[i] * pulse;\n this.dummy.position.copy(position);\n this.dummy.quaternion.copy(quaternion);\n this.dummy.scale.setScalar(s);\n this.dummy.updateMatrix();\n this.field.setMatrixAt(i, this.dummy.matrix);\n }\n\n this.field.instanceMatrix.needsUpdate = true;\n }\n\n private createPointsField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n burstShape,\n }: {\n count: number;\n minRadius: number;\n maxRadius: number;\n sizeMin: number;\n sizeMax: number;\n color: ColorRepresentation | ColorRepresentation[];\n material?: Material;\n burstShape: Required<StarBurstShapeOptions>;\n }): Points {\n const palette = resolvePalette(color);\n const direction = new Vector3();\n const shellSpan = Math.max(maxRadius - minRadius, 0);\n const meanRadius = minRadius + shellSpan * 0.5;\n const meanAngular = (sizeMin + sizeMax) / 2;\n const pointSize = meanRadius * meanAngular;\n\n const positions = new Float32Array(count * 3);\n // A per-point color buffer is needed for palettes and for twinkle (which pulses\n // each star's brightness independently — see update()).\n const perPointColor = palette.length > 1 || this.twinkle;\n const colors = perPointColor ? new Float32Array(count * 3) : null;\n\n for (let i = 0; i < count; i++) {\n const distance = minRadius + Math.random() * shellSpan;\n randomUnitVector(direction).multiplyScalar(distance);\n positions[i * 3] = direction.x;\n positions[i * 3 + 1] = direction.y;\n positions[i * 3 + 2] = direction.z;\n\n if (colors) {\n const starColor = palette[Math.floor(Math.random() * palette.length)];\n colors[i * 3] = starColor.r;\n colors[i * 3 + 1] = starColor.g;\n colors[i * 3 + 2] = starColor.b;\n }\n if (this.twinklePhases) this.twinklePhases[i] = Math.random() * Math.PI * 2;\n }\n\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new BufferAttribute(positions, 3));\n if (colors) {\n const colorAttribute = new BufferAttribute(colors, 3);\n if (this.twinkle) {\n // Retain the untwinkled colors to multiply against each frame; the live\n // attribute is rewritten every update, so mark it dynamic.\n this.baseColors = colors.slice();\n colorAttribute.setUsage(DynamicDrawUsage);\n }\n geometry.setAttribute(\"color\", colorAttribute);\n }\n\n this.spriteTexture = createStarSpriteTexture(\n burstShape.sides!,\n burstShape.innerRadius!,\n burstShape.outerRadius!,\n );\n\n const starMaterial =\n material ??\n new PointsMaterial({\n map: this.spriteTexture,\n // When a color buffer exists (palette or twinkle), the tint rides in the\n // vertex colors — keep the base white so it isn't applied twice.\n color: colors ? 0xffffff : palette[0].getHex(),\n size: pointSize,\n sizeAttenuation: true,\n transparent: true,\n alphaTest: 0.05,\n vertexColors: colors !== null,\n depthWrite: false,\n toneMapped: false,\n });\n\n const points = new Points(geometry, starMaterial);\n points.frustumCulled = false;\n points.renderOrder = 1;\n return points;\n }\n\n private createBurstField({\n count,\n minRadius,\n maxRadius,\n sizeMin,\n sizeMax,\n color,\n material,\n geometry,\n }: {\n count: number;\n minRadius: number;\n maxRadius: number;\n sizeMin: number;\n sizeMax: number;\n color: ColorRepresentation | ColorRepresentation[];\n material?: Material;\n geometry: BufferGeometry;\n }): InstancedMesh {\n const palette = resolvePalette(color);\n const direction = new Vector3();\n const shellSpan = Math.max(maxRadius - minRadius, 0);\n\n const centered = geometry.clone();\n centered.center();\n centered.computeBoundingSphere();\n const meshRadius = centered.boundingSphere?.radius ?? 1;\n\n const starMaterial =\n material ??\n new MeshBasicMaterial({\n color: palette.length === 1 ? palette[0].getHex() : 0xffffff,\n side: DoubleSide,\n depthWrite: false,\n toneMapped: false,\n });\n\n const mesh = new InstancedMesh(centered, starMaterial, count);\n mesh.frustumCulled = false;\n mesh.renderOrder = 1;\n\n for (let i = 0; i < count; i++) {\n const distance = minRadius + Math.random() * shellSpan;\n randomUnitVector(direction).multiplyScalar(distance);\n\n const angular = sizeMin + Math.random() * (sizeMax - sizeMin);\n const scale = (distance * angular) / meshRadius;\n if (this.baseScales) this.baseScales[i] = scale;\n if (this.twinklePhases) this.twinklePhases[i] = Math.random() * Math.PI * 2;\n\n this.dummy.position.copy(direction);\n this.dummy.lookAt(SHELL_CENTER);\n this.dummy.rotateZ(Math.random() * Math.PI * 2);\n this.dummy.scale.setScalar(scale);\n this.dummy.updateMatrix();\n mesh.setMatrixAt(i, this.dummy.matrix);\n\n if (palette.length > 1) {\n mesh.setColorAt(i, palette[Math.floor(Math.random() * palette.length)]);\n }\n }\n\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;\n\n return mesh;\n }\n}","import {\n Color,\n ColorRepresentation,\n Mesh,\n MeshBasicMaterial,\n Object3D,\n PointLight,\n SphereGeometry,\n Vector3,\n} from \"three\";\nimport { randomFloat } from \"../utils/RandomNumberUtils\";\n\nexport interface WispEffectOptions {\n /** Number of drifting wisps. Defaults to `3`. */\n count?: number;\n /** Horizontal spawn extent (world units, centered on the effect). Defaults to `16`. */\n width?: number;\n /** Depth spawn maximum (world units, from z = 0). Defaults to `8`. */\n depth?: number;\n /** Minimum spawn height. Defaults to `1`. */\n heightMin?: number;\n /** Maximum spawn height. Defaults to `2`. */\n heightMax?: number;\n /** Wisp tint. Defaults to `0x6dffb0` (portfolio graveyard). */\n color?: ColorRepresentation;\n /** Orb radius. Defaults to `0.08`. */\n orbRadius?: number;\n /** Horizontal drift radius (X). Defaults to `1.6`. */\n driftX?: number;\n /** Vertical drift radius (Y). Defaults to `0.3`. */\n driftY?: number;\n /** Depth drift radius (Z). Defaults to `1.6`. */\n driftZ?: number;\n /** Minimum motion speed multiplier. Defaults to `0.3`. */\n speedMin?: number;\n /** Maximum motion speed multiplier. Defaults to `0.7`. */\n speedMax?: number;\n /**\n * Attach a {@link PointLight} per wisp (keep `count` low).\n * Defaults to `true` to match the portfolio graveyard.\n */\n castLight?: boolean;\n /** Point light distance when `castLight`. Defaults to `6`. */\n lightDistance?: number;\n /** Point light decay when `castLight`. Defaults to `2`. */\n lightDecay?: number;\n /**\n * Light intensity = `lightIntensity + sin(t * lightPulseSpeed) * lightPulseAmplitude`.\n * Defaults to `2.5`.\n */\n lightIntensity?: number;\n /** Defaults to `1.2`. */\n lightPulseAmplitude?: number;\n /** Defaults to `3`. */\n lightPulseSpeed?: number;\n}\n\ninterface WispInstance {\n orb: Mesh<SphereGeometry, MeshBasicMaterial>;\n home: Vector3;\n phase: number;\n speed: number;\n light?: PointLight;\n}\n\n/**\n * Will-o'-the-wisps drifting through a bounded volume — eerie green orbs that\n * bob around spawn points with a pulsing point light. Ported from the portfolio\n * graveyard scene.\n *\n * @example\n * ```ts\n * const wisps = new WispEffect({ count: 3 });\n * scene.add(wisps);\n * onFrame((dt) => wisps.update(dt));\n * ```\n */\nexport class WispEffect extends Object3D {\n private readonly wisps: WispInstance[] = [];\n private readonly orbGeometry: SphereGeometry;\n private readonly orbMaterial: MeshBasicMaterial;\n private readonly halfWidth: number;\n private readonly depth: number;\n private readonly heightMin: number;\n private readonly heightMax: number;\n private readonly driftX: number;\n private readonly driftY: number;\n private readonly driftZ: number;\n private readonly speedMin: number;\n private readonly speedMax: number;\n private readonly castLight: boolean;\n private readonly lightDistance: number;\n private readonly lightDecay: number;\n private readonly lightIntensity: number;\n private readonly lightPulseAmplitude: number;\n private readonly lightPulseSpeed: number;\n\n private elapsed = 0;\n\n constructor({\n count = 3,\n width = 16,\n depth = 8,\n heightMin = 1,\n heightMax = 2,\n color = 0x6dffb0,\n orbRadius = 0.08,\n driftX = 1.6,\n driftY = 0.3,\n driftZ = 1.6,\n speedMin = 0.3,\n speedMax = 0.7,\n castLight = true,\n lightDistance = 6,\n lightDecay = 2,\n lightIntensity = 2.5,\n lightPulseAmplitude = 1.2,\n lightPulseSpeed = 3,\n }: WispEffectOptions = {}) {\n super();\n\n this.halfWidth = width / 2;\n this.depth = depth;\n this.heightMin = heightMin;\n this.heightMax = heightMax;\n this.driftX = driftX;\n this.driftY = driftY;\n this.driftZ = driftZ;\n this.speedMin = speedMin;\n this.speedMax = speedMax;\n this.castLight = castLight;\n this.lightDistance = lightDistance;\n this.lightDecay = lightDecay;\n this.lightIntensity = lightIntensity;\n this.lightPulseAmplitude = lightPulseAmplitude;\n this.lightPulseSpeed = lightPulseSpeed;\n\n this.orbGeometry = new SphereGeometry(orbRadius, 8, 8);\n this.orbMaterial = new MeshBasicMaterial({ color: new Color(color), toneMapped: false });\n\n for (let i = 0; i < count; i++) {\n const home = new Vector3(\n randomFloat(-this.halfWidth, this.halfWidth),\n randomFloat(this.heightMin, this.heightMax),\n randomFloat(0, this.depth),\n );\n\n const orb = new Mesh(this.orbGeometry, this.orbMaterial);\n orb.position.copy(home);\n this.add(orb);\n\n let light: PointLight | undefined;\n if (castLight) {\n light = new PointLight(color, 3, this.lightDistance, this.lightDecay);\n orb.add(light);\n }\n\n this.wisps.push({\n orb,\n home,\n phase: randomFloat(0, Math.PI * 2),\n speed: randomFloat(this.speedMin, this.speedMax),\n light,\n });\n }\n }\n\n update(dt: number): void {\n this.elapsed += dt;\n\n for (const wisp of this.wisps) {\n const t = this.elapsed * wisp.speed + wisp.phase;\n wisp.orb.position.set(\n wisp.home.x + Math.sin(t) * this.driftX,\n wisp.home.y + Math.sin(t * 1.7) * this.driftY,\n wisp.home.z + Math.cos(t * 0.8) * this.driftZ,\n );\n\n if (wisp.light) {\n wisp.light.intensity =\n this.lightIntensity + Math.sin(t * this.lightPulseSpeed) * this.lightPulseAmplitude;\n }\n }\n }\n\n dispose(): void {\n this.orbGeometry.dispose();\n this.orbMaterial.dispose();\n for (const wisp of this.wisps) {\n wisp.light?.dispose();\n }\n this.clear();\n this.wisps.length = 0;\n }\n}","import { BoxGeometry, BufferAttribute, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface BookGeometryOptions {\n /** Cover width (spine to fore-edge). Defaults to `1`. */\n width?: number;\n /** Cover height. Defaults to `1.5`. */\n height?: number;\n /** Spine depth (cover to cover). Defaults to `0.5`. */\n depth?: number;\n /** Cover board thickness. Defaults to `0.05`. */\n coverThickness?: number;\n /** Inset of the page block from the cover edges. Defaults to `0.05`. */\n pageIndent?: number;\n}\n\n/**\n * Closed book — cover shell (group 0) and page block (group 1).\n *\n * Local frame: spine at X=0, fore-edge at +X, sits on the Y=0 plane.\n */\nexport class BookGeometry extends BufferGeometry {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n readonly coverThickness: number;\n readonly pageIndent: number;\n\n constructor({\n width = 1,\n height = 1.5,\n depth = 0.5,\n coverThickness = 0.05,\n pageIndent = 0.05,\n }: BookGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.coverThickness = coverThickness;\n this.pageIndent = pageIndent;\n\n const w = width;\n const h = height;\n const d = depth;\n const t = coverThickness;\n const i = pageIndent;\n\n const vertices = [\n // Front cover\n 0, 0, 0,\n w, 0, 0,\n w, h, 0,\n 0, h, 0,\n\n // Back cover\n w, 0, -d,\n 0, 0, -d,\n 0, h, -d,\n w, h, -d,\n\n // Spine\n 0, 0, -d,\n 0, 0, 0,\n 0, h, 0,\n 0, h, -d,\n\n // Inside front cover\n w, 0, -t,\n t, 0, -t,\n t, h, -t,\n w, h, -t,\n\n // Inside back cover\n t, 0, -d + t,\n w, 0, -d + t,\n w, h, -d + t,\n t, h, -d + t,\n\n // Inside spine\n t, 0, -t,\n t, 0, -d + t,\n t, h, -d + t,\n t, h, -t,\n\n // Front cover top\n 0, h, 0,\n w, h, 0,\n w, h, -t,\n t, h, -t,\n\n // Back cover top\n 0, h, -d,\n t, h, -d + t,\n w, h, -d + t,\n w, h, -d,\n\n // Spine cover top\n 0, h, 0,\n t, h, -t,\n t, h, -d + t,\n 0, h, -d,\n\n // Front cover bottom\n 0, 0, 0,\n t, 0, -t,\n w, 0, -t,\n w, 0, 0,\n\n // Back cover bottom\n 0, 0, -d,\n w, 0, -d,\n w, 0, -d + t,\n t, 0, -d + t,\n\n // Spine cover bottom\n 0, 0, 0,\n 0, 0, -d,\n t, 0, -d + t,\n t, 0, -t,\n\n // Front cover edge\n w, 0, 0,\n w, 0, -t,\n w, h, -t,\n w, h, 0,\n\n // Back cover edge\n w, 0, -d,\n w, h, -d,\n w, h, -d + t,\n w, 0, -d + t,\n ];\n\n\n\n const normals = [\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Front cover\n 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, // Back cover\n -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // Spine\n 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, // Inside front cover\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Inside back cover\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Inside spine\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Front cover top\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Back cover top\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Spine cover top\n 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // Front cover bottom\n 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // Back cover bottom\n 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // Spine cover bottom\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Front cover edge\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Back cover edge\n ];\n\n const u1 = width / ((width * 2) + depth);\n const u2 = (width + depth) / ((width * 2) + depth);\n\n const uvs = [\n u2,0, 1,0, 1,1, u2,1, // Front cover\n 0,0, u1,0, u1,1, 0,1, // Back cover\n u1,0, u2,0, u2,1, u1,1, // Spine\n 1,0, u2,0, u2,1, 1,1, // Inside front cover\n u1,0, 0,0, 0,1, u1,1, // Inside back cover\n u2,0, u1,0, u1,1, u2,1, // Inside spine\n u2,0, 1,0, 1,1, u2,1, // Front cover top\n 0,0, 1,0, 1,1, 0,1, // Back cover top\n 0,0, 1,0, 1,1, 0,1, // Spine cover top\n 0,0, 1,0, 1,1, 0,1, // Front cover bottom\n 0,0, 1,0, 1,1, 0,1, // Back cover bottom\n 0,0, 1,0, 1,1, 0,1, // Spine cover bottom\n 0,0, 1,0, 1,1, 0,1, // Front cover edge\n 0,0, 1,0, 1,1, 0,1, // Back cover edge\n ];\n\n const indices = [\n 0, 1, 2, 0, 2, 3, // Front cover face\n 4, 5, 6, 4, 6, 7, // Back cover face\n 8, 9, 10, 8, 10, 11, // Spine face\n 12, 13, 14, 12, 14, 15, // Inside front cover\n 16, 17, 18, 16, 18, 19, // Inside back cover\n 20, 21, 22, 20, 22, 23, // Inside spine\n 24, 25, 26, 24, 26, 27, // Front cover top\n 28, 29, 30, 28, 30, 31, // Back cover top\n 32, 33, 34, 32, 34, 35, // Spine cover top\n 36, 37, 38, 36, 38, 39, // Front cover bottom\n 40, 41, 42, 40, 42, 43, // Back cover bottom\n 44, 45, 46, 44, 46, 47, // Spine cover bottom\n 48, 49, 50, 48, 50, 51, // Front cover edge\n 52, 53, 54, 52, 54, 55, // Back cover edge\n ];\n\n const positions = new Float32Array(vertices);\n const normalArray = new Float32Array(normals);\n const uvArray = new Float32Array(uvs);\n const indexArray = new Uint16Array(indices);\n\n const coverGeometry = new BufferGeometry();\n coverGeometry.setAttribute('position', new BufferAttribute(positions, 3));\n coverGeometry.setAttribute('normal', new BufferAttribute(normalArray, 3));\n coverGeometry.setAttribute('uv', new BufferAttribute(uvArray, 2));\n coverGeometry.setIndex(new BufferAttribute(indexArray, 1));\n\n const pagesGeometry = new BoxGeometry(width - t - i, h - i * 2, d - t * 2);\n pagesGeometry.translate((width - t - i) / 2 + t, h / 2, -d / 2 );\n this.copy(mergeGeometries([coverGeometry, pagesGeometry], true) as BufferGeometry);\n }\n}\n","import { BookGeometry } from \"../geometry/books/BookGeometry\";\nimport { InstancedMesh, Matrix4, Material, Quaternion, Vector3 } from \"three\";\nimport { createRandom, type RandomSource } from \"../utils/Random\";\nimport { logarithmicRandomMax, logarithmicRandomMin, randomFloat } from \"../utils/RandomNumberUtils\";\n\n/** Default {@link BookGeometry} spine depth — stack layer height when books lay flat. */\nconst BOOK_UNIT_DEPTH = 0.5;\n\n/** Lay a book flat on its cover (+90° X) so spine depth becomes stack height (Y+). */\nconst LAY_FLAT_X = Math.PI / 2;\n\ninterface RandomScaleOptions {\n scaleXMin?: number;\n scaleXMax?: number;\n scaleYMin?: number;\n scaleYMax?: number;\n scaleZMin?: number;\n scaleZMax?: number;\n source: RandomSource;\n}\n\n// Define a generic interface for book row options using scales\ninterface RowOfBooksByScalesOptions<T extends Material = Material> {\n coverMaterial: T;\n pagesMaterial: T;\n scales: Vector3[];\n /** Shared stream for shelf jitter — must be the same source that built `scales`. */\n source: RandomSource;\n}\n\nexport interface RowOfBooksOptions<T extends Material = Material> {\n coverMaterial: T;\n pagesMaterial: T;\n count?: number;\n length?: number;\n scaleXMin?: number;\n scaleXMax?: number;\n scaleYMin?: number;\n scaleYMax?: number;\n scaleZMin?: number;\n scaleZMax?: number;\n /** Optional seed for reproducible layout. Omit for unique runtime. */\n seed?: number;\n}\n\nexport interface StackOfBooksOptions<T extends Material = Material> {\n coverMaterial: T;\n pagesMaterial: T;\n /** Number of books in the stack. Defaults to `6`. */\n count?: number;\n scaleXMin?: number;\n scaleXMax?: number;\n scaleYMin?: number;\n scaleYMax?: number;\n scaleZMin?: number;\n scaleZMax?: number;\n /**\n * Max in-plane spin (world Y, radians) once the book is laid flat — a lazy\n * turn on the floor, not a tilt. Defaults to `0.55` (~31°).\n */\n yawMax?: number;\n /** Max horizontal drift per layer on X/Z. Defaults to `0.06`. */\n offsetMax?: number;\n /** Optional seed for reproducible layout. Omit for unique runtime. */\n seed?: number;\n}\n\nfunction randomScale({\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n source,\n}: RandomScaleOptions): Vector3 {\n return new Vector3(\n randomFloat(scaleXMin, scaleXMax, source),\n logarithmicRandomMax(0.25, scaleYMin, scaleYMax, source),\n logarithmicRandomMin(0.8, scaleZMin, scaleZMax, source),\n );\n}\n\n/**\n * Creates a row of books from the scales array of Vector3.\n */\nexport function rowOfBooksByScales<T extends Material>({\n coverMaterial,\n pagesMaterial,\n scales,\n source,\n}: RowOfBooksByScalesOptions<T>): InstancedMesh {\n const geometry = new BookGeometry();\n const row = new InstancedMesh(geometry, [coverMaterial, pagesMaterial], scales.length);\n const matrix = new Matrix4();\n let currentZ = 0;\n\n for (let i = 0; i < scales.length; i++) {\n const scale = scales[i];\n const scaleMatrix = new Matrix4();\n scaleMatrix.makeScale(scale.x, scale.y, scale.z);\n matrix.identity();\n matrix.multiply(scaleMatrix);\n matrix.setPosition(0.01 + source.float(0, 0.1), 0, currentZ + scale.z * 0.5);\n row.setMatrixAt(i, matrix);\n currentZ += scale.z * 0.5;\n }\n return row;\n}\n\n/**\n * Creates a row of books with a given count.\n */\nexport function rowOfBooksByCount<T extends Material>({\n coverMaterial,\n pagesMaterial,\n count = 10,\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n seed,\n}: RowOfBooksOptions<T>): InstancedMesh {\n const source = createRandom(seed);\n const scales = Array.from({ length: count }, () =>\n randomScale({ scaleXMin, scaleXMax, scaleYMin, scaleYMax, scaleZMin, scaleZMax, source }),\n );\n\n return rowOfBooksByScales({ coverMaterial, pagesMaterial, scales, source });\n}\n\n/**\n * Creates a row of books with a total length.\n */\nexport function rowOfBooksByLength<T extends Material>({\n coverMaterial,\n pagesMaterial,\n length = 10,\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n seed,\n}: RowOfBooksOptions<T>): InstancedMesh {\n const source = createRandom(seed);\n const scales: Vector3[] = [];\n let remainingZ = length;\n while (remainingZ > 0) {\n const scale = randomScale({ scaleXMin, scaleXMax, scaleYMin, scaleYMax, scaleZMin, scaleZMax, source });\n scale.z = Math.min(scale.z, remainingZ);\n scales.push(scale);\n remainingZ -= scale.z;\n }\n\n return rowOfBooksByScales({ coverMaterial, pagesMaterial, scales, source });\n}\n\n/**\n * Stack of books on the floor — each book lays flat on its cover; count sets stack height.\n * Each layer is laid flat (+90° X), then given a small in-plane spin (world Y)\n * around the book's geometric center — not the spine corner.\n *\n * Local frame: bottom of the stack at Y=0, centered on X/Z.\n *\n * @example\n * ```ts\n * const stack = stackOfBooks({\n * coverMaterial,\n * pagesMaterial,\n * count: 8,\n * yawMax: 0.6,\n * seed: 1337,\n * });\n * scene.add(stack);\n * ```\n */\nexport function stackOfBooks<T extends Material>({\n coverMaterial,\n pagesMaterial,\n count = 6,\n scaleXMin = 0.4,\n scaleXMax = 0.7,\n scaleYMin = 0.3,\n scaleYMax = 0.95,\n scaleZMin = 0.1,\n scaleZMax = 0.5,\n yawMax = 0.55,\n offsetMax = 0.06,\n seed,\n}: StackOfBooksOptions<T>): InstancedMesh {\n const source = createRandom(seed);\n const geometry = new BookGeometry();\n const stack = new InstancedMesh(geometry, [coverMaterial, pagesMaterial], count);\n\n const matrix = new Matrix4();\n const position = new Vector3();\n const quaternion = new Quaternion();\n const layFlatQuat = new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), LAY_FLAT_X);\n const spinQuat = new Quaternion();\n const scale = new Vector3();\n /** Upright geometry center — spin pivots here, not the bottom-front-spine corner. */\n const localCenter = new Vector3(\n geometry.width * 0.5,\n geometry.height * 0.5,\n -geometry.depth * 0.5,\n );\n const scaledCenter = new Vector3();\n const centerOffset = new Vector3();\n\n let currentY = 0;\n\n for (let i = 0; i < count; i++) {\n const layerScale = randomScale({\n scaleXMin,\n scaleXMax,\n scaleYMin,\n scaleYMax,\n scaleZMin,\n scaleZMax,\n source,\n });\n\n scale.copy(layerScale);\n const layerHeight = BOOK_UNIT_DEPTH * layerScale.z;\n\n spinQuat.setFromAxisAngle(new Vector3(0, 1, 0), source.float(-yawMax, yawMax));\n quaternion.copy(layFlatQuat).premultiply(spinQuat);\n\n scaledCenter.copy(localCenter).multiply(scale);\n centerOffset.copy(scaledCenter).applyQuaternion(quaternion);\n\n position.set(\n source.float(-offsetMax, offsetMax),\n currentY + layerHeight * 0.5,\n source.float(-offsetMax, offsetMax),\n );\n position.sub(centerOffset);\n\n matrix.compose(position, quaternion, scale);\n stack.setMatrixAt(i, matrix);\n\n currentY += layerHeight;\n }\n\n stack.instanceMatrix.needsUpdate = true;\n return stack;\n}\n","/**\n * Coherent value noise + fbm — the shared core for baking procedural detail into\n * real geometry. Coherence is the whole point: neighboring samples return nearby\n * values, so vertices displaced by these functions move together and faces never\n * tear the way independent per-vertex random offsets do.\n *\n * - {@link fbm2} — heightfields (terrain: `Y = f(x, z)`).\n * - {@link fbm3} — surfaces displaced in 3D (boulders: push along the normal).\n */\n\n/** 32-bit integer hash → [0, 1). Deterministic per lattice cell + seed. */\nfunction hash2(ix: number, iy: number, seed: number): number {\n let h = Math.imul(ix | 0, 374761393) ^ Math.imul(iy | 0, 668265263) ^ Math.imul(seed | 0, 362437);\n h = Math.imul(h ^ (h >>> 13), 1274126177);\n h ^= h >>> 16;\n return (h >>> 0) / 4294967296;\n}\n\nfunction hash3(ix: number, iy: number, iz: number, seed: number): number {\n let h =\n Math.imul(ix | 0, 374761393) ^\n Math.imul(iy | 0, 668265263) ^\n Math.imul(iz | 0, 1274126177) ^\n Math.imul(seed | 0, 362437);\n h = Math.imul(h ^ (h >>> 13), 1274126177);\n h ^= h >>> 16;\n return (h >>> 0) / 4294967296;\n}\n\nconst smooth = (t: number) => t * t * (3 - 2 * t);\n\n/** Smoothly interpolated 2D value noise on a unit lattice → [0, 1). */\nfunction valueNoise2(x: number, y: number, seed: number): number {\n const x0 = Math.floor(x);\n const y0 = Math.floor(y);\n const u = smooth(x - x0);\n const v = smooth(y - y0);\n const n00 = hash2(x0, y0, seed);\n const n10 = hash2(x0 + 1, y0, seed);\n const n01 = hash2(x0, y0 + 1, seed);\n const n11 = hash2(x0 + 1, y0 + 1, seed);\n const nx0 = n00 + (n10 - n00) * u;\n const nx1 = n01 + (n11 - n01) * u;\n return nx0 + (nx1 - nx0) * v;\n}\n\n/** Smoothly interpolated 3D value noise on a unit lattice → [0, 1). */\nfunction valueNoise3(x: number, y: number, z: number, seed: number): number {\n const x0 = Math.floor(x);\n const y0 = Math.floor(y);\n const z0 = Math.floor(z);\n const u = smooth(x - x0);\n const v = smooth(y - y0);\n const w = smooth(z - z0);\n const c000 = hash3(x0, y0, z0, seed);\n const c100 = hash3(x0 + 1, y0, z0, seed);\n const c010 = hash3(x0, y0 + 1, z0, seed);\n const c110 = hash3(x0 + 1, y0 + 1, z0, seed);\n const c001 = hash3(x0, y0, z0 + 1, seed);\n const c101 = hash3(x0 + 1, y0, z0 + 1, seed);\n const c011 = hash3(x0, y0 + 1, z0 + 1, seed);\n const c111 = hash3(x0 + 1, y0 + 1, z0 + 1, seed);\n const x00 = c000 + (c100 - c000) * u;\n const x10 = c010 + (c110 - c010) * u;\n const x01 = c001 + (c101 - c001) * u;\n const x11 = c011 + (c111 - c011) * u;\n const y0v = x00 + (x10 - x00) * v;\n const y1v = x01 + (x11 - x01) * v;\n return y0v + (y1v - y0v) * w;\n}\n\n/**\n * 2D fractal Brownian motion → roughly [-1, 1]. Each octave doubles frequency and\n * scales amplitude by `persistence`, with its own seed offset so layers don't\n * correlate. Normalized by total amplitude so the range is stable across octave counts.\n */\nexport function fbm2(x: number, y: number, seed: number, octaves: number, persistence: number): number {\n let sum = 0;\n let amplitude = 1;\n let frequency = 1;\n let norm = 0;\n for (let o = 0; o < octaves; o++) {\n sum += (valueNoise2(x * frequency, y * frequency, seed + o * 101) * 2 - 1) * amplitude;\n norm += amplitude;\n amplitude *= persistence;\n frequency *= 2;\n }\n return norm > 0 ? sum / norm : 0;\n}\n\n/** 3D fractal Brownian motion → roughly [-1, 1]. The 3D counterpart to {@link fbm2}. */\nexport function fbm3(\n x: number,\n y: number,\n z: number,\n seed: number,\n octaves: number,\n persistence: number,\n): number {\n let sum = 0;\n let amplitude = 1;\n let frequency = 1;\n let norm = 0;\n for (let o = 0; o < octaves; o++) {\n sum +=\n (valueNoise3(x * frequency, y * frequency, z * frequency, seed + o * 101) * 2 - 1) * amplitude;\n norm += amplitude;\n amplitude *= persistence;\n frequency *= 2;\n }\n return norm > 0 ? sum / norm : 0;\n}\n","import { BufferGeometry, IcosahedronGeometry, Vector3 } from \"three\";\nimport { mergeVertices } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport { fbm3 } from \"../../utils/CoherentNoise\";\n\nexport interface BoulderGeometryOptions {\n /** Base radius before displacement (world units). Defaults to `1`. */\n radius?: number;\n /** Icosahedron subdivision — more detail = more, finer facets. Defaults to `2`. */\n detail?: number;\n /** Radial relief amplitude (world units, ±). Keep below `radius`. Defaults to `0.35`. */\n noiseHeight?: number;\n /** Noise frequency over the unit sphere — higher packs more, smaller lumps. Defaults to `1.6`. */\n noiseScale?: number;\n /** fbm octaves (detail layers). Defaults to `3`. */\n octaves?: number;\n /** fbm gain per octave (0–1); lower is smoother, higher is rougher. Defaults to `0.5`. */\n persistence?: number;\n /** Seed for reproducible shape. Defaults to `1`. */\n seed?: number;\n}\n\n/**\n * Boulder — an icosphere lumped by coherent 3D fbm ({@link fbm3}) displaced along\n * each vertex's radial direction. The 3D counterpart to the terrain heightfields:\n * same noise strategy, applied over a closed surface instead of a height map.\n *\n * The icosphere is welded (`mergeVertices` after stripping seam UVs) so coincident\n * vertices share one displacement — the coherent noise then moves neighbors together,\n * so the surface stays watertight and never cracks (the failure mode of displacing a\n * non-indexed polyhedron along normals). Real baked geometry, so shadows, raycasts,\n * and physics colliders match what's drawn, on WebGL and WebGPU/TSL alike.\n *\n * Centered on the origin. Pair with a `flatShading` material for a faceted low-poly\n * look. Vary `seed` per instance to fill a field with unique boulders.\n */\nexport class BoulderGeometry extends BufferGeometry {\n readonly radius: number;\n\n constructor({\n radius = 1,\n detail = 2,\n noiseHeight = 0.35,\n noiseScale = 1.6,\n octaves = 3,\n persistence = 0.5,\n seed = 1,\n }: BoulderGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n\n // Strip seam UVs/normals before welding so coincident vertices actually merge —\n // otherwise the icosphere stays split at UV seams and displacing along normals\n // would pull those duplicates apart into cracks.\n const base = new IcosahedronGeometry(radius, detail);\n base.deleteAttribute(\"uv\");\n base.deleteAttribute(\"normal\");\n const merged = mergeVertices(base);\n base.dispose();\n\n const position = merged.getAttribute(\"position\");\n const v = new Vector3();\n // Sample noise on the unit sphere (position / radius) so lump count stays\n // consistent regardless of radius; displace radially outward/inward.\n const s = noiseScale / radius;\n for (let i = 0; i < position.count; i++) {\n v.fromBufferAttribute(position, i);\n const n = fbm3(v.x * s, v.y * s, v.z * s, seed, octaves, persistence);\n const length = v.length() || 1;\n const scale = (length + n * noiseHeight) / length;\n position.setXYZ(i, v.x * scale, v.y * scale, v.z * scale);\n }\n position.needsUpdate = true;\n\n merged.computeVertexNormals();\n merged.center();\n\n this.copy(merged);\n merged.dispose();\n }\n}\n","import {\n Color,\n ColorRepresentation,\n Euler,\n Group,\n InstancedMesh,\n Material,\n Matrix4,\n MeshStandardMaterial,\n Quaternion,\n Vector3,\n} from \"three\";\nimport { BoulderGeometry } from \"../geometry/rocks/BoulderGeometry\";\nimport { createRandom } from \"../utils/Random\";\nimport type { RockScatterPlacementOptions } from \"./RockFactory\";\n\nexport interface ScatterBouldersOptions extends RockScatterPlacementOptions {\n /** Base radius for each boulder geometry. Defaults to `1`. */\n radius?: number;\n /** Icosphere subdivision per boulder. Defaults to `2`. */\n detail?: number;\n /** Radial relief amplitude per boulder. Defaults to `0.35`. */\n noiseHeight?: number;\n /** Noise frequency per boulder. Defaults to `1.6`. */\n noiseScale?: number;\n /** fbm octaves per boulder. Defaults to `3`. */\n octaves?: number;\n /** fbm gain per octave. Defaults to `0.5`. */\n persistence?: number;\n /**\n * Distinct boulder geometries generated and distributed across the field. Each is\n * a real, unique lumped shape (unlike rotating one shared mesh); instances round-robin\n * across them, so the field stays batch-friendly (one draw call per variant).\n * Defaults to `4`.\n */\n variants?: number;\n /** Override the default stone material (shared across all instances). */\n material?: Material;\n /** Stone tint when `material` is omitted. Defaults to `#6f6f6f`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Scatter a field of instanced boulders inside a horizontal bounds region — a \"created\n * layer\" of the noise-lumped {@link BoulderGeometry}. Unlike {@link scatterRocks}, which\n * rotates a single shared shape, this generates several distinct boulder geometries\n * (see `variants`) and distributes instances across them, so the field reads as unique\n * rocks while staying to a few draw calls.\n *\n * Returns a {@link Group} of {@link InstancedMesh}es (one per variant), each sharing the\n * stone material. Pass a `seed` for a reproducible field. Dispose each child's geometry\n * and the shared material when removing it.\n *\n * @example\n * ```ts\n * const boulders = scatterBoulders({ count: 24, width: 12, depth: 12, seed: 1337 });\n * scene.add(boulders);\n * ```\n */\nexport function scatterBoulders({\n count = 8,\n width = 6,\n depth = 6,\n heightJitter = 0,\n scaleMin = 0.8,\n scaleMax = 1.2,\n seed,\n radius = 1,\n detail = 2,\n noiseHeight = 0.35,\n noiseScale = 1.6,\n octaves = 3,\n persistence = 0.5,\n variants = 4,\n material,\n color = \"#6f6f6f\",\n}: ScatterBouldersOptions = {}): Group {\n const source = createRandom(seed);\n const variantCount = Math.max(1, Math.min(Math.round(variants), Math.max(1, count)));\n\n const boulderMaterial =\n material ?? new MeshStandardMaterial({ color: new Color(color), roughness: 1, metalness: 0, flatShading: true });\n\n // One distinct geometry per variant, each seeded from the scatter stream so the whole\n // field is reproducible when `seed` is given.\n const geometries: BoulderGeometry[] = [];\n for (let v = 0; v < variantCount; v++) {\n geometries.push(\n new BoulderGeometry({\n radius,\n detail,\n noiseHeight,\n noiseScale,\n octaves,\n persistence,\n seed: source.int(0, 1_000_000),\n }),\n );\n }\n\n // Round-robin instance counts across variants.\n const perVariant = new Array<number>(variantCount).fill(0);\n for (let i = 0; i < count; i++) perVariant[i % variantCount]++;\n\n const meshes = geometries.map((geometry, v) => new InstancedMesh(geometry, boulderMaterial, perVariant[v]));\n const cursors = new Array<number>(variantCount).fill(0);\n\n const matrix = new Matrix4();\n const position = new Vector3();\n const quaternion = new Quaternion();\n const scale = new Vector3();\n const rotation = new Euler();\n\n for (let i = 0; i < count; i++) {\n // Uniform scale keeps the lumped shape from stretching.\n const s = source.float(scaleMin, scaleMax);\n scale.set(s, s, s);\n rotation.set(\n source.float(0, Math.PI * 2),\n source.float(0, Math.PI * 2),\n source.float(0, Math.PI * 2),\n );\n quaternion.setFromEuler(rotation);\n position.set(\n source.float(-width / 2, width / 2),\n source.float(0, heightJitter),\n source.float(-depth / 2, depth / 2),\n );\n matrix.compose(position, quaternion, scale);\n\n const v = i % variantCount;\n meshes[v].setMatrixAt(cursors[v]++, matrix);\n }\n\n const group = new Group();\n for (const mesh of meshes) {\n mesh.instanceMatrix.needsUpdate = true;\n mesh.castShadow = true;\n mesh.receiveShadow = true;\n group.add(mesh);\n }\n return group;\n}\n","import { Shape } from \"three\";\n\nexport class HexagonShape extends Shape {\n constructor(radius = 1) {\n super();\n\n for (let i = 0; i < 6; i++) {\n const angle = (Math.PI / 3) * i; // 60-degree increments\n const x = Math.cos(angle) * radius;\n const y = Math.sin(angle) * radius;\n\n if (i === 0) this.moveTo(x, y);\n else this.lineTo(x, y);\n }\n this.closePath();\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { HexagonShape } from \"../../shapes/HexagonShape\";\n\nexport interface HexagonGeometryOptions {\n /** Hex circumradius. Defaults to `1`. */\n radius?: number;\n /** Extrusion depth. Defaults to `0.01`. */\n depth?: number;\n}\n\n/**\n * Extruded regular hexagon prism.\n */\nexport class HexagonGeometry extends ExtrudeGeometry {\n readonly radius: number;\n readonly depth: number;\n\n constructor({ radius = 1, depth = 0.01 }: HexagonGeometryOptions = {}) {\n super(new HexagonShape(radius), { depth, bevelEnabled: false });\n\n this.radius = radius;\n this.depth = depth;\n }\n}","import { InstancedMesh, Material, MeshStandardMaterial, Object3D } from \"three\";\nimport { HexagonGeometry } from \"../geometry/shapes/HexagonGeometry\";\n\nexport interface HexagonalTileCountOptions {\n width: number; // Total area width to fill (x-axis)\n depth: number; // Total area depth to fill (z-axis)\n height: number; // Height of each tile (y-axis)\n count: number; // Number of tiles along the x-axis\n gap: number; // Gap spacing between tiles\n material?: Material; // Optional custom material\n}\n\n/**\n * Hexagonal tile pattern factory with density control.\n *\n * Example usage:\n * ```ts\n * const hexTile = createHexagonalTilesByCount({\n * width: 10,\n * depth: 10,\n * height: 0.01,\n * count: 10, // 10 tiles along the x-axis\n * gap: 0.01,\n * material: new THREE.MeshStandardMaterial({ color: 0xffffff }),\n * });\n *\n * scene.add(hexTile);\n * ```\n */\nexport function createHexagonalTilesByCount(options: HexagonalTileCountOptions): InstancedMesh {\n const { width, depth, height, count, gap, material } = options;\n\n const tileMaterial = material || new MeshStandardMaterial({ color: 0xffffff });\n\n // Calculate the radius based on the x-axis count and area width\n const spacingX = width / count; // Horizontal spacing including gap\n const radius = ((spacingX - gap) * 2) / 3; // Adjusted for hexagonal geometry\n\n // Effective spacing between hexagon centers\n const effectiveSpacingZ = Math.sqrt(3) * radius + gap;\n\n // Calculate the number of tiles that fit along the z-axis\n const countZ = Math.floor(depth / effectiveSpacingZ);\n\n const hexTileCount = count * countZ;\n\n // Create a hexagonal prism geometry\n const geometry = new HexagonGeometry({ radius, depth: height });\n\n // Rotate geometry so tiles lay flat\n geometry.rotateX(-Math.PI / 2);\n\n // Create the instanced mesh\n const instancedMesh = new InstancedMesh(geometry, tileMaterial, hexTileCount);\n\n const dummy = new Object3D();\n let index = 0;\n\n for (let x = 0; x < count; x++) {\n for (let z = 0; z < countZ; z++) {\n // Calculate the staggered row offset\n const offsetX = x * spacingX;\n const offsetZ = z * effectiveSpacingZ + (x % 2) * (effectiveSpacingZ / 2); // Stagger odd rows by half a tile\n\n // Center the grid\n const positionX = offsetX - (count * spacingX) / 2 + spacingX / 2;\n const positionZ = offsetZ - (countZ * effectiveSpacingZ) / 2 + effectiveSpacingZ / 2;\n\n dummy.position.set(positionX, 0, positionZ);\n dummy.updateMatrix();\n instancedMesh.setMatrixAt(index++, dummy.matrix);\n }\n }\n\n instancedMesh.instanceMatrix.needsUpdate = true;\n\n return instancedMesh;\n}\n\nexport interface HexagonalTileRadiusOptions {\n width: number; // Total area width to fill (x-axis)\n depth: number; // Total area depth to fill (z-axis)\n height: number; // Height of each tile (y-axis)\n radius: number; // Radius of each hexagonal tile\n gap: number; // Gap spacing between tiles\n material?: Material; // Optional custom material\n}\n\n/**\n * Hexagonal tile pattern factory.\n *\n * Example usage:\n * ```ts\n * const hexTile = createHexagonalTilesByRadius({\n * width: 10,\n * depth: 10,\n * height: 0.01,\n * radius: 0.1,\n * gap: 0.01,\n * material: new THREE.MeshStandardMaterial({ color: 0xffffff }),\n * });\n *\n * scene.add(hexTile);\n * ```\n */\nexport function createHexagonalTilesByRadius(options: HexagonalTileRadiusOptions): InstancedMesh {\n const { width, depth, height, radius, gap, material } = options;\n\n const tileMaterial = material || new MeshStandardMaterial({ color: 0xffffff });\n\n // Effective spacing between hexagon centers, including the gap\n const spacingX = (radius * 3) / 2 + gap; // Horizontal distance between hex centers\n const spacingZ = Math.sqrt(3) * radius + gap; // Vertical distance between hex centers\n\n // Calculate the number of tiles that fit within the area\n const hexTileCountX = Math.floor(width / spacingX);\n const hexTileCountZ = Math.floor(depth / spacingZ);\n\n const hexTileCount = hexTileCountX * hexTileCountZ;\n\n // Create a hexagonal prism geometry\n const geometry = new HexagonGeometry({ radius, depth: height });\n\n // Rotate geometry so tiles lay flat\n geometry.rotateX(-Math.PI / 2);\n\n // Create the instanced mesh\n const instancedMesh = new InstancedMesh(geometry, tileMaterial, hexTileCount);\n\n const dummy = new Object3D();\n let index = 0;\n\n for (let x = 0; x < hexTileCountX; x++) {\n for (let z = 0; z < hexTileCountZ; z++) {\n // Calculate the staggered row offset\n const offsetX = x * spacingX;\n const offsetZ = z * spacingZ + (x % 2) * (spacingZ / 2); // Stagger odd rows by half a tile\n\n // Center the grid\n const positionX = offsetX - (hexTileCountX * spacingX) / 2 + spacingX / 2;\n const positionZ = offsetZ - (hexTileCountZ * spacingZ) / 2 + spacingZ / 2;\n\n dummy.position.set(positionX, 0, positionZ);\n dummy.updateMatrix();\n instancedMesh.setMatrixAt(index++, dummy.matrix);\n }\n }\n\n instancedMesh.instanceMatrix.needsUpdate = true;\n\n return instancedMesh;\n}\n","import { BufferGeometry, DodecahedronGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface MossyRockGeometryOptions {\n /** Rock dodecahedron radius. Defaults to `1`. */\n radius?: number;\n /** Dodecahedron detail level. Defaults to `0`. */\n detail?: number;\n /** Moss horizontal scale relative to the rock. Defaults to `0.9`. */\n mossScaleXZ?: number;\n /** Moss vertical scale relative to the rock. Defaults to `0.5`. */\n mossScaleY?: number;\n /** Moss center offset above the rock origin. Defaults to `0.3`. */\n mossOffsetY?: number;\n}\n\n/**\n * Mossy rock — dodecahedron body with a smaller, flatter moss shell (group 1).\n *\n * Material groups: `0` rock, `1` moss.\n *\n * Local frame: centered on the rock body.\n */\nexport class MossyRockGeometry extends BufferGeometry {\n readonly radius: number;\n readonly detail: number;\n\n constructor({\n radius = 1,\n detail = 0,\n mossScaleXZ = 0.9,\n mossScaleY = 0.5,\n mossOffsetY = 0.3,\n }: MossyRockGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.detail = detail;\n\n const rock = new DodecahedronGeometry(radius, detail);\n\n const moss = new DodecahedronGeometry(radius, detail);\n moss.scale(mossScaleXZ, mossScaleY, mossScaleXZ);\n moss.translate(0, mossOffsetY, 0);\n\n this.copy(mergeGeometries([rock, moss], true) as BufferGeometry);\n this.computeVertexNormals();\n }\n}","import { Axis } from \"../constants/Axis\";\nimport { BufferGeometry, Vector3 } from \"three\";\nimport { mergeVertices } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport function randomTransformVertices<T extends BufferGeometry>(geometry:T, axis = Axis.XYZ, minScale = 0.5, maxScale = 2.0) {\n // Delete unnecessary attributes\n geometry.deleteAttribute(\"uv\");\n geometry.deleteAttribute(\"normal\");\n geometry = mergeVertices(geometry) as T;\n geometry.computeVertexNormals();\n\n // Get position attribute\n const positionAttribute = geometry.getAttribute(\"position\");\n\n // Loop through each vertex\n for (let i = 0; i < positionAttribute.count; i++) {\n const vertex = new Vector3().fromBufferAttribute(positionAttribute, i);\n\n // Randomly scale the displacement along the given axis\n const randomScale = Math.random() * (maxScale - minScale) + minScale;\n const displacement = axis.clone().multiplyScalar(randomScale);\n\n // Apply the displacement to the vertex\n vertex.add(displacement);\n positionAttribute.setXYZ(i, vertex.x, vertex.y, vertex.z);\n }\n\n // Notify Three.js that the position attribute has been updated\n positionAttribute.needsUpdate = true;\n geometry.computeVertexNormals();\n\n return geometry;\n}\n","import { BufferGeometry, SphereGeometry } from \"three\";\nimport { Axis } from \"../../constants/Axis\";\nimport { randomTransformVertices } from \"../../utils/VertexUtils\";\n\nexport interface RockGeometryOptions {\n /** Base sphere radius before vertex noise. Defaults to `1`. */\n radius?: number;\n /** Horizontal segments. Defaults to `4`. */\n widthSegments?: number;\n /** Vertical segments. Defaults to `4`. */\n heightSegments?: number;\n}\n\n/**\n * Low-poly rock — sphere with randomized vertex offsets, then centered.\n */\nexport class RockGeometry extends BufferGeometry {\n readonly radius: number;\n readonly widthSegments: number;\n readonly heightSegments: number;\n\n constructor({\n radius = 1,\n widthSegments = 4,\n heightSegments = 4,\n }: RockGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.widthSegments = widthSegments;\n this.heightSegments = heightSegments;\n\n const sphere = new SphereGeometry(radius, widthSegments, heightSegments);\n this.copy(randomTransformVertices(sphere, Axis.XYZ, 0.5, 1.0));\n this.computeVertexNormals();\n this.center();\n }\n}","import {\n Color,\n ColorRepresentation,\n Euler,\n InstancedMesh,\n Material,\n Matrix4,\n MeshStandardMaterial,\n Quaternion,\n Vector3,\n} from \"three\";\nimport { MossyRockGeometry } from \"../geometry/rocks/MossyRockGeometry\";\nimport { RockGeometry } from \"../geometry/rocks/RockGeometry\";\nimport { createRandom } from \"../utils/Random\";\n\nexport interface RockScatterBounds {\n /** Scatter extent along X (centered on origin). Defaults to `4`. */\n width?: number;\n /** Scatter extent along Z (centered on origin). Defaults to `4`. */\n depth?: number;\n /** Max random Y offset above the ground plane. Defaults to `0`. */\n heightJitter?: number;\n}\n\nexport interface RockScatterPlacementOptions extends RockScatterBounds {\n /** Number of instances. Defaults to `5`. */\n count?: number;\n /** Min per-axis instance scale. Defaults to `0.8`. */\n scaleMin?: number;\n /** Max per-axis instance scale. Defaults to `1.2`. */\n scaleMax?: number;\n /** Optional seed for reproducible scatter. Omit for unique runtime. */\n seed?: number;\n}\n\nexport interface ScatterRocksOptions extends RockScatterPlacementOptions {\n /** Base sphere radius for each instance geometry. Defaults to `1`. */\n radius?: number;\n widthSegments?: number;\n heightSegments?: number;\n material?: Material;\n /** Stone tint when `material` is omitted. Defaults to `#808080`. */\n color?: ColorRepresentation;\n}\n\nexport interface ScatterMossyRocksOptions extends RockScatterPlacementOptions {\n /** Dodecahedron radius for each instance geometry. Defaults to `1`. */\n radius?: number;\n detail?: number;\n mossScaleXZ?: number;\n mossScaleY?: number;\n mossOffsetY?: number;\n rockMaterial?: Material;\n mossMaterial?: Material;\n /** Rock tint when `rockMaterial` is omitted. Defaults to `#808080`. */\n rockColor?: ColorRepresentation;\n /** Moss tint when `mossMaterial` is omitted. Defaults to `#4b8b3b`. */\n mossColor?: ColorRepresentation;\n /** Moss opacity when `mossMaterial` is omitted. Defaults to `0.8`. */\n mossOpacity?: number;\n}\n\nfunction placeInstances(\n mesh: InstancedMesh,\n {\n count = 5,\n width = 4,\n depth = 4,\n heightJitter = 0,\n scaleMin = 0.8,\n scaleMax = 1.2,\n seed,\n }: RockScatterPlacementOptions,\n): void {\n const source = createRandom(seed);\n const matrix = new Matrix4();\n const position = new Vector3();\n const quaternion = new Quaternion();\n const scale = new Vector3();\n const rotation = new Euler();\n\n for (let i = 0; i < count; i++) {\n scale.set(\n source.float(scaleMin, scaleMax),\n source.float(scaleMin, scaleMax),\n source.float(scaleMin, scaleMax),\n );\n rotation.set(source.float(0, Math.PI), source.float(0, Math.PI), source.float(0, Math.PI));\n quaternion.setFromEuler(rotation);\n position.set(\n source.float(-width / 2, width / 2),\n source.float(0, heightJitter),\n source.float(-depth / 2, depth / 2),\n );\n matrix.compose(position, quaternion, scale);\n mesh.setMatrixAt(i, matrix);\n }\n\n mesh.instanceMatrix.needsUpdate = true;\n}\n\n/**\n * Scatter instanced rocks inside a horizontal bounds region.\n *\n * @example\n * ```ts\n * const rocks = scatterRocks({ count: 12, width: 8, depth: 8, seed: 1337 });\n * scene.add(rocks);\n * ```\n */\nexport function scatterRocks({\n count = 5,\n width = 4,\n depth = 4,\n heightJitter = 0,\n scaleMin = 0.8,\n scaleMax = 1.2,\n seed,\n radius = 1,\n widthSegments = 4,\n heightSegments = 4,\n material,\n color = \"#808080\",\n}: ScatterRocksOptions = {}): InstancedMesh {\n const rockMaterial =\n material ??\n new MeshStandardMaterial({ color: new Color(color), flatShading: true });\n\n const geometry = new RockGeometry({ radius, widthSegments, heightSegments });\n const mesh = new InstancedMesh(geometry, rockMaterial, count);\n\n placeInstances(mesh, { count, width, depth, heightJitter, scaleMin, scaleMax, seed });\n return mesh;\n}\n\n/**\n * Scatter instanced mossy rocks inside a horizontal bounds region.\n *\n * Uses two material groups (rock + moss) on a shared {@link InstancedMesh}.\n */\nexport function scatterMossyRocks({\n count = 5,\n width = 4,\n depth = 4,\n heightJitter = 0,\n scaleMin = 0.8,\n scaleMax = 1.2,\n seed,\n radius = 1,\n detail = 0,\n mossScaleXZ = 0.9,\n mossScaleY = 0.5,\n mossOffsetY = 0.3,\n rockMaterial,\n mossMaterial,\n rockColor = \"#808080\",\n mossColor = \"#4b8b3b\",\n mossOpacity = 0.8,\n}: ScatterMossyRocksOptions = {}): InstancedMesh {\n const materials: Material[] = [\n rockMaterial ??\n new MeshStandardMaterial({ color: new Color(rockColor), flatShading: true }),\n mossMaterial ??\n new MeshStandardMaterial({\n color: new Color(mossColor),\n flatShading: true,\n opacity: mossOpacity,\n transparent: mossOpacity < 1,\n }),\n ];\n\n const geometry = new MossyRockGeometry({ radius, detail, mossScaleXZ, mossScaleY, mossOffsetY });\n const mesh = new InstancedMesh(geometry, materials, count);\n\n placeInstances(mesh, { count, width, depth, heightJitter, scaleMin, scaleMax, seed });\n return mesh;\n}","import { BoxGeometry, ExtrudeGeometry, Path, Shape } from \"three\";\n\n/**\n * Axis-aligned diamond lattice\n */\nexport interface DiamondLatticeGrid {\n /** Horizontal half-diagonal of each quarrel (east–west point spacing). */\n a: number;\n /** Vertical half-diagonal of each quarrel (north–south point spacing). */\n b: number;\n /**\n * Came angle from +X; the two families run at `+angle` and `−angle`.\n * Equals 45° only when `a === b`.\n */\n angle: number;\n /** Shared perpendicular spacing for both came families. */\n spacing: number;\n}\n\n/**\n * Perpendicular distance from the window center to a corner along the diamond\n * grid axis (45° families share this spacing when square).\n */\nexport function diamondLatticeCornerSpan(width: number, height: number): number {\n return (width / 2 + height / 2) / Math.SQRT2;\n}\n\n/**\n * Build an axis-aligned diamond grid from cell counts.\n *\n * `cellsX` quarrels span the width (east–west); `cellsY` span the height.\n * Equal counts on a square opening yield square diamonds; `5×10` elongates them\n * vertically while keeping north/south tips on the same vertical axis.\n */\nexport function diamondLatticeGridFromCells(\n width: number,\n height: number,\n cellsX: number,\n cellsY: number,\n): DiamondLatticeGrid {\n const cx = Math.max(1, Math.round(cellsX));\n const cy = Math.max(1, Math.round(cellsY));\n const a = width / (2 * cx);\n const b = height / (2 * cy);\n return {\n a,\n b,\n angle: Math.atan2(b, a),\n spacing: (2 * a * b) / Math.hypot(a, b),\n };\n}\n\n/**\n * Snap cell size so diagonal cames align symmetrically at all four frame edges.\n * Legacy single-spacing helper — prefer {@link diamondLatticeGridFromCells}.\n */\nexport function fitDiamondLatticeCell(width: number, height: number, preferredCell: number): number {\n const span = diamondLatticeCornerSpan(width, height);\n const count = Math.max(2, Math.round(span / preferredCell));\n return span / count;\n}\n\n/** Derive uniform cell size from center-to-corner periods. Legacy — prefer grid counts. */\nexport function diamondLatticeCellFromCount(width: number, height: number, cellsAcross: number): number {\n const span = diamondLatticeCornerSpan(width, height);\n return span / Math.max(2, cellsAcross);\n}\n\nexport interface DiamondLatticePartOptions {\n width: number;\n height: number;\n /** Center Y of the opening in local space. Defaults to `0`. */\n centerY?: number;\n grid: DiamondLatticeGrid;\n leadThickness: number;\n leadDepth: number;\n}\n\n/**\n * Build merged box geometries for the outer frame and diagonal lead cames.\n * Diagonal bars are trimmed to the rectangular opening (segment clip, not stencil).\n */\nexport function buildDiamondLatticeParts({\n width,\n height,\n centerY = 0,\n grid,\n leadThickness: barT,\n leadDepth: barD,\n}: DiamondLatticePartOptions): BoxGeometry[] {\n const hw = width / 2;\n const hh = height / 2;\n const parts: BoxGeometry[] = [\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY - hh, 0),\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY + hh, 0),\n new BoxGeometry(barT, height + barT, barD).translate(-hw, centerY, 0),\n new BoxGeometry(barT, height + barT, barD).translate(hw, centerY, 0),\n ];\n\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, grid.angle);\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, -grid.angle);\n return parts;\n}\n\n/** Diagonal cames only — no outer frame (for stencil-masked openings). */\nexport function buildDiamondLatticeCameParts(options: DiamondLatticePartOptions): BoxGeometry[] {\n const { width, height, centerY = 0, grid, leadThickness: barT, leadDepth: barD } = options;\n const parts: BoxGeometry[] = [];\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, grid.angle);\n addDiagonalFamily(parts, width, height, centerY, grid.spacing, barT, barD, -grid.angle);\n return parts;\n}\n\nfunction addDiagonalFamily(\n parts: BoxGeometry[],\n winW: number,\n winH: number,\n winY: number,\n spacing: number,\n barT: number,\n barD: number,\n angle: number,\n): void {\n const hw = winW / 2;\n const hh = winH / 2;\n const minX = -hw;\n const maxX = hw;\n const minY = winY - hh;\n const maxY = winY + hh;\n const len = Math.hypot(winW, winH) + barT;\n const perpX = -Math.sin(angle);\n const perpY = Math.cos(angle);\n const count = Math.ceil(Math.hypot(winW, winH) / spacing) + 2;\n\n for (let i = -count; i <= count; i++) {\n const cx = perpX * i * spacing;\n const cy = winY + perpY * i * spacing;\n const dx = Math.cos(angle) * len * 0.5;\n const dy = Math.sin(angle) * len * 0.5;\n const clipped = clipSegmentToAabb(cx - dx, cy - dy, cx + dx, cy + dy, minX, minY, maxX, maxY);\n if (!clipped) continue;\n\n const [x1, y1, x2, y2] = clipped;\n const clippedLen = Math.hypot(x2 - x1, y2 - y1);\n if (clippedLen < 1e-6) continue;\n\n const geo = new BoxGeometry(clippedLen, barT, barD);\n geo.rotateZ(angle);\n geo.translate((x1 + x2) / 2, (y1 + y2) / 2, 0);\n parts.push(geo);\n }\n}\n\n/** Clip a segment to an axis-aligned rectangle; returns endpoints inside the opening. */\nexport function clipSegmentToAabb(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): [number, number, number, number] | null {\n const dx = x2 - x1;\n const dy = y2 - y1;\n let tmin = 0;\n let tmax = 1;\n\n const axes: [number, number, number, number][] = [\n [x1, dx, minX, maxX],\n [y1, dy, minY, maxY],\n ];\n\n for (const [p, dp, min, max] of axes) {\n if (Math.abs(dp) < 1e-9) {\n if (p < min || p > max) return null;\n } else {\n const a = (min - p) / dp;\n const b = (max - p) / dp;\n tmin = Math.max(tmin, Math.min(a, b));\n tmax = Math.min(tmax, Math.max(a, b));\n if (tmin > tmax) return null;\n }\n }\n\n return [x1 + dx * tmin, y1 + dy * tmin, x1 + dx * tmax, y1 + dy * tmax];\n}\n\n/** Rectangular lower section plus circular arch head. */\nexport interface ArchedOpeningBounds {\n width: number;\n /** Height of the straight-sided lower section. */\n rectHeight: number;\n /** Arch rise from the spring line to the apex. Defaults to `width / 2` (semicircle). */\n archHeight?: number;\n /** Vertical center of the full opening. Defaults to `0`. */\n centerY?: number;\n}\n\nexport interface ArchedOpeningMetrics {\n hw: number;\n ymin: number;\n ymax: number;\n rectTopY: number;\n /** Circle center Y — lies on or below the spring line. */\n archCy: number;\n /** Circular arc radius derived from `width` and `archHeight`. */\n archRadius: number;\n archHeight: number;\n totalHeight: number;\n centerY: number;\n}\n\n/**\n * Circular arc through `(-width/2, springY)` and `(width/2, springY)` with rise\n * `archHeight`. Frame, glass, and lattice clip all use this same arc.\n */\nexport function archedOpeningMetrics({\n width,\n rectHeight,\n archHeight = width / 2,\n centerY = 0,\n}: ArchedOpeningBounds): ArchedOpeningMetrics {\n const rise = Math.max(archHeight, 1e-6);\n const archRadius = (width * width + 4 * rise * rise) / (8 * rise);\n const totalHeight = rectHeight + rise;\n const ymin = centerY - totalHeight / 2;\n const rectTopY = ymin + rectHeight;\n // Center sits `archRadius − rise` below the spring line (on it for a semicircle,\n // where radius === rise). Getting this sign right is what makes the apex land at\n // `rectTopY + rise` for shallow and tall arches, not just the semicircle case.\n const archCy = rectTopY + rise - archRadius;\n return {\n hw: width / 2,\n ymin,\n ymax: rectTopY + rise,\n rectTopY,\n archCy,\n archRadius,\n archHeight: rise,\n totalHeight,\n centerY,\n };\n}\n\ninterface ArchedOutlineTarget {\n moveTo(x: number, y: number): unknown;\n lineTo(x: number, y: number): unknown;\n absarc(\n x: number,\n y: number,\n radius: number,\n startAngle: number,\n endAngle: number,\n clockwise: boolean,\n ): unknown;\n closePath(): unknown;\n}\n\n/** Trace the shared rect-plus-arch outline (glass, stencil mask, frame outer edge). */\nexport function traceArchedOpeningOutline(\n target: ArchedOutlineTarget,\n metrics: ArchedOpeningMetrics,\n { hole = false }: { hole?: boolean } = {},\n): void {\n const { hw, ymin, rectTopY, archCy, archRadius } = metrics;\n const angleLeft = Math.atan2(rectTopY - archCy, -hw);\n const angleRight = Math.atan2(rectTopY - archCy, hw);\n\n if (!hole) {\n target.moveTo(-hw, ymin);\n target.lineTo(hw, ymin);\n target.lineTo(hw, rectTopY);\n // Upper bulge: right spring → left spring, counter-clockwise along the top arc.\n target.absarc(0, archCy, archRadius, angleRight, angleLeft, false);\n target.lineTo(-hw, rectTopY);\n target.closePath();\n return;\n }\n\n target.moveTo(-hw, ymin);\n target.lineTo(-hw, rectTopY);\n // Hole winds opposite the outer contour — clockwise along the inner top arc.\n target.absarc(0, archCy, archRadius, angleLeft, angleRight, true);\n target.lineTo(hw, rectTopY);\n target.lineTo(hw, ymin);\n target.closePath();\n}\n\n/** Inset opening for frame ring inner edge (uniform `inset` wall thickness). */\nexport function insetArchedOpeningMetrics(\n outer: ArchedOpeningMetrics,\n inset: number,\n): ArchedOpeningMetrics {\n const hw = Math.max(outer.hw - inset, inset);\n const ymin = outer.ymin + inset;\n const rectTopY = outer.rectTopY - inset;\n const archHeight = Math.max(outer.archHeight - inset, inset);\n const archRadius = (hw * hw + archHeight * archHeight) / (2 * archHeight);\n const archCy = rectTopY + archHeight - archRadius;\n const ymax = rectTopY + archHeight;\n return {\n hw,\n ymin,\n ymax,\n rectTopY,\n archCy,\n archRadius,\n archHeight,\n totalHeight: ymax - ymin,\n centerY: (ymin + ymax) / 2,\n };\n}\n\nconst ARCHED_SHAPE_CURVE_SEGMENTS = 48;\n\n/** Extruded frame ring following the arched opening perimeter. */\nexport function buildArchedDiamondLatticeFrameGeometry(\n metrics: ArchedOpeningMetrics,\n barThickness: number,\n barDepth: number,\n): ExtrudeGeometry {\n const outer = new Shape();\n traceArchedOpeningOutline(outer, metrics);\n\n const inner = new Path();\n traceArchedOpeningOutline(inner, insetArchedOpeningMetrics(metrics, barThickness), { hole: true });\n outer.holes.push(inner);\n\n const geo = new ExtrudeGeometry(outer, {\n depth: barDepth,\n bevelEnabled: false,\n curveSegments: ARCHED_SHAPE_CURVE_SEGMENTS,\n });\n geo.translate(0, 0, -barDepth / 2);\n return geo;\n}\n\n/** Spring-to-apex Y shift that snaps the lattice phase to the rect/arch junction. */\nexport function diamondLatticeSpringPhaseShift(\n ymin: number,\n rectTopY: number,\n grid: DiamondLatticeGrid,\n): number {\n const period = 2 * grid.b;\n const springFromYmin = rectTopY - ymin;\n const snapped = Math.round(springFromYmin / period) * period;\n return snapped - springFromYmin;\n}\n\nfunction pointInsideArchedOpening(\n x: number,\n y: number,\n { hw, ymin, ymax, rectTopY, archCy, archRadius }: ArchedOpeningMetrics,\n eps = 1e-6,\n): boolean {\n if (y < ymin - eps || y > ymax + eps) return false;\n if (y <= rectTopY + eps) return Math.abs(x) <= hw + eps;\n const dx = x;\n const dy = y - archCy;\n return dx * dx + dy * dy <= archRadius * archRadius + eps;\n}\n\nfunction collectLineParameterSplits(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n metrics: ArchedOpeningMetrics,\n): number[] {\n const ts = new Set<number>([0, 1]);\n const dx = x2 - x1;\n const dy = y2 - y1;\n const { hw, ymin, ymax, rectTopY, archCy, archRadius } = metrics;\n\n const addIfInterior = (t: number) => {\n if (t > 1e-9 && t < 1 - 1e-9) ts.add(t);\n };\n\n if (Math.abs(dx) > 1e-9) {\n addIfInterior((-hw - x1) / dx);\n addIfInterior((hw - x1) / dx);\n }\n if (Math.abs(dy) > 1e-9) {\n addIfInterior((ymin - y1) / dy);\n addIfInterior((rectTopY - y1) / dy);\n addIfInterior((ymax - y1) / dy);\n }\n\n const ax = x1;\n const ay = y1 - archCy;\n const a = dx * dx + dy * dy;\n const b = 2 * (ax * dx + ay * dy);\n const c = ax * ax + ay * ay - archRadius * archRadius;\n const disc = b * b - 4 * a * c;\n if (disc >= 0 && a > 1e-12) {\n const sqrtDisc = Math.sqrt(disc);\n addIfInterior((-b - sqrtDisc) / (2 * a));\n addIfInterior((-b + sqrtDisc) / (2 * a));\n }\n\n return [...ts].sort((left, right) => left - right);\n}\n\n/**\n * Clip a segment to a rect-plus-semicircle opening (analytic, same family as\n * {@link clipSegmentToAabb}).\n */\nexport function clipSegmentToArchedOpening(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n bounds: ArchedOpeningBounds,\n): [number, number, number, number] | null {\n const metrics = archedOpeningMetrics(bounds);\n const splits = collectLineParameterSplits(x1, y1, x2, y2, metrics);\n const dx = x2 - x1;\n const dy = y2 - y1;\n\n // The circle's lower half dips into the rectangular section, so a single line\n // can be split at a circle crossing that isn't a real boundary there. Both\n // sides stay inside, so merge adjacent interior intervals into runs and keep\n // the longest run rather than a single sub-interval (which would truncate the\n // came at the phantom crossing).\n const runs: [number, number][] = [];\n let runStart: number | null = null;\n let runEnd = 0;\n for (let i = 0; i < splits.length - 1; i++) {\n const t0 = splits[i];\n const t1 = splits[i + 1];\n const tm = (t0 + t1) * 0.5;\n const mx = x1 + dx * tm;\n const my = y1 + dy * tm;\n if (pointInsideArchedOpening(mx, my, metrics)) {\n if (runStart === null) runStart = t0;\n runEnd = t1;\n } else if (runStart !== null) {\n runs.push([runStart, runEnd]);\n runStart = null;\n }\n }\n if (runStart !== null) runs.push([runStart, runEnd]);\n\n let best: [number, number] | null = null;\n let bestLen = 0;\n for (const run of runs) {\n const len = run[1] - run[0];\n if (len > bestLen) {\n bestLen = len;\n best = run;\n }\n }\n\n if (!best || bestLen < 1e-9) return null;\n const [t0, t1] = best;\n return [x1 + dx * t0, y1 + dy * t0, x1 + dx * t1, y1 + dy * t1];\n}\n\nexport interface ArchedDiamondLatticePartOptions {\n width: number;\n rectHeight: number;\n archHeight?: number;\n centerY?: number;\n grid: DiamondLatticeGrid;\n leadThickness: number;\n leadDepth: number;\n /**\n * Shrink the opening the cames are clipped to (positioning stays on the full\n * grid). Set to the frame thickness so came ends tuck under the frame ring\n * instead of poking past the outer silhouette. Defaults to `0`.\n */\n clipInset?: number;\n}\n\n/** Recover the rect-plus-arch bounds from a metrics object (inverse of {@link archedOpeningMetrics}). */\nfunction boundsFromMetrics(m: ArchedOpeningMetrics): ArchedOpeningBounds {\n return {\n width: 2 * m.hw,\n rectHeight: m.rectTopY - m.ymin,\n archHeight: m.archHeight,\n centerY: m.centerY,\n };\n}\n\nfunction appendArchedFrameHead(\n parts: BoxGeometry[],\n metrics: ArchedOpeningMetrics,\n barT: number,\n barD: number,\n): void {\n const { hw, rectTopY, archCy, archRadius: radius } = metrics;\n const angleLeft = Math.atan2(rectTopY - archCy, -hw);\n const angleRight = Math.atan2(rectTopY - archCy, hw);\n const sweep = angleRight - angleLeft;\n const segments = Math.max(12, Math.ceil((Math.abs(sweep) * radius) / (barT * 1.8)));\n\n for (let i = 0; i < segments; i++) {\n const t0 = i / segments;\n const t1 = (i + 1) / segments;\n const a0 = angleLeft + sweep * t0;\n const a1 = angleLeft + sweep * t1;\n const mid = (a0 + a1) / 2;\n const chord = 2 * radius * Math.sin((a1 - a0) / 2);\n const geo = new BoxGeometry(chord, barT, barD);\n geo.rotateZ(mid - Math.PI / 2);\n geo.translate(radius * Math.cos(mid), archCy + radius * Math.sin(mid), 0);\n parts.push(geo);\n }\n}\n\n/**\n * Diagonal cames only, each segment analytically clipped to the rect-plus-arch\n * opening — no outer frame, no stencil. Bar ends land as real vertices on the\n * arc, so the merged geometry casts a correct shadow and matches any collider.\n */\nexport function buildArchedDiamondLatticeCameParts({\n width,\n rectHeight,\n archHeight,\n centerY = 0,\n grid,\n leadThickness: barT,\n leadDepth: barD,\n clipInset = 0,\n}: ArchedDiamondLatticePartOptions): BoxGeometry[] {\n const bounds: ArchedOpeningBounds = { width, rectHeight, archHeight, centerY };\n const metrics = archedOpeningMetrics(bounds);\n // Positioning (grid phase, line count) follows the full opening so diamonds\n // stay registered; only the clip boundary shrinks so ends land under the frame.\n const clipBounds =\n clipInset > 0 ? boundsFromMetrics(insetArchedOpeningMetrics(metrics, clipInset)) : bounds;\n const parts: BoxGeometry[] = [];\n\n const phaseShiftY = diamondLatticeSpringPhaseShift(metrics.ymin, metrics.rectTopY, grid);\n addArchedDiagonalFamily(parts, clipBounds, metrics, grid, phaseShiftY, barT, barD, grid.angle);\n addArchedDiagonalFamily(parts, clipBounds, metrics, grid, phaseShiftY, barT, barD, -grid.angle);\n return parts;\n}\n\n/** Outer frame (rect sides + circular arch head) and clipped diagonal cames. */\nexport function buildArchedDiamondLatticeParts(\n options: ArchedDiamondLatticePartOptions,\n): BoxGeometry[] {\n const { width, rectHeight, archHeight, centerY = 0, leadThickness: barT, leadDepth: barD } = options;\n const bounds: ArchedOpeningBounds = { width, rectHeight, archHeight, centerY };\n const metrics = archedOpeningMetrics(bounds);\n const { hw, ymin, rectTopY } = metrics;\n const rectSectionHeight = rectTopY - ymin;\n\n const parts: BoxGeometry[] = [\n new BoxGeometry(width + barT, barT, barD).translate(0, ymin, 0),\n new BoxGeometry(barT, rectSectionHeight + barT, barD).translate(-hw, ymin + rectSectionHeight / 2, 0),\n new BoxGeometry(barT, rectSectionHeight + barT, barD).translate(hw, ymin + rectSectionHeight / 2, 0),\n ];\n appendArchedFrameHead(parts, metrics, barT, barD);\n parts.push(...buildArchedDiamondLatticeCameParts(options));\n return parts;\n}\n\nfunction addArchedDiagonalFamily(\n parts: BoxGeometry[],\n bounds: ArchedOpeningBounds,\n metrics: ArchedOpeningMetrics,\n grid: DiamondLatticeGrid,\n phaseShiftY: number,\n barT: number,\n barD: number,\n angle: number,\n): void {\n const { totalHeight, centerY } = metrics;\n const spacing = grid.spacing;\n const len = Math.hypot(bounds.width, totalHeight) + barT;\n const perpX = -Math.sin(angle);\n const perpY = Math.cos(angle);\n const count = Math.ceil(Math.hypot(bounds.width, totalHeight) / spacing) + 2;\n const gridCenterY = centerY + phaseShiftY;\n\n for (let i = -count; i <= count; i++) {\n const cx = perpX * i * spacing;\n const cy = gridCenterY + perpY * i * spacing;\n const dx = Math.cos(angle) * len * 0.5;\n const dy = Math.sin(angle) * len * 0.5;\n const clipped = clipSegmentToArchedOpening(\n cx - dx,\n cy - dy,\n cx + dx,\n cy + dy,\n bounds,\n );\n if (!clipped) continue;\n\n const [x1, y1, x2, y2] = clipped;\n const clippedLen = Math.hypot(x2 - x1, y2 - y1);\n if (clippedLen < 1e-6) continue;\n\n const geo = new BoxGeometry(clippedLen, barT, barD);\n geo.rotateZ(angle);\n geo.translate((x1 + x2) / 2, (y1 + y2) / 2, 0);\n parts.push(geo);\n }\n}\n","import { BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport {\n archedOpeningMetrics,\n buildArchedDiamondLatticeCameParts,\n diamondLatticeGridFromCells,\n type ArchedOpeningMetrics,\n type DiamondLatticeGrid,\n} from \"./diamondLattice\";\n\nexport interface ArchedDiamondLatticeWindowGeometryOptions {\n /** Opening width (world units). */\n width?: number;\n /** Height of the straight-sided lower section. */\n rectHeight?: number;\n /** Arch rise from the spring line to the apex. Defaults to `width / 2`. */\n archHeight?: number;\n /** Lead came thickness (cross-section). Defaults to `0.055`. */\n leadThickness?: number;\n /** Lead depth (Z extent). Defaults to `0.11`. */\n leadDepth?: number;\n /** Quarrels spanning east–west across the bounding opening. Defaults to `10`. */\n cellsX?: number;\n /** Quarrels spanning north–south across the bounding opening. Defaults to `12`. */\n cellsY?: number;\n /** Vertical center of the full opening. Defaults to `0`. */\n centerY?: number;\n}\n\n/**\n * Diamond cames analytically clipped to the arched (rect-plus-Tudor-head)\n * opening — real trimmed geometry, no stencil, so it shadows and raycasts\n * correctly. Frame is a separate extruded ring on {@link ArchedDiamondLatticeWindow}.\n */\nexport class ArchedDiamondLatticeWindowGeometry extends BufferGeometry {\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n readonly opening: ArchedOpeningMetrics;\n\n constructor({\n width = 4.5,\n rectHeight = 4,\n archHeight,\n leadThickness = 0.055,\n leadDepth = 0.11,\n cellsX = 10,\n cellsY = 12,\n centerY = 0,\n }: ArchedDiamondLatticeWindowGeometryOptions = {}) {\n super();\n\n this.cellsX = Math.max(1, Math.round(cellsX));\n this.cellsY = Math.max(1, Math.round(cellsY));\n this.opening = archedOpeningMetrics({ width, rectHeight, archHeight, centerY });\n this.fittedGrid = diamondLatticeGridFromCells(\n width,\n this.opening.totalHeight,\n this.cellsX,\n this.cellsY,\n );\n\n const parts = buildArchedDiamondLatticeCameParts({\n width,\n rectHeight,\n archHeight,\n centerY,\n grid: this.fittedGrid,\n leadThickness,\n leadDepth,\n // Frame ring occupies `leadThickness` around the perimeter. End the cames\n // half a ring-width in so their tips overlap under the frame (no gap at the\n // crown) while their end-caps stay inside the outer silhouette (no spikes).\n clipInset: leadThickness * 0.5,\n });\n\n const merged = mergeGeometries(parts);\n if (!merged) throw new Error(\"ArchedDiamondLatticeWindowGeometry: merge failed\");\n\n this.copy(merged);\n merged.dispose();\n for (const part of parts) part.dispose();\n }\n}","import { BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport {\n buildDiamondLatticeParts,\n diamondLatticeGridFromCells,\n type DiamondLatticeGrid,\n} from \"./diamondLattice\";\n\nexport interface DiamondLatticeWindowGeometryOptions {\n /** Opening width (world units). */\n width?: number;\n /** Opening height (world units). */\n height?: number;\n /** Lead came thickness (cross-section). Defaults to `0.055`. */\n leadThickness?: number;\n /** Lead depth (Z extent). Defaults to `0.11`. */\n leadDepth?: number;\n /** Quarrels spanning east–west across the opening. Defaults to `10`. */\n cellsX?: number;\n /** Quarrels spanning north–south across the opening. Defaults to `10`. */\n cellsY?: number;\n /** Vertical center of the opening in local geometry space. Defaults to `0`. */\n centerY?: number;\n}\n\n/**\n * Diamond lattice window — outer frame plus diagonal cames.\n * Quarrel tips align to the vertical and horizontal axes (`<>`).\n * Built in the XY plane facing +Z.\n *\n * Glass is a separate pane on {@link DiamondLatticeWindow} — this geometry is\n * lead and frame only (casts shadow; glass typically does not).\n */\nexport class DiamondLatticeWindowGeometry extends BufferGeometry {\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n\n constructor({\n width = 4.5,\n height = 5.5,\n leadThickness = 0.055,\n leadDepth = 0.11,\n cellsX = 10,\n cellsY = 10,\n centerY = 0,\n }: DiamondLatticeWindowGeometryOptions = {}) {\n super();\n\n this.cellsX = Math.max(1, Math.round(cellsX));\n this.cellsY = Math.max(1, Math.round(cellsY));\n this.fittedGrid = diamondLatticeGridFromCells(width, height, this.cellsX, this.cellsY);\n\n const parts = buildDiamondLatticeParts({\n width,\n height,\n centerY,\n grid: this.fittedGrid,\n leadThickness,\n leadDepth,\n });\n\n const merged = mergeGeometries(parts);\n if (!merged) throw new Error(\"DiamondLatticeWindowGeometry: merge failed\");\n\n this.copy(merged);\n merged.dispose();\n for (const part of parts) part.dispose();\n }\n}","import { BoxGeometry } from \"three\";\n\n/** Pane dimensions derived from opening size and cell counts. */\nexport interface GregorianLatticeGrid {\n /** Width of each rectangular pane. */\n paneWidth: number;\n /** Height of each rectangular pane. */\n paneHeight: number;\n}\n\n/**\n * Derive pane size from cell counts.\n *\n * `cellsX` panes span the opening width; `cellsY` span the height. Mullions\n * divide the opening evenly so every segment is a full rectangle.\n */\nexport function gregorianLatticeGridFromCells(\n width: number,\n height: number,\n cellsX: number,\n cellsY: number,\n): GregorianLatticeGrid {\n const cx = Math.max(1, Math.round(cellsX));\n const cy = Math.max(1, Math.round(cellsY));\n return {\n paneWidth: width / cx,\n paneHeight: height / cy,\n };\n}\n\nexport interface GregorianLatticePartOptions {\n width: number;\n height: number;\n /** Center Y of the opening in local space. Defaults to `0`. */\n centerY?: number;\n cellsX: number;\n cellsY: number;\n mullionThickness: number;\n mullionDepth: number;\n}\n\n/**\n * Build merged box geometries for the outer frame and interior mullions.\n * Orthogonal grid — no clipping required; counts guarantee full panes.\n */\nexport function buildGregorianLatticeParts({\n width,\n height,\n centerY = 0,\n cellsX,\n cellsY,\n mullionThickness: barT,\n mullionDepth: barD,\n}: GregorianLatticePartOptions): BoxGeometry[] {\n const hw = width / 2;\n const hh = height / 2;\n const parts: BoxGeometry[] = [\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY - hh, 0),\n new BoxGeometry(width + barT, barT, barD).translate(0, centerY + hh, 0),\n new BoxGeometry(barT, height + barT, barD).translate(-hw, centerY, 0),\n new BoxGeometry(barT, height + barT, barD).translate(hw, centerY, 0),\n ];\n\n const { paneWidth, paneHeight } = gregorianLatticeGridFromCells(width, height, cellsX, cellsY);\n\n for (let col = 1; col < cellsX; col++) {\n const x = -hw + paneWidth * col;\n parts.push(new BoxGeometry(barT, height + barT, barD).translate(x, centerY, 0));\n }\n\n for (let row = 1; row < cellsY; row++) {\n const y = centerY - hh + paneHeight * row;\n parts.push(new BoxGeometry(width + barT, barT, barD).translate(0, y, 0));\n }\n\n return parts;\n}","import { BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport {\n buildGregorianLatticeParts,\n gregorianLatticeGridFromCells,\n type GregorianLatticeGrid,\n} from \"./gregorianLattice\";\n\nexport interface GregorianLatticeWindowGeometryOptions {\n /** Opening width (world units). */\n width?: number;\n /** Opening height (world units). */\n height?: number;\n /** Mullion thickness (cross-section). Defaults to `0.055`. */\n mullionThickness?: number;\n /** Mullion depth (Z extent). Defaults to `0.11`. */\n mullionDepth?: number;\n /** Rectangular panes across the opening width. Defaults to `4`. */\n cellsX?: number;\n /** Rectangular panes up the opening height. Defaults to `6`. */\n cellsY?: number;\n /** Vertical center of the opening in local geometry space. Defaults to `0`. */\n centerY?: number;\n}\n\n/**\n * Gregorian lattice window — outer frame plus orthogonal mullions in a rectangular grid.\n * Built in the XY plane facing +Z.\n */\nexport class GregorianLatticeWindowGeometry extends BufferGeometry {\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: GregorianLatticeGrid;\n\n constructor({\n width = 4.5,\n height = 5.5,\n mullionThickness = 0.055,\n mullionDepth = 0.11,\n cellsX = 4,\n cellsY = 6,\n centerY = 0,\n }: GregorianLatticeWindowGeometryOptions = {}) {\n super();\n\n this.cellsX = Math.max(1, Math.round(cellsX));\n this.cellsY = Math.max(1, Math.round(cellsY));\n this.fittedGrid = gregorianLatticeGridFromCells(width, height, this.cellsX, this.cellsY);\n\n const parts = buildGregorianLatticeParts({\n width,\n height,\n centerY,\n cellsX: this.cellsX,\n cellsY: this.cellsY,\n mullionThickness,\n mullionDepth,\n });\n\n const merged = mergeGeometries(parts);\n if (!merged) throw new Error(\"GregorianLatticeWindowGeometry: merge failed\");\n\n this.copy(merged);\n merged.dispose();\n for (const part of parts) part.dispose();\n }\n}","export type StairVec3 = [number, number, number];\nexport type StairVec2 = [number, number];\n\n/**\n * Append one quad (two triangles). Corners must be CCW when viewed along `normal`.\n */\nexport function pushQuad(\n positions: number[],\n normals: number[],\n uvs: number[],\n indices: number[],\n corners: [StairVec3, StairVec3, StairVec3, StairVec3],\n normal: StairVec3,\n cornerUvs: [StairVec2, StairVec2, StairVec2, StairVec2],\n): void {\n const base = positions.length / 3;\n for (const [x, y, z] of corners) {\n positions.push(x, y, z);\n normals.push(...normal);\n }\n for (const [u, v] of cornerUvs) uvs.push(u, v);\n indices.push(base, base + 1, base + 2, base, base + 2, base + 3);\n}\n\nexport const UNIT_QUAD_UV: [StairVec2, StairVec2, StairVec2, StairVec2] = [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n];\n\n/** Riser facing +Z at `zFront`. */\nexport function pushRiserZ(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n hw: number,\n yBottom: number,\n yTop: number,\n zFront: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [-hw, yBottom, zFront],\n [-hw, yTop, zFront],\n [hw, yTop, zFront],\n [hw, yBottom, zFront],\n ],\n [0, 0, 1],\n [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n ],\n );\n}\n\n/** Tread facing +Y between `zFront` and `zBack`. */\nexport function pushTreadZ(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n hw: number,\n yTop: number,\n zFront: number,\n zBack: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [-hw, yTop, zFront],\n [-hw, yTop, zBack],\n [hw, yTop, zBack],\n [hw, yTop, zFront],\n ],\n [0, 1, 0],\n UNIT_QUAD_UV,\n );\n}\n\n/** Riser facing +X at `xFront` (second flight climbing −X). */\nexport function pushRiserX(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n yBottom: number,\n yTop: number,\n xFront: number,\n zNear: number,\n zFar: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xFront, yBottom, zFar],\n [xFront, yBottom, zNear],\n [xFront, yTop, zNear],\n [xFront, yTop, zFar],\n ],\n [1, 0, 0],\n [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n ],\n );\n}\n\n/** Tread facing +Y between `xFront` and `xBack` (second flight climbing −X). */\nexport function pushTreadX(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n yTop: number,\n xFront: number,\n xBack: number,\n zNear: number,\n zFar: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xFront, yTop, zNear],\n [xFront, yTop, zFar],\n [xBack, yTop, zFar],\n [xBack, yTop, zNear],\n ],\n [0, 1, 0],\n UNIT_QUAD_UV,\n );\n}\n\n/** Point on the XZ circle at `angle` (radians, +Y up, 0 = +X, CCW = +Z). */\nexport function polarXZ(radius: number, angle: number): [number, number] {\n return [radius * Math.cos(angle), radius * Math.sin(angle)];\n}\n\n/** Tangent on the XZ circle at `angle`, CCW when viewed from +Y. */\nexport function tangentXZ(angle: number): [number, number, number] {\n return [-Math.sin(angle), 0, Math.cos(angle)];\n}\n\n/**\n * Spiral riser — vertical quad along one radial line at `angle`.\n * Normal faces the CCW climb direction (turret stair ascending counter-clockwise).\n */\nexport function pushSpiralRiser(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n innerRadius: number,\n outerRadius: number,\n yBottom: number,\n yTop: number,\n angle: number,\n): void {\n const [xi, zi] = polarXZ(innerRadius, angle);\n const [xo, zo] = polarXZ(outerRadius, angle);\n const normal = tangentXZ(angle);\n\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xi, yBottom, zi],\n [xi, yTop, zi],\n [xo, yTop, zo],\n [xo, yBottom, zo],\n ],\n normal,\n [\n [0, 0],\n [0, 1],\n [1, 1],\n [1, 0],\n ],\n );\n}\n\n/**\n * Spiral tread — horizontal trapezoid between inner/outer radii from `angleStart`\n * to `angleEnd` (exclusive overlap with the next step when angles are contiguous).\n */\nexport function pushSpiralTread(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n innerRadius: number,\n outerRadius: number,\n yTop: number,\n angleStart: number,\n angleEnd: number,\n): void {\n const [xIf, zIf] = polarXZ(innerRadius, angleStart);\n const [xIb, zIb] = polarXZ(innerRadius, angleEnd);\n const [xOb, zOb] = polarXZ(outerRadius, angleEnd);\n const [xOf, zOf] = polarXZ(outerRadius, angleStart);\n\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [xIf, yTop, zIf],\n [xIb, yTop, zIb],\n [xOb, yTop, zOb],\n [xOf, yTop, zOf],\n ],\n [0, 1, 0],\n [\n [0, 0],\n [1, 0],\n [1, 1],\n [0, 1],\n ],\n );\n}\n\n/** Landing platform facing +Y. */\nexport function pushLanding(\n buffers: { positions: number[]; normals: number[]; uvs: number[]; indices: number[] },\n hw: number,\n y: number,\n zNear: number,\n zFar: number,\n): void {\n pushQuad(\n buffers.positions,\n buffers.normals,\n buffers.uvs,\n buffers.indices,\n [\n [-hw, y, zNear],\n [-hw, y, zFar],\n [hw, y, zFar],\n [hw, y, zNear],\n ],\n [0, 1, 0],\n UNIT_QUAD_UV,\n );\n}","import { BufferAttribute, BufferGeometry } from \"three\";\nimport {\n pushLanding,\n pushRiserX,\n pushRiserZ,\n pushTreadX,\n pushTreadZ,\n} from \"./staircaseQuad\";\n\nexport interface LShapedStaircaseGeometryOptions {\n /** Stair width (tread left–right extent). Defaults to `2`. */\n width?: number;\n /** Vertical rise per step (riser). Defaults to `0.3`. */\n riserHeight?: number;\n /** Horizontal run per step (tread depth). Defaults to `0.5`. */\n treadDepth?: number;\n /** Steps in each flight (before and after the landing). Defaults to `5`. */\n stepsPerFlight?: number;\n}\n\n/**\n * L-shaped staircase with a square landing (width × width) at the 90° turn.\n *\n * Local frame:\n * - First flight climbs +Z, centered on X = 0.\n * - Landing is a width² platform starting at the last tread (no cantilever over\n * the lower flight) and extending forward at the turn.\n * - Second flight climbs −X from the left edge of the landing.\n */\nexport class LShapedStaircaseGeometry extends BufferGeometry {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepsPerFlight: number;\n readonly landingSize: number;\n readonly flightRun: number;\n readonly totalHeight: number;\n\n constructor({\n width = 2,\n riserHeight = 0.3,\n treadDepth = 0.5,\n stepsPerFlight = 5,\n }: LShapedStaircaseGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.riserHeight = riserHeight;\n this.treadDepth = treadDepth;\n this.stepsPerFlight = Math.max(1, Math.round(stepsPerFlight));\n this.landingSize = width;\n this.flightRun = this.stepsPerFlight * this.treadDepth;\n this.totalHeight = this.stepsPerFlight * 2 * this.riserHeight;\n\n const hw = width / 2;\n const positions: number[] = [];\n const normals: number[] = [];\n const uvs: number[] = [];\n const indices: number[] = [];\n const buffers = { positions, normals, uvs, indices };\n\n for (let i = 0; i < this.stepsPerFlight; i++) {\n const yBottom = i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n const zFront = i * this.treadDepth;\n const zBack = zFront + this.treadDepth;\n\n pushRiserZ(buffers, hw, yBottom, yTop, zFront);\n pushTreadZ(buffers, hw, yTop, zFront, zBack);\n }\n\n const landingY = this.stepsPerFlight * this.riserHeight;\n // Begin at the front of the last tread — avoids a shelf over the lower flight.\n const landingZNear = (this.stepsPerFlight - 1) * this.treadDepth;\n const landingZFar = landingZNear + this.landingSize;\n\n pushLanding(buffers, hw, landingY, landingZNear, landingZFar);\n\n const leftEdgeX = -hw;\n for (let i = 0; i < this.stepsPerFlight; i++) {\n const yBottom = landingY + i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n const xFront = leftEdgeX - i * this.treadDepth;\n const xBack = xFront - this.treadDepth;\n\n pushRiserX(buffers, yBottom, yTop, xFront, landingZNear, landingZFar);\n pushTreadX(buffers, yTop, xFront, xBack, landingZNear, landingZFar);\n }\n\n this.setIndex(indices);\n this.setAttribute(\"position\", new BufferAttribute(new Float32Array(positions), 3));\n this.setAttribute(\"normal\", new BufferAttribute(new Float32Array(normals), 3));\n this.setAttribute(\"uv\", new BufferAttribute(new Float32Array(uvs), 2));\n this.computeBoundingSphere();\n }\n}","import { BufferAttribute, BufferGeometry } from \"three\";\nimport { pushSpiralRiser, pushSpiralTread } from \"./staircaseQuad\";\n\nexport interface SpiralStaircaseGeometryOptions {\n /** Newel / center-hole radius (inner edge of every tread). Defaults to `0.45`. */\n innerRadius?: number;\n /** Radial tread width (outer − inner radius). Defaults to `1.95`. */\n width?: number;\n /** Arc run per step at the walking line (mid-radius). Defaults to `0.45`. */\n treadDepth?: number;\n /** Vertical rise per step (riser). Defaults to `0.2`. */\n riserHeight?: number;\n /** Number of steps. Defaults to `20`. */\n stepCount?: number;\n /** Spiral start angle in radians (+X = 0, CCW). Defaults to `0`. */\n startAngle?: number;\n /** Override step angle (radians). When omitted, derived from `treadDepth`. */\n stepAngle?: number;\n}\n\n/**\n * Turret-style spiral staircase — trapezoidal treads between an inner newel radius\n * and an outer wall radius, ascending counter-clockwise when viewed from above.\n *\n * Each step is a four-sided tread (no pinched center point). Step angle is\n * derived from tread depth at the mid-radius so treads meet without overlapping.\n */\nexport class SpiralStaircaseGeometry extends BufferGeometry {\n readonly innerRadius: number;\n readonly width: number;\n readonly outerRadius: number;\n readonly treadDepth: number;\n readonly riserHeight: number;\n readonly stepCount: number;\n readonly startAngle: number;\n readonly stepAngle: number;\n readonly totalHeight: number;\n readonly totalTurn: number;\n\n constructor({\n innerRadius = 0.45,\n width = 1.95,\n treadDepth = 0.45,\n riserHeight = 0.2,\n stepCount = 20,\n startAngle = 0,\n stepAngle: stepAngleOption,\n }: SpiralStaircaseGeometryOptions = {}) {\n super();\n\n this.innerRadius = Math.max(0.01, innerRadius);\n this.width = Math.max(0.05, width);\n this.outerRadius = this.innerRadius + this.width;\n this.treadDepth = treadDepth;\n this.riserHeight = riserHeight;\n this.stepCount = Math.max(1, Math.round(stepCount));\n this.startAngle = startAngle;\n\n const walkRadius = (this.innerRadius + this.outerRadius) * 0.5;\n this.stepAngle =\n stepAngleOption ?? Math.max(treadDepth / walkRadius, Math.PI / 180);\n this.totalHeight = this.stepCount * this.riserHeight;\n this.totalTurn = this.stepCount * this.stepAngle;\n\n const positions: number[] = [];\n const normals: number[] = [];\n const uvs: number[] = [];\n const indices: number[] = [];\n const buffers = { positions, normals, uvs, indices };\n\n for (let i = 0; i < this.stepCount; i++) {\n const angleStart = this.startAngle + i * this.stepAngle;\n const angleEnd = angleStart + this.stepAngle;\n const yBottom = i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n\n pushSpiralRiser(buffers, this.innerRadius, this.outerRadius, yBottom, yTop, angleStart);\n pushSpiralTread(buffers, this.innerRadius, this.outerRadius, yTop, angleStart, angleEnd);\n }\n\n this.setIndex(indices);\n this.setAttribute(\"position\", new BufferAttribute(new Float32Array(positions), 3));\n this.setAttribute(\"normal\", new BufferAttribute(new Float32Array(normals), 3));\n this.setAttribute(\"uv\", new BufferAttribute(new Float32Array(uvs), 2));\n this.computeBoundingSphere();\n }\n}","import { BufferAttribute, BufferGeometry } from \"three\";\nimport { pushRiserZ, pushTreadZ } from \"./staircaseQuad\";\n\nexport interface StaircaseGeometryOptions {\n /** Stair width (tread left–right extent). Defaults to `2`. */\n width?: number;\n /** Vertical rise per step (riser). Defaults to `0.3`. */\n riserHeight?: number;\n /** Horizontal run per step (tread depth). Defaults to `0.5`. */\n treadDepth?: number;\n /** Number of steps. Defaults to `10`. */\n stepCount?: number;\n}\n\n/**\n * Straight run staircase — open risers and treads (no side stringers yet).\n *\n * Local frame: centered on width, rises along +Y, runs along +Z. Each step\n * emits a front riser (+Z) and a top tread (+Y). UVs are normalized per face\n * (0–1) so materials can tile per step.\n */\nexport class StaircaseGeometry extends BufferGeometry {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepCount: number;\n readonly totalHeight: number;\n readonly totalDepth: number;\n\n constructor({\n width = 2,\n riserHeight = 0.3,\n treadDepth = 0.5,\n stepCount = 10,\n }: StaircaseGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.riserHeight = riserHeight;\n this.treadDepth = treadDepth;\n this.stepCount = Math.max(1, Math.round(stepCount));\n this.totalHeight = this.stepCount * this.riserHeight;\n this.totalDepth = this.stepCount * this.treadDepth;\n\n const hw = width / 2;\n const positions: number[] = [];\n const normals: number[] = [];\n const uvs: number[] = [];\n const indices: number[] = [];\n const buffers = { positions, normals, uvs, indices };\n\n for (let i = 0; i < this.stepCount; i++) {\n const yBottom = i * this.riserHeight;\n const yTop = yBottom + this.riserHeight;\n const zFront = i * this.treadDepth;\n const zBack = zFront + this.treadDepth;\n\n pushRiserZ(buffers, hw, yBottom, yTop, zFront);\n pushTreadZ(buffers, hw, yTop, zFront, zBack);\n }\n\n this.setIndex(indices);\n this.setAttribute(\"position\", new BufferAttribute(new Float32Array(positions), 3));\n this.setAttribute(\"normal\", new BufferAttribute(new Float32Array(normals), 3));\n this.setAttribute(\"uv\", new BufferAttribute(new Float32Array(uvs), 2));\n this.computeBoundingSphere();\n }\n}","import { BufferGeometry, CylinderGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Group indices\n * 0. Jar\n * 1. Cork\n */\nexport class JarGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Jar\n const points = [\n new Vector2(0, 0), // Bottom of the jar\n new Vector2(1.2, 0), // Base\n new Vector2(1.5, 1.5), // Mid-body\n new Vector2(1, 3), // Narrow neck\n new Vector2(0.6, 3.5), // Mouth of the jar\n new Vector2(0.5, 3.5), // Cork\n ];\n\n const bodyGeometry = new LatheGeometry(points, 10);\n\n // Cork\n const corkGeometry = new CylinderGeometry(0.6, 0.5, 0.3, 10);\n corkGeometry.translate(0, 3.5, 0);\n\n this.copy(mergeGeometries([bodyGeometry, corkGeometry], true) as BufferGeometry);\n }\n}\n","/**\n * Calculate the x-coordinate for a given y-coordinate using the slope-intercept equation of a line.\n * x = x1 + (y - y1) / m\n *\n * Example usage\n * ```\n * const x1 = 0.8, y1 = 0, x2 = 1, y2 = 1.5, y = 1.0;\n * const x = calculateXForY(x1, y1, x2, y2, y);\n * console.log(`The x-position for y=${y} is x=${x.toFixed(4)}`);\n * ```\n */\nexport function calculateXFromSlopeIntercept(x1: number, y1: number, x2: number, y2: number, y: number): number {\n const m = (y2 - y1) / (x2 - x1); // slope\n return x1 + (y - y1) / m;\n}\n\n/**\n * Calculate the y-coordinate for a given x-coordinate using the slope-intercept equation of a line.\n * y = y1 + m * (x - x1)\n *\n * Example usage\n * ```\n * const x1 = 0.8, y1 = 0, x2 = 1, y2 = 1.5, x = 0.9333;\n * const y = calculateYForX(x1, y1, x2, y2, x);\n * console.log(`The y-position for x=${x} is y=${y.toFixed(4)}`);\n * ```\n */\nexport function calculateYFromSlopeIntercept(x1: number, y1: number, x2: number, y2: number, x: number): number {\n const m = (y2 - y1) / (x2 - x1); // slope\n return y1 + m * (x - x1);\n}\n\nexport const LineEquations = {\n calculateXFromSlopeIntercept,\n calculateYFromSlopeIntercept,\n};\n","import { BufferGeometry, CylinderGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { calculateXFromSlopeIntercept } from \"../../utils/LineEquations\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Potion bottle geometry\n *\n * Group indices\n * 0. Bottle\n * 1. Cork\n * 2. Liquid (optional)\n */\nexport class PotionBottleGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Bottle\n const points = [\n new Vector2(0, 0), // Origin\n new Vector2(0.8, 0), // Base\n new Vector2(1, 1.5), // Rounded body\n new Vector2(0.5, 2.2), // Neck\n new Vector2(0.6, 2.5), // Mouth\n new Vector2(0.5, 2.5), // Cork\n ];\n\n const bottleGeometry = new LatheGeometry(points, 10);\n\n // Cork\n const corkGeometry = new CylinderGeometry(0.55, 0.45, 0.2, 10);\n corkGeometry.translate(0, 2.5, 0);\n\n // Liquid (optional)\n const liquidPoints = [\n new Vector2(0, 0),\n new Vector2(0.8, 0),\n new Vector2(calculateXFromSlopeIntercept(0.8, 0, 1, 1.5, 1.0), 1.0),\n new Vector2(0, 1.0),\n ];\n\n const liquidGeometry = new LatheGeometry(liquidPoints, 10);\n liquidGeometry.translate(0, 0.1, 0);\n liquidGeometry.scale(0.9, 0.9, 0.9);\n\n this.copy(mergeGeometries([bottleGeometry, corkGeometry, liquidGeometry], true) as BufferGeometry);\n }\n}\n","import { BufferGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface WineBottleGeometryOptions {\n /** Body radius. Defaults to `0.5`. */\n radius?: number;\n /** Neck radius. Defaults to `0.2`. */\n neckRadius?: number;\n /** Total height including neck. Defaults to `3`. */\n height?: number;\n /** Neck height. Defaults to `1`. */\n neckHeight?: number;\n /** Circumference segments. Defaults to `16`. */\n segments?: number;\n}\n\n/**\n * Wine bottle — cylindrical body, shoulder taper, and neck.\n *\n * Local frame: base at Y=0.\n */\nexport class WineBottleGeometry extends BufferGeometry {\n readonly radius: number;\n readonly height: number;\n\n constructor({\n radius = 0.5,\n neckRadius = 0.2,\n height = 3,\n neckHeight = 1,\n segments = 16,\n }: WineBottleGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.height = height;\n\n const bodyHeight = height - neckHeight;\n const bodyGeometry = new CylinderGeometry(radius, radius, bodyHeight, segments);\n bodyGeometry.translate(0, bodyHeight / 2, 0);\n\n const shoulderHeight = 0.3;\n const shoulderGeometry = new CylinderGeometry(neckRadius, radius, shoulderHeight, segments);\n shoulderGeometry.translate(0, bodyHeight + shoulderHeight / 2, 0);\n\n const neckGeometry = new CylinderGeometry(neckRadius, neckRadius, neckHeight, segments);\n neckGeometry.translate(0, bodyHeight + shoulderHeight + neckHeight / 2, 0);\n\n this.copy(mergeGeometries([bodyGeometry, shoulderGeometry, neckGeometry], false) as BufferGeometry);\n }\n}","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface CrossHeadstoneGeometryOptions {\n /** Overall cross width (arm span). Defaults to `0.4`. */\n width?: number;\n /** Total height. Defaults to `1.2`. */\n height?: number;\n /** Slab depth. Defaults to `0.2`. */\n depth?: number;\n}\n\n/**\n * Cross headstone — vertical shaft and horizontal arm.\n *\n * Local frame: base on Y=0, centered on X/Z.\n */\nexport class CrossHeadstoneGeometry extends BufferGeometry {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n\n constructor({ width = 0.4, height = 1.2, depth = 0.2 }: CrossHeadstoneGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n\n const verticalHeight = height * 0.6;\n const verticalGeometry = new BoxGeometry(width / 2, verticalHeight, depth);\n verticalGeometry.translate(0, verticalHeight / 2, 0);\n\n const horizontalWidth = width * 1.5;\n const horizontalGeometry = new BoxGeometry(horizontalWidth, width / 4, depth);\n horizontalGeometry.translate(0, verticalHeight * 0.75, 0);\n\n this.copy(mergeGeometries([verticalGeometry, horizontalGeometry], false) as BufferGeometry);\n this.computeVertexNormals();\n }\n}","import { BoxGeometry, BufferGeometry, ConeGeometry, CylinderGeometry, ExtrudeGeometry, Shape } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Mausoleum Geometry\n *\n * Group indices:\n * 0. Base\n * 1. Building\n * 2. Roof\n * 3. Arched entrance\n */\nexport class MausoleumGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Base of the Mausoleum\n const baseGeometry = new BoxGeometry(5, 1, 5);\n baseGeometry.translate(0, 0.5, 0);\n\n // Main Building Structure\n const buildingGeometry = new BoxGeometry(4, 3, 4);\n buildingGeometry.translate(0, 2.5, 0);\n\n // Pillars\n const pillarPositions = [\n [-1.8, 2.3, -2.2],\n [1.8, 2.3, -2.2],\n [-1.8, 2.3, 2.2],\n [1.8, 2.3, 2.2],\n ];\n\n const pillars: BufferGeometry[] = [];\n pillarPositions.forEach((position) => {\n const pillar = new CylinderGeometry(0.2, 0.2, 3.5, 16);\n pillar.translate(position[0], position[1], position[2]);\n pillars.push(pillar);\n });\n\n // Roof (Peaked)\n const roofGeometry = new ConeGeometry(3.5, 2, 4);\n roofGeometry.rotateY(Math.PI / 4);\n roofGeometry.translate(0, 5, 0);\n\n // Arched Entrance\n const archShape = new Shape();\n archShape.moveTo(-1, 0);\n archShape.lineTo(-1, 2);\n archShape.absarc(0, 2, 1, Math.PI, 0, true);\n archShape.lineTo(1, 0);\n\n const extrudeSettings = {\n depth: 0.5,\n bevelEnabled: false,\n };\n const archGeometry = new ExtrudeGeometry(archShape, extrudeSettings);\n archGeometry.translate(0, 0.5, 1.7);\n archGeometry.setIndex([...Array(archGeometry.attributes.position.count).keys()]);\n\n this.copy(\n mergeGeometries(\n [\n baseGeometry,\n mergeGeometries([buildingGeometry, ...pillars], false) as BufferGeometry,\n roofGeometry,\n archGeometry,\n ],\n true,\n ) as BufferGeometry,\n );\n this.computeVertexNormals();\n }\n}\n","import { BoxGeometry, BufferGeometry, ConeGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface ObeliskHeadstoneGeometryOptions {\n /** Total monument height. Defaults to `1.75`. */\n totalHeight?: number;\n /** Base platform width. Defaults to `0.75`. */\n baseWidth?: number;\n}\n\n/**\n * Tiered obelisk headstone with pyramid cap.\n *\n * Local frame: base on Y=0, centered on X/Z.\n */\nexport class ObeliskHeadstoneGeometry extends BufferGeometry {\n readonly totalHeight: number;\n readonly baseWidth: number;\n\n constructor({ totalHeight = 1.75, baseWidth = 0.75 }: ObeliskHeadstoneGeometryOptions = {}) {\n super();\n\n this.totalHeight = totalHeight;\n this.baseWidth = baseWidth;\n\n const baseHeight = totalHeight * 0.05;\n const lowerSegmentHeight = totalHeight * 0.15;\n const middleSegmentHeight = totalHeight * 0.15;\n const topSegmentHeight = totalHeight * 0.75;\n\n let currentHeight = 0;\n\n const baseGeometry = new BoxGeometry(baseWidth, baseHeight, baseWidth);\n baseGeometry.translate(0, currentHeight + baseHeight / 2, 0);\n currentHeight += baseHeight;\n\n const lowerSegmentGeometry = new BoxGeometry(baseWidth * 0.8, lowerSegmentHeight, baseWidth * 0.8);\n lowerSegmentGeometry.translate(0, currentHeight + lowerSegmentHeight / 2, 0);\n currentHeight += lowerSegmentHeight;\n\n const middleSegmentGeometry = new BoxGeometry(baseWidth * 0.6, middleSegmentHeight, baseWidth * 0.6);\n middleSegmentGeometry.translate(0, currentHeight + middleSegmentHeight / 2, 0);\n currentHeight += middleSegmentHeight;\n\n const topSegmentGeometry = new BoxGeometry(baseWidth * 0.4, topSegmentHeight, baseWidth * 0.4);\n topSegmentGeometry.translate(0, currentHeight + topSegmentHeight / 2, 0);\n currentHeight += topSegmentHeight;\n\n const pyramidGeometry = new ConeGeometry((baseWidth * 0.4) / Math.sqrt(2), 0.1, 4, 1, false, Math.PI / 4);\n pyramidGeometry.translate(0, currentHeight + 0.1 / 2, 0);\n\n this.copy(\n mergeGeometries(\n [baseGeometry, lowerSegmentGeometry, middleSegmentGeometry, topSegmentGeometry, pyramidGeometry],\n false,\n ) as BufferGeometry,\n );\n this.computeVertexNormals();\n }\n}","import { BoxGeometry, BufferGeometry, CylinderGeometry } from \"three\";\nimport {mergeGeometries} from \"three/addons/utils/BufferGeometryUtils.js\";\n\nclass RoundedHeadstoneGeometry extends BufferGeometry {\n constructor(width = 0.6, height = 1.0, depth = 0.2, radius = 0.6) {\n super();\n\n // Create the base of the headstone (a box)\n const baseHeight = height - radius / 2;\n const baseGeometry = new BoxGeometry(width, baseHeight, depth);\n baseGeometry.translate(0, baseHeight / 2, 0);\n\n // Create the rounded top part (a half cylinder with caps)\n const topGeometry = new CylinderGeometry(radius / 2, radius / 2, depth, 16, 1, false, 0, Math.PI);\n topGeometry.rotateY(Math.PI / 2);\n topGeometry.rotateX(Math.PI / 2);\n topGeometry.translate(0, baseHeight, 0);\n\n // Merge base and top into a single geometry\n this.copy(mergeGeometries([baseGeometry, topGeometry], false) as BufferGeometry);\n this.computeVertexNormals();\n }\n}\n\nexport { RoundedHeadstoneGeometry };\n","import { BoxGeometry, BufferGeometry } from \"three\";\n\nexport class SquareHeadstoneGeometry extends BufferGeometry {\n constructor(width = 0.5, height = 0.8, depth = 0.15) {\n super();\n\n // Create a rectangular slab\n const slabGeometry = new BoxGeometry(width, height, depth);\n slabGeometry.translate(0, height / 2, 0);\n\n this.copy(slabGeometry);\n }\n}\n","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface StoneFencePostGeometryOptions {\n /** Main column height (excluding base and cap). Defaults to `2.25`. */\n height?: number;\n}\n\n/**\n * Stone fence post — wide base, column, and cap.\n *\n * Local frame: base on Y=0.\n */\nexport class StoneFencePostGeometry extends BufferGeometry {\n readonly height: number;\n\n constructor({ height = 2.25 }: StoneFencePostGeometryOptions = {}) {\n super();\n\n this.height = height;\n\n const baseGeometry = new BoxGeometry(1.2, 0.5, 1.2);\n baseGeometry.translate(0, 0.25, 0);\n\n const columnGeometry = new BoxGeometry(1, height, 1);\n columnGeometry.translate(0, 0.5 + height / 2, 0);\n\n const capGeometry = new BoxGeometry(1.4, 0.3, 1.4);\n capGeometry.translate(0, 0.5 + height + 0.15, 0);\n\n this.copy(mergeGeometries([baseGeometry, columnGeometry, capGeometry], false) as BufferGeometry);\n }\n}","import { BufferGeometry, ConeGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface WroughtIronBarGeometryOptions {\n /** Vertical bar height. Defaults to `2`. */\n barHeight?: number;\n /** Bar cylinder radius. Defaults to `0.05`. */\n barRadius?: number;\n /** Spike cone height. Defaults to `0.3`. */\n spikeHeight?: number;\n /** Spike base radius. Defaults to `0.075`. */\n spikeRadius?: number;\n /** Spike depth scale on Z. Defaults to `1`. */\n spikeScaleZ?: number;\n /** Circumference segments. Defaults to `8`. */\n radialSegments?: number;\n}\n\n/**\n * Wrought-iron fence post — cylinder bar with a decorative spike.\n *\n * Local frame: base at Y=0.\n */\nexport class WroughtIronBarGeometry extends BufferGeometry {\n readonly barHeight: number;\n\n constructor({\n barHeight = 2.0,\n barRadius = 0.05,\n spikeHeight = 0.3,\n spikeRadius = 0.075,\n spikeScaleZ = 1.0,\n radialSegments = 8,\n }: WroughtIronBarGeometryOptions = {}) {\n super();\n\n this.barHeight = barHeight;\n\n const barGeometry = new CylinderGeometry(barRadius, barRadius, barHeight, radialSegments);\n barGeometry.translate(0, barHeight / 2, 0);\n\n const spikeGeometry = new ConeGeometry(spikeRadius, spikeHeight, radialSegments);\n spikeGeometry.translate(0, barHeight + spikeHeight / 2, 0);\n spikeGeometry.scale(1, 1, spikeScaleZ);\n\n this.copy(mergeGeometries([barGeometry, spikeGeometry], false) as BufferGeometry);\n }\n}","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport { WroughtIronBarGeometry } from \"./WroughtIronBarGeometry\";\n\nexport interface WroughtIronFenceGeometryOptions {\n /** Number of posts. Defaults to `20`. */\n count?: number;\n /** Center-to-center post spacing. Defaults to `0.4`. */\n spacing?: number;\n /** Post bar height. Defaults to `2`. */\n barHeight?: number;\n /** Post bar radius. Defaults to `0.05`. */\n barRadius?: number;\n /** Post spike height. Defaults to `0.3`. */\n spikeHeight?: number;\n /** Post spike radius. Defaults to `0.075`. */\n spikeRadius?: number;\n /** Post spike Z scale. Defaults to `1`. */\n spikeScaleZ?: number;\n /** Horizontal rail thickness. Defaults to `0.1`. */\n railHeight?: number;\n /** Horizontal rail depth. Defaults to `0.05`. */\n railDepth?: number;\n /** Top rail offset below the spike tip. Defaults to `0`. */\n railOffset?: number;\n /** Post circumference segments. Defaults to `8`. */\n radialSegments?: number;\n}\n\n/**\n * Wrought-iron fence run — repeated posts with top and bottom rails.\n *\n * Local frame: first post at the origin, extending along +X.\n */\nexport class WroughtIronFenceGeometry extends BufferGeometry {\n readonly count: number;\n readonly spacing: number;\n\n constructor({\n count = 20,\n spacing = 0.4,\n barHeight = 2.0,\n barRadius = 0.05,\n spikeHeight = 0.3,\n spikeRadius = 0.075,\n spikeScaleZ = 1.0,\n railHeight = 0.1,\n railDepth = 0.05,\n railOffset = 0.0,\n radialSegments = 8,\n }: WroughtIronFenceGeometryOptions = {}) {\n super();\n\n this.count = count;\n this.spacing = spacing;\n\n const geometries = [];\n const bar = new WroughtIronBarGeometry({\n barHeight,\n barRadius,\n spikeHeight,\n spikeRadius,\n spikeScaleZ,\n radialSegments,\n });\n const rail = new BoxGeometry(count * spacing, railHeight, railDepth);\n\n for (let i = 0; i < count; i++) {\n const geometry = bar.clone();\n geometry.translate(i * spacing, 0, 0);\n geometries.push(geometry);\n }\n\n const topRail = rail.clone();\n topRail.translate((spacing * (count - 1)) / 2, barHeight - railOffset - railHeight / 2, 0);\n geometries.push(topRail);\n\n const bottomRail = rail.clone();\n bottomRail.translate((spacing * (count - 1)) / 2, railHeight / 2, 0);\n geometries.push(bottomRail);\n\n this.copy(mergeGeometries(geometries) as BufferGeometry);\n }\n}","import { BoxGeometry, BufferGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface BookshelfGeometryOptions {\n /** Overall width. Defaults to `5`. */\n width?: number;\n /** Overall height. Defaults to `8`. */\n height?: number;\n /** Shelf depth. Defaults to `1`. */\n depth?: number;\n /** Number of interior shelves. Defaults to `4`. */\n shelves?: number;\n /** Frame board thickness. Defaults to `0.1`. */\n frameThickness?: number;\n /** Omit the back panel when `true`. Defaults to `false`. */\n open?: boolean;\n}\n\n/**\n * Bookshelf frame with optional back panel and evenly spaced shelves.\n *\n * Local frame: sits on the Y=0 plane, centered on X/Z.\n */\nexport class BookshelfGeometry extends BufferGeometry {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n readonly shelves: number;\n\n constructor({\n width = 5,\n height = 8,\n depth = 1,\n shelves = 4,\n frameThickness = 0.1,\n open = false,\n }: BookshelfGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.height = height;\n this.depth = depth;\n this.shelves = shelves;\n\n const sidePanelGeometry = new BoxGeometry(frameThickness, height, depth);\n const shelfGeometry = new BoxGeometry(width - 2 * frameThickness, frameThickness, depth);\n\n const leftPanel = sidePanelGeometry.clone();\n leftPanel.translate(-width / 2 + frameThickness / 2, height / 2, 0);\n\n const rightPanel = sidePanelGeometry.clone();\n rightPanel.translate(width / 2 - frameThickness / 2, height / 2, 0);\n\n const topPanel = shelfGeometry.clone();\n topPanel.translate(0, height - frameThickness / 2, 0);\n\n const bottomPanel = shelfGeometry.clone();\n bottomPanel.translate(0, frameThickness / 2, 0);\n\n const backPanel = new BoxGeometry(width, height, frameThickness);\n backPanel.translate(0, height / 2, -depth / 2 + frameThickness / 2);\n\n const shelfPanels = [];\n const shelfSpacing = (height - frameThickness) / (shelves + 1);\n for (let i = 1; i <= shelves; i++) {\n const shelfPanel = shelfGeometry.clone();\n shelfPanel.translate(0, frameThickness / 2 + i * shelfSpacing, 0);\n shelfPanels.push(shelfPanel);\n }\n\n this.copy(\n mergeGeometries(\n [leftPanel, rightPanel, topPanel, bottomPanel, ...(open ? [] : [backPanel]), ...shelfPanels],\n false,\n ) as BufferGeometry,\n );\n }\n}","import { BoxGeometry, BufferGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Group indices:\n * 0. Desk surface\n * 1. Desk legs\n */\nexport class DeskGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Desk Surface\n const surfaceGeometry = new BoxGeometry(5, 0.3, 3);\n surfaceGeometry.translate(0, 3.15, 0);\n\n // Desk Legs (using lathe geometry)\n const points = [\n new Vector2(0.2, 0), //\n new Vector2(0.25, 0.5),\n new Vector2(0.15, 1.5),\n new Vector2(0.3, 3),\n ];\n\n const legLatheGeometry = new LatheGeometry(points, 32);\n\n // Create four legs for the desk\n const legPositions = [\n [2.1, 0, 1.1],\n [-2.1, 0, 1.1],\n [2.1, 0, -1.1],\n [-2.1, 0, -1.1],\n ];\n\n const legGeometry = mergeGeometries(\n legPositions.map((position) => {\n const leg = legLatheGeometry.clone();\n leg.translate(position[0], position[1], position[2]);\n return leg;\n }),\n ) as BufferGeometry;\n\n this.copy(mergeGeometries([surfaceGeometry, legGeometry], true) as BufferGeometry);\n }\n}\n","import { BufferGeometry, Float32BufferAttribute } from \"three\";\n\nexport interface LeafGeometryOptions {\n /** Overall leaf scale. Defaults to `0.13`. */\n size?: number;\n /** Midrib rise above the rim as a fraction of size. Defaults to `0.22`. */\n lift?: number;\n}\n\n/**\n * Low-poly folded leaf — a pointed ellipse with a gently raised midrib so it\n * catches rim light instead of reading as a flat sliver. Spine vertices sit\n * slightly above the mirrored rim outline, giving a soft V cross-section under\n * flat shading.\n *\n * Local frame: tip at +Y, base at −Y, fold rises along +Z.\n */\nexport class LeafGeometry extends BufferGeometry {\n readonly size: number;\n readonly lift: number;\n\n constructor({ size = 0.13, lift = 0.22 }: LeafGeometryOptions = {}) {\n super();\n\n this.size = size;\n this.lift = lift;\n\n // Outline pairs (rim) running tip → base down each side, plus a raised spine.\n const half: [number, number][] = [\n [0.0, 1.0],\n [0.34, 0.55],\n [0.42, 0.05],\n [0.3, -0.45],\n [0.0, -1.0],\n ];\n\n const verts: number[] = [];\n const idx: number[] = [];\n\n const spine: number[] = [];\n for (let i = 0; i < half.length; i++) {\n const [, y] = half[i];\n spine.push(verts.length / 3);\n verts.push(0, y * size, lift * size * (1 - Math.abs(y)));\n }\n\n const left: number[] = [];\n const right: number[] = [];\n for (let i = 0; i < half.length; i++) {\n const [x, y] = half[i];\n right.push(verts.length / 3);\n verts.push(x * size, y * size, 0);\n left.push(verts.length / 3);\n verts.push(-x * size, y * size, 0);\n }\n\n for (let i = 0; i < half.length - 1; i++) {\n idx.push(spine[i], right[i], right[i + 1], spine[i], right[i + 1], spine[i + 1]);\n idx.push(spine[i], spine[i + 1], left[i + 1], spine[i], left[i + 1], left[i]);\n }\n\n this.setAttribute(\"position\", new Float32BufferAttribute(verts, 3));\n this.setIndex(idx);\n this.computeVertexNormals();\n this.computeBoundingSphere();\n }\n}","import { ParametricGeometry } from \"three/addons/geometries/ParametricGeometry.js\";\nimport { Vector3 } from \"three\";\n\nexport interface FlameGeometryOptions {\n /** Flame tip height. Defaults to `0.25`. */\n height?: number;\n /** Base radius at the widest point. Defaults to `0.05`. */\n radius?: number;\n /** Parametric segments around the circumference. Defaults to `16`. */\n segmentsU?: number;\n /** Parametric segments along the height. Defaults to `16`. */\n segmentsV?: number;\n}\n\n/**\n * Teardrop flame volume — parametric surface tapering to a point at the top.\n *\n * Local frame: base at Y=0, tip at Y=`height`.\n */\nexport class FlameGeometry extends ParametricGeometry {\n readonly height: number;\n readonly radius: number;\n readonly segmentsU: number;\n readonly segmentsV: number;\n\n constructor({\n height = 0.25,\n radius = 0.05,\n segmentsU = 16,\n segmentsV = 16,\n }: FlameGeometryOptions = {}) {\n super(\n (u: number, v: number, target: Vector3) => {\n const theta = u * Math.PI * 2;\n const radialFactor = Math.sin(v * Math.PI);\n const x = radius * radialFactor * Math.cos(theta);\n const y = v * height;\n const z = radius * radialFactor * Math.sin(theta);\n\n target.set(x, y, -z);\n },\n segmentsU,\n segmentsV,\n );\n\n this.height = height;\n this.radius = radius;\n this.segmentsU = segmentsU;\n this.segmentsV = segmentsV;\n }\n}","import { BufferGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport { FlameGeometry } from \"./FlameGeometry\";\n\nexport interface CandleGeometryOptions {\n /** Stick top radius. Defaults to `0.2`. */\n radiusTop?: number;\n /** Stick bottom radius. Defaults to `0.2`. */\n radiusBottom?: number;\n /** Stick height. Defaults to `1`. */\n height?: number;\n /** Flame tip height. Defaults to `0.25`. */\n flameHeight?: number;\n /** Flame base radius. Defaults to `0.05`. */\n flameRadius?: number;\n /** Circumference segments. Defaults to `16`. */\n segments?: number;\n}\n\n/**\n * Candle stick and flame — group 0 stick, group 1 flame.\n *\n * Local frame: base at Y=0.\n */\nexport class CandleGeometry extends BufferGeometry {\n readonly radiusTop: number;\n readonly radiusBottom: number;\n readonly height: number;\n readonly flameHeight: number;\n readonly flameRadius: number;\n readonly segments: number;\n\n constructor({\n radiusTop = 0.2,\n radiusBottom = 0.2,\n height = 1,\n flameHeight = 0.25,\n flameRadius = 0.05,\n segments = 16,\n }: CandleGeometryOptions = {}) {\n super();\n\n this.radiusTop = radiusTop;\n this.radiusBottom = radiusBottom;\n this.height = height;\n this.flameHeight = flameHeight;\n this.flameRadius = flameRadius;\n this.segments = segments;\n\n const stickGeometry = new CylinderGeometry(radiusTop, radiusBottom, height, segments);\n stickGeometry.translate(0, height / 2, 0);\n\n const flameGeometry = new FlameGeometry({\n segmentsU: segments,\n segmentsV: segments,\n height: flameHeight,\n radius: flameRadius,\n });\n flameGeometry.translate(0, height, 0);\n\n this.copy(mergeGeometries([stickGeometry, flameGeometry], true) as BufferGeometry);\n }\n}","import { BufferGeometry, ConeGeometry, CylinderGeometry, TorusGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface LanternGeometryOptions {\n /** Base / foot radius. Defaults to `0.5`. */\n baseWidth?: number;\n /** Glass body height. Defaults to `1.3`. */\n bodyHeight?: number;\n /** Base height. Defaults to `0.2`. */\n baseHeight?: number;\n /** Roof cone height. Defaults to `0.5`. */\n roofHeight?: number;\n /** Roof cone radius. Defaults to `baseWidth * 1.1`. */\n roofRadius?: number;\n /** Glass radius relative to `baseWidth`. Defaults to `0.9`. */\n glassRadiusScale?: number;\n /** Glass height inset relative to `bodyHeight`. Defaults to `0.96`. */\n innerScale?: number;\n /** Carry-handle major radius. Defaults to `baseWidth * 0.8`. */\n handleRadius?: number;\n /** Carry-handle tube radius. Defaults to `0.05`. */\n handleTubeRadius?: number;\n /** Gap above the roof to the handle center. Defaults to `0.35`. */\n handleLift?: number;\n /** Radial segments on round parts. Defaults to `8`. */\n segments?: number;\n /** Include the emissive glass body. Defaults to `true`. */\n inner?: boolean;\n}\n\n/**\n * Tabletop lantern — wood/metal base, roof, and handle framing an emissive\n * glass body.\n *\n * Material groups: `0` frame (base + roof + handle), `1` glass body.\n *\n * Local frame: sits on the Y=0 plane; lamp center at `lampCenterY`.\n */\nexport class LanternGeometry extends BufferGeometry {\n readonly baseWidth: number;\n readonly bodyHeight: number;\n readonly baseHeight: number;\n readonly innerScale: number;\n readonly inner: boolean;\n readonly lampCenterY: number;\n\n constructor({\n baseWidth = 0.5,\n bodyHeight = 1.3,\n baseHeight = 0.2,\n roofHeight = 0.5,\n roofRadius = baseWidth * 1.1,\n glassRadiusScale = 0.9,\n innerScale = 0.96,\n handleRadius = baseWidth * 0.8,\n handleTubeRadius = 0.05,\n handleLift = 0.35,\n segments = 8,\n inner = true,\n }: LanternGeometryOptions = {}) {\n super();\n\n this.baseWidth = baseWidth;\n this.bodyHeight = bodyHeight;\n this.baseHeight = baseHeight;\n this.innerScale = innerScale;\n this.inner = inner;\n this.lampCenterY = baseHeight + bodyHeight / 2;\n\n const frame: BufferGeometry[] = [];\n\n const base = new CylinderGeometry(baseWidth, baseWidth, baseHeight, segments);\n base.translate(0, baseHeight / 2, 0);\n frame.push(base);\n\n const roofBottomY = baseHeight + bodyHeight;\n const roof = new ConeGeometry(roofRadius, roofHeight, segments);\n roof.translate(0, roofBottomY + roofHeight / 2, 0);\n frame.push(roof);\n\n const roofTopY = roofBottomY + roofHeight;\n const handle = new TorusGeometry(handleRadius, handleTubeRadius, segments, segments * 2);\n handle.translate(0, roofTopY + handleLift, 0);\n frame.push(handle);\n\n const frameMerged = mergeGeometries(\n frame.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n\n const parts = [frameMerged];\n\n if (inner) {\n const glass = new CylinderGeometry(\n baseWidth * glassRadiusScale * innerScale,\n baseWidth * glassRadiusScale * innerScale,\n bodyHeight * innerScale,\n segments,\n );\n glass.translate(0, this.lampCenterY, 0);\n parts.push(glass.toNonIndexed());\n }\n\n this.copy(mergeGeometries(parts, true) as BufferGeometry);\n this.computeBoundingSphere();\n }\n}","import { BoxGeometry, Quaternion, Vector3 } from \"three\";\n\nconst Y_AXIS = new Vector3(0, 1, 0);\n\n/** Thin box aligned between two points — for open iron lantern cages. */\nexport function barBetween(from: Vector3, to: Vector3, thickness: number): BoxGeometry {\n const direction = to.clone().sub(from);\n const length = direction.length();\n const geometry = new BoxGeometry(thickness, length, thickness);\n geometry.applyQuaternion(new Quaternion().setFromUnitVectors(Y_AXIS, direction.normalize()));\n const midpoint = from.clone().add(to).multiplyScalar(0.5);\n geometry.translate(midpoint.x, midpoint.y, midpoint.z);\n return geometry;\n}","import { BoxGeometry, BufferGeometry, OctahedronGeometry, Vector3 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\nimport { barBetween } from \"./barBetween\";\n\nexport interface HangingLanternGeometryOptions {\n /** Chain length from the hang point. Defaults to `3`. */\n drop?: number;\n /** Chain link cross-section. Defaults to `0.05`. */\n chainWidth?: number;\n /** Cap width (X). Defaults to `0.18`. */\n capWidth?: number;\n /** Cap height (Y). Defaults to `0.16`. */\n capHeight?: number;\n /** Cap depth (Z). Defaults to `0.18`. */\n capDepth?: number;\n /** Cap center offset below the chain bottom. Defaults to `0.02`. */\n capOffset?: number;\n /** Cage vertex radius before stretch. Defaults to `0.42`. */\n cageRadius?: number;\n /** Vertical stretch on the cage. Defaults to `1.4`. */\n cageStretch?: number;\n /** Extra downward offset below the cap-center cage attach. Defaults to `0`. */\n cageGap?: number;\n /** Cage strut thickness. Defaults to `0.03`. */\n cageBarWidth?: number;\n /** Inner lamp scale relative to the cage (inset to sit inside struts). Defaults to `0.96`. */\n innerScale?: number;\n /** Include the solid inner octahedron lamp volume. Defaults to `true`. */\n inner?: boolean;\n}\n\n/**\n * Wrought-iron hanging lantern frame — chain, cap, and open octahedron cage\n * built from edge struts.\n *\n * Material groups: `0` mount (chain + cap), `1` cage struts, `2` inner lamp\n * (solid octahedron).\n *\n * Local frame: origin at the chain top (hang point). The cage top vertex\n * attaches at the cap center, optionally lowered by `cageGap`.\n */\nexport class HangingLanternGeometry extends BufferGeometry {\n readonly drop: number;\n readonly chainWidth: number;\n readonly capWidth: number;\n readonly capHeight: number;\n readonly capDepth: number;\n readonly capOffset: number;\n readonly cageRadius: number;\n readonly cageStretch: number;\n readonly cageGap: number;\n readonly cageBarWidth: number;\n readonly innerScale: number;\n readonly inner: boolean;\n /** Y of the cage center in local space (negative, below the hang point). */\n readonly cageCenterY: number;\n\n constructor({\n drop = 3,\n chainWidth = 0.05,\n capWidth = 0.18,\n capHeight = 0.16,\n capDepth = 0.18,\n capOffset = 0.02,\n cageRadius = 0.42,\n cageStretch = 1.4,\n cageGap = 0,\n cageBarWidth = 0.03,\n innerScale = 0.96,\n inner = true,\n }: HangingLanternGeometryOptions = {}) {\n super();\n\n this.drop = drop;\n this.chainWidth = chainWidth;\n this.capWidth = capWidth;\n this.capHeight = capHeight;\n this.capDepth = capDepth;\n this.capOffset = capOffset;\n this.cageRadius = cageRadius;\n this.cageStretch = cageStretch;\n this.cageGap = cageGap;\n this.cageBarWidth = cageBarWidth;\n this.innerScale = innerScale;\n this.inner = inner;\n\n const capCenterY = -drop + capOffset;\n this.cageCenterY = capCenterY - cageRadius * cageStretch - cageGap;\n\n const mount: BufferGeometry[] = [];\n\n const chain = new BoxGeometry(chainWidth, drop, chainWidth);\n chain.translate(0, -drop / 2, 0);\n mount.push(chain);\n\n const cap = new BoxGeometry(capWidth, capHeight, capDepth);\n cap.translate(0, -drop + capOffset, 0);\n mount.push(cap);\n\n const cy = this.cageCenterY;\n const r = cageRadius;\n const top = new Vector3(0, cy + r * cageStretch, 0);\n const bottom = new Vector3(0, cy - r * cageStretch, 0);\n const px = new Vector3(r, cy, 0);\n const nx = new Vector3(-r, cy, 0);\n const pz = new Vector3(0, cy, r);\n const nz = new Vector3(0, cy, -r);\n\n const cageEdges: [Vector3, Vector3][] = [\n [top, px],\n [top, nx],\n [top, pz],\n [top, nz],\n [bottom, px],\n [bottom, nx],\n [bottom, pz],\n [bottom, nz],\n [px, pz],\n [pz, nx],\n [nx, nz],\n [nz, px],\n ];\n\n const cage = cageEdges.map(([from, to]) => barBetween(from, to, cageBarWidth));\n\n const mountMerged = mergeGeometries(\n mount.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n const cageMerged = mergeGeometries(\n cage.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n\n const parts = [mountMerged, cageMerged];\n\n if (inner) {\n const lamp = new OctahedronGeometry(cageRadius * innerScale, 0);\n lamp.scale(1, cageStretch, 1);\n lamp.translate(0, cy, 0);\n parts.push(lamp.toNonIndexed());\n }\n\n this.copy(mergeGeometries(parts, true) as BufferGeometry);\n this.computeBoundingSphere();\n }\n}","import { BoxGeometry, BufferGeometry, CylinderGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface WallSconceGeometryOptions {\n /** Wall-plate thickness (X). Defaults to `0.05`. */\n plateThickness?: number;\n /** Wall-plate height (Y). Defaults to `0.22`. */\n plateHeight?: number;\n /** Wall-plate depth (Z). Defaults to `0.28`. */\n plateDepth?: number;\n /** Wall-plate center X (negative = into the wall). Defaults to `-0.055`. */\n plateOffsetX?: number;\n /** Bracket length into the room (X). Defaults to `0.1`. */\n bracketLength?: number;\n /** Bracket height (Y). Defaults to `0.05`. */\n bracketHeight?: number;\n /** Bracket depth (Z). Defaults to `0.07`. */\n bracketDepth?: number;\n /** Bracket center X. Defaults to `-0.005`. */\n bracketOffsetX?: number;\n /** Bracket center Y. Defaults to `0.1`. */\n bracketOffsetY?: number;\n /** Chimney / lamp body center X. Defaults to `0.06`. */\n bodyOffsetX?: number;\n /** Chimney height. Defaults to `0.3`. */\n chimneyHeight?: number;\n /** Chimney top radius. Defaults to `0.1`. */\n chimneyTopRadius?: number;\n /** Chimney bottom radius. Defaults to `0.105`. */\n chimneyBottomRadius?: number;\n /** Chimney center Y. Defaults to `-0.05`. */\n chimneyCenterY?: number;\n /** Cap radius. Defaults to `0.115`. */\n capRadius?: number;\n /** Cap height. Defaults to `0.05`. */\n capHeight?: number;\n /** Cap center Y. Defaults to `0.12`. */\n capCenterY?: number;\n /** Bowl top radius. Defaults to `0.09`. */\n bowlTopRadius?: number;\n /** Bowl bottom radius. Defaults to `0.11`. */\n bowlBottomRadius?: number;\n /** Bowl height. Defaults to `0.05`. */\n bowlHeight?: number;\n /** Bowl center Y. Defaults to `-0.22`. */\n bowlCenterY?: number;\n /** Radial segments on cylinders. Defaults to `8`. */\n radialSegments?: number;\n /** Glass chimney scale relative to the frame opening. Defaults to `0.96`. */\n innerScale?: number;\n /** Include the emissive glass chimney. Defaults to `true`. */\n inner?: boolean;\n}\n\n/**\n * Wall-mounted oil-lamp sconce — iron mount, cap, and bowl framing an emissive\n * glass chimney.\n *\n * Material groups: `0` mount (plate + bracket), `1` iron frame (cap + bowl),\n * `2` glass chimney.\n *\n * Local frame: faces +X from a −X wall; lamp center at\n * `(bodyOffsetX, chimneyCenterY, 0)`.\n */\nexport class WallSconceGeometry extends BufferGeometry {\n readonly bodyOffsetX: number;\n readonly chimneyCenterY: number;\n readonly innerScale: number;\n readonly inner: boolean;\n readonly lightCenterX: number;\n readonly lightCenterY: number;\n readonly lightCenterZ: number;\n\n constructor({\n plateThickness = 0.05,\n plateHeight = 0.22,\n plateDepth = 0.28,\n plateOffsetX = -0.055,\n bracketLength = 0.1,\n bracketHeight = 0.05,\n bracketDepth = 0.07,\n bracketOffsetX = -0.005,\n bracketOffsetY = 0.1,\n bodyOffsetX = 0.06,\n chimneyHeight = 0.3,\n chimneyTopRadius = 0.1,\n chimneyBottomRadius = 0.105,\n chimneyCenterY = -0.05,\n capRadius = 0.115,\n capHeight = 0.05,\n capCenterY = 0.12,\n bowlTopRadius = 0.09,\n bowlBottomRadius = 0.11,\n bowlHeight = 0.05,\n bowlCenterY = -0.22,\n radialSegments = 8,\n innerScale = 0.96,\n inner = true,\n }: WallSconceGeometryOptions = {}) {\n super();\n\n this.bodyOffsetX = bodyOffsetX;\n this.chimneyCenterY = chimneyCenterY;\n this.innerScale = innerScale;\n this.inner = inner;\n this.lightCenterX = bodyOffsetX;\n this.lightCenterY = chimneyCenterY;\n this.lightCenterZ = 0;\n\n const mount: BufferGeometry[] = [];\n\n const plate = new BoxGeometry(plateThickness, plateHeight, plateDepth);\n plate.translate(plateOffsetX, 0, 0);\n mount.push(plate);\n\n const bracket = new BoxGeometry(bracketLength, bracketHeight, bracketDepth);\n bracket.translate(bracketOffsetX, bracketOffsetY, 0);\n mount.push(bracket);\n\n const frame: BufferGeometry[] = [];\n\n const cap = new CylinderGeometry(capRadius, capRadius, capHeight, radialSegments);\n cap.translate(bodyOffsetX, capCenterY, 0);\n frame.push(cap);\n\n const bowl = new CylinderGeometry(bowlTopRadius, bowlBottomRadius, bowlHeight, radialSegments);\n bowl.translate(bodyOffsetX, bowlCenterY, 0);\n frame.push(bowl);\n\n const mountMerged = mergeGeometries(\n mount.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n const frameMerged = mergeGeometries(\n frame.map((part) => part.toNonIndexed()),\n false,\n ) as BufferGeometry;\n\n const parts = [mountMerged, frameMerged];\n\n if (inner) {\n const glass = new CylinderGeometry(\n chimneyTopRadius * innerScale,\n chimneyBottomRadius * innerScale,\n chimneyHeight * innerScale,\n radialSegments,\n );\n glass.translate(bodyOffsetX, chimneyCenterY, 0);\n parts.push(glass.toNonIndexed());\n }\n\n this.copy(mergeGeometries(parts, true) as BufferGeometry);\n this.computeBoundingSphere();\n }\n}","import { BufferAttribute, BufferGeometry } from \"three\";\n\n/**\n * Prismatic parallelogram, with horizontal skew (offset in X for the slant).\n */\nexport class ParallelogramBoxGeometry extends BufferGeometry {\n constructor(width = 1, height = 2, depth = 0.5, angle = Math.PI / 4) {\n super();\n\n const s = height * Math.tan(angle); // skew\n const w = width;\n const h = height;\n const d = depth;\n\n // Bottom face vertices (X, Y, Z)\n const vertices = [\n 0, 0, 0, // Front face, bottom left\n w, 0, 0, // Front face, bottom right\n w + s, h, 0, // Front face, top right\n s, h, 0, // Front face, top left\n\n w, 0, -d, // Back face\n 0, 0, -d,\n s, h, -d,\n w + s, h, -d,\n\n 0, 0, -d, // Left face\n 0, 0, 0,\n s, h, 0,\n s, h, -d,\n\n w, 0, 0, // Right face\n w, 0, -d,\n w + s, h, -d,\n w + s, h, 0,\n\n s, h, 0, // Top face\n w + s, h, 0,\n w + s, h, -d,\n s, h, -d,\n\n 0, 0, -d, // Bottom\n w, 0, -d,\n w, 0, 0,\n 0, 0, 0,\n ];\n\n const normals = [\n 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Front face\n 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, // Back face\n -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // Left face\n 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Right face\n 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Top face\n 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, // Bottom face\n ]\n\n // Define indices for faces (triangles)\n const indices = [\n 0, 1, 2, 2, 3, 0, // Front face\n 4, 5, 6, 6, 7, 4, // Back face\n 8, 9, 10, 10, 11, 8, // Left face\n 12, 13, 14, 14, 15, 12, // Right face\n 16, 17, 18, 18, 19, 16, // Top face\n 20, 21, 22, 22, 23, 20, // Bottom face\n ];\n\n // Define UV coordinates\n const uvs = new Float32Array([\n 0, 0, 1, 0, 1, 1, 0, 1, // Front face\n 0, 0, 1, 0, 1, 1, 0, 1, // Back face\n 0, 0, 1, 0, 1, 1, 0, 1, // Left face\n 0, 0, 1, 0, 1, 1, 0, 1, // Right face\n 0, 0, 1, 0, 1, 1, 0, 1, // Top face\n 0, 0, 1, 0, 1, 1, 0, 1, // Bottom face\n ]);\n\n\n const positions = new Float32Array(vertices);\n const normalArray = new Float32Array(normals);\n const uvArray = new Float32Array(uvs);\n const indexArray = new Uint16Array(indices);\n\n this.setAttribute('position', new BufferAttribute(positions, 3));\n this.setAttribute('normal', new BufferAttribute(normalArray, 3));\n this.setAttribute('uv', new BufferAttribute(uvArray, 2));\n this.setIndex(new BufferAttribute(indexArray, 1));\n this.center();\n }\n}\n","import { Path, Shape } from \"three\";\n\nexport class GearShape extends Shape {\n constructor(sides = 5, innerRadius = 0.5, outerRadius = 1, holeSides = 5, holeRadius = 0.25) {\n super();\n\n const step = (Math.PI * 2) / sides;\n const qtrStep = step / 4;\n\n this.moveTo(Math.cos(0) * outerRadius, -Math.sin(0) * outerRadius);\n\n for (let n = 1; n <= sides; ++n) {\n this.lineTo(Math.cos(step * n - qtrStep * 3) * innerRadius, -Math.sin(step * n - qtrStep * 3) * innerRadius);\n this.lineTo(Math.cos(step * n - qtrStep * 2) * innerRadius, -Math.sin(step * n - qtrStep * 2) * innerRadius);\n this.lineTo(Math.cos(step * n - qtrStep) * outerRadius, -Math.sin(step * n - qtrStep) * outerRadius);\n this.lineTo(Math.cos(step * n) * outerRadius, -Math.sin(step * n) * outerRadius);\n }\n this.closePath();\n\n // Create the hole in the gear, if specified\n if (holeRadius > 0 && holeSides > 2) {\n const hole = new Path();\n const holeStep = (Math.PI * 2) / holeSides;\n\n hole.moveTo(Math.cos(0) * holeRadius, -Math.sin(0) * holeRadius);\n for (let n = 1; n < holeSides; ++n) {\n hole.lineTo(Math.cos(holeStep * n) * holeRadius, -Math.sin(holeStep * n) * holeRadius);\n }\n hole.lineTo(Math.cos(0) * holeRadius, -Math.sin(0) * holeRadius);\n\n this.holes.push(hole);\n }\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { GearShape } from \"../../shapes/GearShape\";\n\nexport interface GearGeometryOptions {\n /** Number of gear teeth. Defaults to `5`. */\n sides?: number;\n /** Inner tooth valley radius. Defaults to `0.5`. */\n innerRadius?: number;\n /** Outer tooth tip radius. Defaults to `1`. */\n outerRadius?: number;\n /** Center hole sides. Defaults to `5`. */\n holeSides?: number;\n /** Center hole radius. Defaults to `0.25`. */\n holeRadius?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded gear profile with center hole.\n */\nexport class GearGeometry extends ExtrudeGeometry {\n constructor({\n sides = 5,\n innerRadius = 0.5,\n outerRadius = 1,\n holeSides = 5,\n holeRadius = 0.25,\n depth = 0.25,\n }: GearGeometryOptions = {}) {\n super(new GearShape(sides, innerRadius, outerRadius, holeSides, holeRadius), {\n depth,\n bevelEnabled: false,\n });\n }\n}","import { Shape } from \"three\";\n\nexport class HeartShape extends Shape {\n constructor(size = 1, width = 2.1, height = 1.4, tipDepth = 1.6) {\n super();\n\n // Start from the top middle of the heart\n this.moveTo(0, height * size / 3);\n\n // Left curve\n this.bezierCurveTo(\n -width * 0.375 * size, height * size, // Control point 1 for the left lobe\n -width * size, height * size / 3, // Control point 2 for the left side of the heart\n 0, -tipDepth * size // Bottom tip of the heart, controlled by `tipDepth`\n );\n\n // Right curve\n this.bezierCurveTo(\n width * size, height * size / 3, // Control point 3 for the right side of the heart\n width * 0.375 * size, height * size, // Control point 4 for the right lobe\n 0, height * size / 3 // Close shape at the top middle\n );\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { HeartShape } from \"../../shapes/HeartShape\";\n\nexport interface HeartGeometryOptions {\n /** Overall scale factor. Defaults to `1`. */\n size?: number;\n /** Heart width. Defaults to `2.1`. */\n width?: number;\n /** Heart height. Defaults to `1.4`. */\n height?: number;\n /** Tip depth. Defaults to `1.6`. */\n tipDepth?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded heart prism.\n */\nexport class HeartGeometry extends ExtrudeGeometry {\n constructor({\n size = 1,\n width = 2.1,\n height = 1.4,\n tipDepth = 1.6,\n depth = 0.25,\n }: HeartGeometryOptions = {}) {\n super(new HeartShape(size, width, height, tipDepth), { depth, bevelEnabled: false });\n }\n}","import { Shape } from \"three\";\n\nexport class StarShape extends Shape {\n constructor(points = 5, innerRadius = 0.5, outerRadius = 1.0) {\n super();\n\n const step = (Math.PI * 2) / points;\n const halfStep = step / 2;\n this.moveTo(Math.cos(0) * outerRadius, Math.sin(0) * outerRadius);\n\n for (let n = 1; n <= points; ++n) {\n this.lineTo(Math.cos(step * n - halfStep) * innerRadius, Math.sin(step * n - halfStep) * innerRadius);\n this.lineTo(Math.cos(step * n) * outerRadius, Math.sin(step * n) * outerRadius);\n }\n\n this.closePath();\n }\n}\n","import { ExtrudeGeometry } from \"three\";\nimport { StarShape } from \"../../shapes/StarShape\";\n\nexport interface StarGeometryOptions {\n /** Number of star points. Defaults to `5`. */\n points?: number;\n /** Inner vertex radius. Defaults to `0.5`. */\n innerRadius?: number;\n /** Outer vertex radius. Defaults to `1`. */\n outerRadius?: number;\n /** Extrusion depth. Defaults to `0.25`. */\n depth?: number;\n}\n\n/**\n * Extruded star prism.\n */\nexport class StarGeometry extends ExtrudeGeometry {\n constructor({\n points = 5,\n innerRadius = 0.5,\n outerRadius = 1.0,\n depth = 0.25,\n }: StarGeometryOptions = {}) {\n super(new StarShape(points, innerRadius, outerRadius), { depth, bevelEnabled: false });\n }\n}","import { BufferGeometry, CylinderGeometry, SphereGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Bone Geometry, a simple bone shape\n * @extends BufferGeometry\n *\n * @example\n * // Create a bone\n * const boneGeometry = new BoneGeometry();\n * const boneMaterial = new MeshStandardMaterial({ color: 0xffffff });\n * const bone = new Mesh(boneGeometry, boneMaterial);\n * scene.add(bone);\n */\nclass BoneGeometry extends BufferGeometry {\n constructor(radiusTop = 0.1, radiusBottom = 0.1, height = 0.4, radialSegments = 8) {\n super();\n\n // Create the cylinder (shaft of the bone)\n const cylinderGeometry = new CylinderGeometry(radiusTop * 0.6, radiusBottom * 0.6, height, radialSegments);\n cylinderGeometry.translate(0, 0, 0);\n\n // Create the spheres (ends of the bone)\n const sphereGeometry = new SphereGeometry(radiusTop, radialSegments, radialSegments);\n const topSphere1 = sphereGeometry.clone();\n const topSphere2 = sphereGeometry.clone();\n const bottomSphere1 = sphereGeometry.clone();\n const bottomSphere2 = sphereGeometry.clone();\n\n // Position the spheres at each end of the cylinder\n topSphere1.translate(0, height / 2 + radiusTop * 0.6, -radiusTop * 0.6);\n topSphere2.translate(0, height / 2 + radiusTop * 0.6, radiusTop * 0.6);\n bottomSphere1.translate(0, -height / 2 - radiusBottom * 0.6, -radiusBottom * 0.6);\n bottomSphere2.translate(0, -height / 2 - radiusBottom * 0.6, radiusBottom * 0.6);\n\n // Merge the parts\n this.copy(mergeGeometries([cylinderGeometry, topSphere1, topSphere2, bottomSphere1, bottomSphere2], false) as BufferGeometry);\n }\n}\n\nexport { BoneGeometry };\n","import { BufferGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface ErlenmeyerFlaskGeometryOptions {\n /** Flask body radius. Defaults to `1`. */\n flaskRadius?: number;\n /** Neck radius. Defaults to `0.3`. */\n neckRadius?: number;\n /** Body height before the neck. Defaults to `2.5`. */\n height?: number;\n /** Neck height. Defaults to `1`. */\n neckHeight?: number;\n /** Lathe segments. Defaults to `16`. */\n radialSegments?: number;\n}\n\n/**\n * Erlenmeyer flask profile — conical body with straight neck and lip.\n *\n * Local frame: base at Y=0.\n */\nexport class ErlenmeyerFlaskGeometry extends BufferGeometry {\n readonly flaskRadius: number;\n readonly height: number;\n\n constructor({\n flaskRadius = 1,\n neckRadius = 0.3,\n height = 2.5,\n neckHeight = 1,\n radialSegments = 16,\n }: ErlenmeyerFlaskGeometryOptions = {}) {\n super();\n\n this.flaskRadius = flaskRadius;\n this.height = height;\n\n const points = [\n new Vector2(0, 0),\n new Vector2(flaskRadius * 0.875, 0),\n new Vector2(flaskRadius, 0.1),\n new Vector2(neckRadius, height),\n new Vector2(neckRadius, height + neckHeight),\n new Vector2(neckRadius * 1.1, height + neckHeight + 0.3),\n ];\n\n const flaskGeometry = new LatheGeometry(points, radialSegments);\n\n this.copy(mergeGeometries([flaskGeometry], false) as BufferGeometry);\n }\n}","/**\n * Calculate the radius to achieve a spherical cap height.\n * R = r / (1 - cos(thetaLength))\n */\nexport const radiusFromCapHeight = (height: number, thetaLength: number) => height / (1 - Math.cos(thetaLength));\n\n/**\n * Calculate the radius to achieve a spherical cap width.\n * R = w / (2 * sin(thetaLength))\n */\nexport const radiusFromCapWidth = (width: number, thetaLength: number) => width / (2 * Math.sin(thetaLength));\n\n/**\n * Calculate the height of a spherical cap.\n * h = R * (1 - cos(thetaLength))\n */\nexport const capHeightFromRadius = (radius: number, thetaLength: number) => radius * (1 - Math.cos(thetaLength));\n\n/**\n * Calculate the width of a spherical cap.\n * w = 2 * R * sin(thetaLength)\n */\nexport const capWidthFromRadius = (radius: number, thetaLength: number) => 2 * radius * Math.sin(thetaLength);\n\n/**\n * Calculate the thetaLength to achieve a specific hole radius in a sphere.\n * thetaLength = asin(w / (2 * R))\n *\n * Returns the thetaLength in radians.\n *\n * Example usage:\n * ```\n * const sphereRadius = 5; // Radius of the sphere\n * const holeRadius = 1; // Desired radius of the hole at the top\n * const thetaLength = thetaLengthForRadius(sphereRadius, holeRadius);\n * ```\n */\nexport const thetaLengthForRadius = (sphereRadius: number, holeRadius: number) => {\n const holeDiameter = 2 * holeRadius; // Hole width\n return Math.asin(holeDiameter / (2 * sphereRadius));\n};\n\n/**\n * Convert spherical coordinates to Cartesian coordinates.\n * @param {number} radius - The radius of the sphere.\n * @param {number} theta - The azimuthal angle in radians (from the x-axis in the x-y plane).\n * @param {number} phi - The polar angle in radians (from the positive z-axis).\n * @returns {{x: number, y: number, z: number}} The Cartesian coordinates.\n */\nexport const sphericalToCartesian = (radius: number, theta: number, phi: number) => {\n return {\n x: radius * Math.sin(phi) * Math.cos(theta),\n y: radius * Math.sin(phi) * Math.sin(theta),\n z: radius * Math.cos(phi),\n };\n};\n\n/**\n * Convert Cartesian coordinates to spherical coordinates.\n * @param {number} x - The x-coordinate.\n * @param {number} y - The y-coordinate.\n * @param {number} z - The z-coordinate.\n * @returns {{radius: number, theta: number, phi: number}} The spherical coordinates.\n */\nexport const cartesianToSpherical = (x: number, y: number, z: number) => {\n const radius = Math.sqrt(x * x + y * y + z * z);\n const theta = Math.atan2(y, x); // Azimuthal angle\n const phi = Math.acos(z / radius); // Polar angle\n return { radius, theta, phi };\n};\n","import { Vector2 } from \"three\";\nimport { thetaLengthForRadius } from \"./SphericalGeometryUtils\";\n\n/**\n * Generates spherical curve profile points, for use with geometry.\n * Enables connective geometry via holes at the top and bottom of the sphere.\n *\n * Example usage:\n *\n * Tube that connect with a sphere on the bottom:\n * ```\n * const points: Vector2[] = [\n * new Vector2(1, 0),\n * ...appendSphericalCurve(\n * 2, // Radius x\n * 2, // Radius y\n * 5, // Start y\n * 0, // Hole top radius\n * 1, // Hole bottom radius\n * 32, // Segments\n * ),\n * ];\n *\n * const latheGeometry = new LatheGeometry(points, 32);\n * ```\n *\n * Tube that connect with a sphere on the top:\n * ```\n * const points: Vector2[] = [\n * ...appendSphericalCurve(\n * 2, // Radius x\n * 2, // Radius y\n * 1, // Start y\n * 1, // Hole top radius\n * 0, // Hole bottom radius\n * 32, // Segments\n * ),\n * new Vector2(1, 5),\n * ];\n *\n * const latheGeometry = new LatheGeometry(points, 32);\n * ```\n */\nexport function appendSphericalCurve(\n sphereRadiusX: number,\n sphereRadiusY: number,\n sphereStartY: number,\n holeTopRadius: number = 0,\n holeBottomRadius: number = 0,\n segments: number = 32,\n) {\n const thetaTop = holeTopRadius ? thetaLengthForRadius(sphereRadiusX, holeTopRadius) : 0;\n const thetaBottom = holeBottomRadius ? Math.PI - thetaLengthForRadius(sphereRadiusX, holeBottomRadius) : Math.PI;\n\n // Generate sphere points (from bottom to top)\n const spherePoints = [];\n for (let i = 0; i <= segments; i++) {\n const theta = thetaBottom - ((thetaBottom - thetaTop) / segments) * i; // Bottom to top\n const x = sphereRadiusX * Math.sin(theta);\n const y = sphereRadiusY * Math.cos(theta) + sphereStartY; // Offset by sphereStartY\n spherePoints.push(new Vector2(x, y));\n }\n\n // Combine base points and sphere points\n return [...spherePoints];\n}\n","import { BufferGeometry, LatheGeometry, Vector2 } from \"three\";\nimport { appendSphericalCurve } from \"../../utils/SphericalCurve\";\n\nexport class FlorenceFlaskGeometry extends BufferGeometry {\n constructor() {\n super();\n\n const points = [\n ...appendSphericalCurve(1, 1, 0.5, 0.2, 0, 32),\n new Vector2(0.2, 3),\n ];\n\n // Create LatheGeometry\n const latheGeometry = new LatheGeometry(points, 32);\n this.copy(latheGeometry);\n }\n}\n","import { BufferGeometry, CircleGeometry, LatheGeometry, Vector2 } from \"three\";\nimport {mergeGeometries} from \"three/addons/utils/BufferGeometryUtils.js\";\n\nclass MortarGeometry extends BufferGeometry {\n constructor() {\n super();\n\n const mortarPoints = [\n new Vector2(1, 0), // Bottom of the bowl\n new Vector2(1.2, 0.5), // Slight flare at the base\n new Vector2(1.4, 1.5), // Outer wall\n new Vector2(1.3, 1.8), // Flared edge\n new Vector2(0.8, 1.8), // Lip of the bowl\n ];\n const mortarGeometry = new LatheGeometry(mortarPoints, 12);\n\n // Create a disk to close off the bottom\n const baseDisk = new CircleGeometry(1, 12); // Radius matches the base of the mortar\n baseDisk.rotateX(-Math.PI / 2); // Rotate to align with the bottom\n baseDisk.translate(0, 0, 0); // Position at the base of the mortar\n\n this.copy(mergeGeometries([mortarGeometry, baseDisk], false) as BufferGeometry);\n }\n}\n\nexport { MortarGeometry };\n","import { BufferGeometry, CylinderGeometry, TorusGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface StandGeometryOptions {\n /** Ring radius. Defaults to `0.3`. */\n radius?: number;\n /** Leg height. Defaults to `0.4`. */\n height?: number;\n /** Number of legs. Defaults to `3`. */\n count?: number;\n /** Ring tube thickness. Defaults to `0.03`. */\n thickness?: number;\n /** Circumference segments. Defaults to `16`. */\n radialSegments?: number;\n}\n\n/**\n * Tripod-style stand — torus ring with radial legs.\n *\n * Local frame: legs on Y=0.\n */\nexport class StandGeometry extends BufferGeometry {\n readonly radius: number;\n readonly height: number;\n readonly count: number;\n\n constructor({\n radius = 0.3,\n height = 0.4,\n count = 3,\n thickness = 0.03,\n radialSegments = 16,\n }: StandGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.height = height;\n this.count = count;\n\n const ringGeometry = new TorusGeometry(radius, thickness, 8, radialSegments);\n ringGeometry.rotateX(Math.PI / 2);\n ringGeometry.translate(0, height, 0);\n\n const legGeometry = new CylinderGeometry(thickness * 0.6, thickness * 0.6, height, radialSegments);\n const legs = [];\n\n for (let i = 0; i < count; i++) {\n const angle = (i / count) * Math.PI * 2;\n const leg = legGeometry.clone();\n leg.translate(Math.cos(angle) * radius, height / 2, Math.sin(angle) * radius);\n legs.push(leg);\n }\n\n this.copy(mergeGeometries([ringGeometry, ...legs], false) as BufferGeometry);\n }\n}","import { BufferGeometry, CylinderGeometry, SphereGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\n/**\n * Group indices\n * 0: Base\n * 1: Coil\n */\nexport class TeslaCoilGeometry extends BufferGeometry {\n constructor() {\n super();\n\n // Base geometry\n const baseGeometry = new CylinderGeometry(0.5, 0.6, 0.3, 16);\n baseGeometry.translate(0, 0.15, 0);\n\n // Coil geometry\n const coilGeometry = new CylinderGeometry(0.15, 0.15, 2, 12, 1, true);\n coilGeometry.translate(0, 1.3, 0);\n const coilTopGeometry = new SphereGeometry(0.3, 16, 16);\n coilTopGeometry.translate(0, 2.4, 0);\n\n this.copy(\n mergeGeometries(\n [baseGeometry, mergeGeometries([coilGeometry, coilTopGeometry]) as BufferGeometry],\n true,\n ) as BufferGeometry,\n );\n }\n}\n","import { BufferGeometry, CylinderGeometry, SphereGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nclass TestTubeGeometry extends BufferGeometry {\n constructor(radiusTop = 0.2, radiusBottom = 0.2, height = 3, segments = 32, openEnded = true) {\n super();\n\n // Create the cylindrical body\n const tubeGeometry = new CylinderGeometry(radiusTop, radiusBottom, height, segments, 1, openEnded);\n\n // Create the rounded bottom using a half sphere\n const bottomGeometry = new SphereGeometry(radiusBottom, segments, segments / 2, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2);\n bottomGeometry.translate(0, -(height / 2), 0); // Position it at the bottom of the cylinder\n\n // Merge parts\n this.copy(mergeGeometries([tubeGeometry, bottomGeometry], false) as BufferGeometry);\n }\n}\n\nexport { TestTubeGeometry };\n","import { BufferAttribute, BufferGeometry } from \"three\";\nimport { fbm2 } from \"../../utils/CoherentNoise\";\n\nexport interface TerrainMoundGeometryOptions {\n /** Footprint radius (world units). Defaults to `8`. */\n radius?: number;\n /** Dome peak height at the center. Defaults to `1.2`. */\n height?: number;\n /** Concentric rings from center to rim. Defaults to `40`. */\n radialSegments?: number;\n /** Segments around the circumference. Defaults to `64`. */\n angularSegments?: number;\n /** Amplitude of the terrain relief added on top of the dome. Defaults to `0.5`. */\n noiseHeight?: number;\n /** Noise frequency — higher packs more, smaller bumps into the footprint. Defaults to `0.35`. */\n noiseScale?: number;\n /** fbm octaves (detail layers). Defaults to `4`. */\n octaves?: number;\n /** fbm gain per octave (0–1); lower is smoother, higher is rougher. Defaults to `0.5`. */\n persistence?: number;\n /** Normalized radius (0–1) where the rim begins fading relief to a flat edge. Defaults to `0.82`. */\n rim?: number;\n /** Seed for reproducible terrain. Defaults to `1`. */\n seed?: number;\n}\n\n/**\n * Rounded terrain cap — a circular disc bulged into a gentle dome, then broken up\n * with coherent fbm noise so it reads as rolling terrain rather than a smooth lens.\n * The relief tapers to a clean circular rim seated on the Y=0 plane.\n *\n * Displacement is baked into real vertices (no shader), so shadows, raycasts, and\n * any physics collider derived from the mesh match exactly what's drawn — and it\n * renders identically on WebGL and WebGPU/TSL. Pair with a `flatShading` material\n * for a faceted low-poly look; the coherent noise keeps neighboring vertices moving\n * together, so faces never tear.\n *\n * Local frame: base on Y=0, peak toward +Y, centered on the origin.\n */\nexport class TerrainMoundGeometry extends BufferGeometry {\n readonly radius: number;\n readonly height: number;\n\n constructor({\n radius = 8,\n height = 1.2,\n radialSegments = 40,\n angularSegments = 64,\n noiseHeight = 0.5,\n noiseScale = 0.35,\n octaves = 4,\n persistence = 0.5,\n rim = 0.82,\n seed = 1,\n }: TerrainMoundGeometryOptions = {}) {\n super();\n\n this.radius = radius;\n this.height = height;\n\n const rings = Math.max(1, Math.round(radialSegments));\n const segs = Math.max(3, Math.round(angularSegments));\n\n // Height at normalized radius r ∈ [0, 1]: raised cosine — 1 at center, 0 at the\n // rim, with zero slope at both ends so the peak is rounded and the edge melts\n // flush into Y=0. Relief is added on top and faded out over the rim band.\n const domeAt = (r: number) => 0.5 + 0.5 * Math.cos(Math.PI * r);\n const rimFade = (r: number) => {\n if (r <= rim) return 1;\n const t = (r - rim) / (1 - rim);\n return 1 - t * t * (3 - 2 * t);\n };\n const yAt = (r: number, x: number, z: number) =>\n domeAt(r) * height + fbm2(x * noiseScale, z * noiseScale, seed, octaves, persistence) * noiseHeight * rimFade(r);\n\n const vertexCount = 1 + rings * segs;\n const positions = new Float32Array(vertexCount * 3);\n const uvs = new Float32Array(vertexCount * 2);\n\n // Center vertex.\n positions[1] = yAt(0, 0, 0);\n uvs[0] = 0.5;\n uvs[1] = 0.5;\n\n // Ring vertices: ring j ∈ [1, rings], each with `segs` points.\n for (let j = 1; j <= rings; j++) {\n const r = j / rings;\n const ringRadius = r * radius;\n for (let k = 0; k < segs; k++) {\n const angle = (k / segs) * Math.PI * 2;\n const x = Math.cos(angle) * ringRadius;\n const z = Math.sin(angle) * ringRadius;\n const vi = 1 + (j - 1) * segs + k;\n positions[vi * 3] = x;\n positions[vi * 3 + 1] = yAt(r, x, z);\n positions[vi * 3 + 2] = z;\n uvs[vi * 2] = x / (2 * radius) + 0.5;\n uvs[vi * 2 + 1] = z / (2 * radius) + 0.5;\n }\n }\n\n const ringVertex = (j: number, k: number) => 1 + (j - 1) * segs + (k % segs);\n const indices: number[] = [];\n\n // Center fan (center → ring 1). Wound so the surface faces +Y.\n for (let k = 0; k < segs; k++) {\n indices.push(0, ringVertex(1, k + 1), ringVertex(1, k));\n }\n\n // Concentric quad strips between successive rings.\n for (let j = 1; j < rings; j++) {\n for (let k = 0; k < segs; k++) {\n const inner0 = ringVertex(j, k);\n const inner1 = ringVertex(j, k + 1);\n const outer0 = ringVertex(j + 1, k);\n const outer1 = ringVertex(j + 1, k + 1);\n indices.push(inner0, outer1, outer0);\n indices.push(inner0, inner1, outer1);\n }\n }\n\n this.setAttribute(\"position\", new BufferAttribute(positions, 3));\n this.setAttribute(\"uv\", new BufferAttribute(uvs, 2));\n this.setIndex(indices);\n this.computeVertexNormals();\n }\n}\n","import { BufferAttribute, BufferGeometry } from \"three\";\nimport { fbm2 } from \"../../utils/CoherentNoise\";\n\nexport interface TerrainPlaneGeometryOptions {\n /** Extent along X (world units). Defaults to `16`. */\n width?: number;\n /** Extent along Z (world units). Defaults to `16`. */\n depth?: number;\n /** Grid segments along X. Defaults to `48`. */\n widthSegments?: number;\n /** Grid segments along Z. Defaults to `48`. */\n depthSegments?: number;\n /** Amplitude of the terrain relief (world units, ±). Defaults to `0.8`. */\n noiseHeight?: number;\n /** Noise frequency — higher packs more, smaller features into the footprint. Defaults to `0.35`. */\n noiseScale?: number;\n /** fbm octaves (detail layers). Defaults to `4`. */\n octaves?: number;\n /** fbm gain per octave (0–1); lower is smoother, higher is rougher. Defaults to `0.5`. */\n persistence?: number;\n /**\n * Border band (0–1 fraction of the half-extent) over which relief fades to a flat\n * edge at Y=0. `0` leaves a raw, seamless heightfield (tileable); higher values\n * seat the slab like a contained diorama patch. Defaults to `0`.\n */\n edgeFalloff?: number;\n /** Seed for reproducible terrain. Defaults to `1`. */\n seed?: number;\n}\n\n/**\n * Rectangular terrain patch — a flat grid displaced on Y by the shared coherent fbm\n * sampler ({@link fbm2}). The rectangular counterpart to {@link TerrainMoundGeometry}:\n * same noise strategy, grid layout instead of a radial disc.\n *\n * A pure heightfield (Y is single-valued per XZ) so faces can never fold, and it's\n * baked into real vertices — shadows, raycasts, and physics colliders match what's\n * drawn, on WebGL and WebGPU/TSL alike. Pair with a `flatShading` material for a\n * faceted low-poly look. Leave `edgeFalloff` at `0` for a tileable field; raise it to\n * seat the edges flat at Y=0.\n *\n * Local frame: base grid on Y=0, relief toward ±Y, centered on the origin.\n */\nexport class TerrainPlaneGeometry extends BufferGeometry {\n readonly width: number;\n readonly depth: number;\n\n constructor({\n width = 16,\n depth = 16,\n widthSegments = 48,\n depthSegments = 48,\n noiseHeight = 0.8,\n noiseScale = 0.35,\n octaves = 4,\n persistence = 0.5,\n edgeFalloff = 0,\n seed = 1,\n }: TerrainPlaneGeometryOptions = {}) {\n super();\n\n this.width = width;\n this.depth = depth;\n\n const cols = Math.max(1, Math.round(widthSegments));\n const rows = Math.max(1, Math.round(depthSegments));\n const halfW = width / 2;\n const halfD = depth / 2;\n\n // Fade relief to zero within `edgeFalloff` of the border so the rim seats flat.\n const fade = Math.min(Math.max(edgeFalloff, 0), 1);\n const edgeFade = (x: number, z: number) => {\n if (fade <= 0) return 1;\n const nx = Math.min(x + halfW, halfW - x) / halfW; // 0 at X edges → 1 at center line\n const nz = Math.min(z + halfD, halfD - z) / halfD;\n const d = Math.min(nx, nz);\n if (d >= fade) return 1;\n const t = d / fade;\n return t * t * (3 - 2 * t);\n };\n\n const vertexCount = (cols + 1) * (rows + 1);\n const positions = new Float32Array(vertexCount * 3);\n const uvs = new Float32Array(vertexCount * 2);\n\n for (let iz = 0; iz <= rows; iz++) {\n const z = -halfD + (iz / rows) * depth;\n for (let ix = 0; ix <= cols; ix++) {\n const x = -halfW + (ix / cols) * width;\n const y =\n fbm2(x * noiseScale, z * noiseScale, seed, octaves, persistence) * noiseHeight * edgeFade(x, z);\n const vi = iz * (cols + 1) + ix;\n positions[vi * 3] = x;\n positions[vi * 3 + 1] = y;\n positions[vi * 3 + 2] = z;\n uvs[vi * 2] = ix / cols;\n uvs[vi * 2 + 1] = iz / rows;\n }\n }\n\n const indices: number[] = [];\n const vertex = (ix: number, iz: number) => iz * (cols + 1) + ix;\n for (let iz = 0; iz < rows; iz++) {\n for (let ix = 0; ix < cols; ix++) {\n const a = vertex(ix, iz);\n const b = vertex(ix + 1, iz);\n const c = vertex(ix, iz + 1);\n const d = vertex(ix + 1, iz + 1);\n // Wound so the surface faces +Y.\n indices.push(a, c, b);\n indices.push(b, c, d);\n }\n }\n\n this.setAttribute(\"position\", new BufferAttribute(positions, 3));\n this.setAttribute(\"uv\", new BufferAttribute(uvs, 2));\n this.setIndex(indices);\n this.computeVertexNormals();\n }\n}\n","import { BufferGeometry, CylinderGeometry, DodecahedronGeometry } from \"three\";\nimport { mergeGeometries } from \"three/addons/utils/BufferGeometryUtils.js\";\n\nexport interface TreeGeometryOptions {\n /** Trunk top radius. Defaults to `0.25`. */\n trunkRadiusTop?: number;\n /** Trunk bottom radius. Defaults to `0.4`. */\n trunkRadiusBottom?: number;\n /** Trunk height. Defaults to `2.5`. */\n trunkHeight?: number;\n /** Trunk circumference segments. Defaults to `14`. */\n trunkSegments?: number;\n /** Leaf dodecahedron radius. Defaults to `0.8`. */\n leafSize?: number;\n /** Number of leaf clusters. Defaults to `6`. */\n leafCount?: number;\n /** Leaf dodecahedron detail level. Defaults to `0`. */\n leafDetail?: number;\n /** Horizontal spread of leaf placement. Defaults to `1.5`. */\n leafSpreadRadius?: number;\n}\n\n/**\n * Low-poly tree — trunk (group 0) and leaf clusters (group 1).\n *\n * Local frame: trunk base at Y=0. Leaf positions use `Math.random()` each build.\n */\nexport class TreeGeometry extends BufferGeometry {\n readonly trunkRadiusTop: number;\n readonly trunkRadiusBottom: number;\n readonly trunkHeight: number;\n readonly trunkSegments: number;\n readonly leafSize: number;\n readonly leafCount: number;\n readonly leafDetail: number;\n readonly leafSpreadRadius: number;\n\n constructor({\n trunkRadiusTop = 0.25,\n trunkRadiusBottom = 0.4,\n trunkHeight = 2.5,\n trunkSegments = 14,\n leafSize = 0.8,\n leafCount = 6,\n leafDetail = 0,\n leafSpreadRadius = 1.5,\n }: TreeGeometryOptions = {}) {\n super();\n\n this.trunkRadiusTop = trunkRadiusTop;\n this.trunkRadiusBottom = trunkRadiusBottom;\n this.trunkHeight = trunkHeight;\n this.trunkSegments = trunkSegments;\n this.leafSize = leafSize;\n this.leafCount = leafCount;\n this.leafDetail = leafDetail;\n this.leafSpreadRadius = leafSpreadRadius;\n\n const trunk = new CylinderGeometry(trunkRadiusTop, trunkRadiusBottom, trunkHeight, trunkSegments);\n trunk.translate(0, trunkHeight / 2, 0);\n\n const leafs: DodecahedronGeometry[] = [];\n for (let i = 0; i < leafCount; i++) {\n const leaf = new DodecahedronGeometry(leafSize, leafDetail);\n leaf.translate(\n (Math.random() - 0.5) * leafSpreadRadius,\n (Math.random() - 0.5) * leafSize + trunkHeight,\n (Math.random() - 0.5) * leafSpreadRadius,\n );\n leafs.push(leaf);\n }\n\n this.copy(\n mergeGeometries(\n [trunk.toNonIndexed(), mergeGeometries(leafs, false) as BufferGeometry],\n true,\n ) as BufferGeometry,\n );\n this.computeVertexNormals();\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n LShapedStaircaseGeometry,\n type LShapedStaircaseGeometryOptions,\n} from \"../../geometry/architecture/LShapedStaircaseGeometry\";\n\nexport interface LShapedStaircaseOptions extends LShapedStaircaseGeometryOptions {\n /** Tread and riser tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * L-shaped staircase prefab — two flights with a square width × width landing.\n */\nexport class LShapedStaircase extends Mesh<LShapedStaircaseGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepsPerFlight: number;\n readonly landingSize: number;\n readonly flightRun: number;\n readonly totalHeight: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: LShapedStaircaseOptions = {}) {\n const geometry = new LShapedStaircaseGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n side: DoubleSide,\n }),\n );\n\n this.width = geometry.width;\n this.riserHeight = geometry.riserHeight;\n this.treadDepth = geometry.treadDepth;\n this.stepsPerFlight = geometry.stepsPerFlight;\n this.landingSize = geometry.landingSize;\n this.flightRun = geometry.flightRun;\n this.totalHeight = geometry.totalHeight;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n SpiralStaircaseGeometry,\n type SpiralStaircaseGeometryOptions,\n} from \"../../geometry/architecture/SpiralStaircaseGeometry\";\n\nexport interface SpiralStaircaseOptions extends SpiralStaircaseGeometryOptions {\n /** Tread and riser tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Turret-style spiral staircase prefab — wraps {@link SpiralStaircaseGeometry}.\n */\nexport class SpiralStaircase extends Mesh<SpiralStaircaseGeometry, MeshStandardMaterial> {\n readonly innerRadius: number;\n readonly width: number;\n readonly outerRadius: number;\n readonly treadDepth: number;\n readonly riserHeight: number;\n readonly stepCount: number;\n readonly stepAngle: number;\n readonly totalHeight: number;\n readonly totalTurn: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: SpiralStaircaseOptions = {}) {\n const geometry = new SpiralStaircaseGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n side: DoubleSide,\n }),\n );\n\n this.innerRadius = geometry.innerRadius;\n this.width = geometry.width;\n this.outerRadius = geometry.outerRadius;\n this.treadDepth = geometry.treadDepth;\n this.riserHeight = geometry.riserHeight;\n this.stepCount = geometry.stepCount;\n this.stepAngle = geometry.stepAngle;\n this.totalHeight = geometry.totalHeight;\n this.totalTurn = geometry.totalTurn;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n StaircaseGeometry,\n type StaircaseGeometryOptions,\n} from \"../../geometry/architecture/StaircaseGeometry\";\n\nexport interface StaircaseOptions extends StaircaseGeometryOptions {\n /** Tread and riser tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Straight run staircase prefab — {@link StaircaseGeometry} with a wood-tone\n * default material.\n *\n * Local frame: centered on width, rises along +Y, runs along +Z.\n */\nexport class Staircase extends Mesh<StaircaseGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly riserHeight: number;\n readonly treadDepth: number;\n readonly stepCount: number;\n readonly totalHeight: number;\n readonly totalDepth: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: StaircaseOptions = {}) {\n const geometry = new StaircaseGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n // Open shell (no side stringers yet) — same as legacy staircase examples.\n side: DoubleSide,\n }),\n );\n\n this.width = geometry.width;\n this.riserHeight = geometry.riserHeight;\n this.treadDepth = geometry.treadDepth;\n this.stepCount = geometry.stepCount;\n this.totalHeight = geometry.totalHeight;\n this.totalDepth = geometry.totalDepth;\n }\n}","import {\n Color,\n ColorRepresentation,\n DoubleSide,\n Group,\n Mesh,\n MeshPhysicalMaterial,\n MeshStandardMaterial,\n Shape,\n ShapeGeometry,\n} from \"three\";\nimport {\n archedOpeningMetrics,\n buildArchedDiamondLatticeFrameGeometry,\n traceArchedOpeningOutline,\n type ArchedOpeningMetrics,\n type DiamondLatticeGrid,\n} from \"../../geometry/architecture/diamondLattice\";\nimport {\n ArchedDiamondLatticeWindowGeometry,\n type ArchedDiamondLatticeWindowGeometryOptions,\n} from \"../../geometry/architecture/ArchedDiamondLatticeWindowGeometry\";\n\nexport interface ArchedDiamondLatticeWindowOptions extends ArchedDiamondLatticeWindowGeometryOptions {\n /** Lead + outer frame tint. Defaults to `#0c0f14`. */\n leadColor?: ColorRepresentation;\n /** Optional glass pane centered in the lead depth (`z = 0`), visible from both sides. */\n glass?: boolean;\n glassColor?: ColorRepresentation;\n glassEmissive?: ColorRepresentation;\n glassEmissiveIntensity?: number;\n}\n\nconst ARCHED_SHAPE_CURVE_SEGMENTS = 48;\n\n/**\n * Arched diamond lattice window — diagonal lead cames analytically clipped to a\n * Tudor head opening, with an extruded frame ring. The lattice is real trimmed\n * geometry (no stencil mask), so it casts a correct arch-shaped shadow and any\n * collider derived from the mesh matches what's drawn.\n *\n * Local frame: centered on the opening, XY plane facing +Z. Lead is centered on\n * `z = 0`; optional glass sits in the same plane (both faces).\n */\nexport class ArchedDiamondLatticeWindow extends Group {\n readonly lattice: Mesh<ArchedDiamondLatticeWindowGeometry, MeshStandardMaterial>;\n readonly frame: Mesh;\n readonly glass?: Mesh<ShapeGeometry, MeshPhysicalMaterial>;\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n readonly opening: ArchedOpeningMetrics;\n\n constructor({\n leadColor = \"#0c0f14\",\n glass = false,\n glassColor = \"#6a7d8c\",\n glassEmissive,\n glassEmissiveIntensity = 0,\n width = 4.5,\n rectHeight = 4,\n archHeight,\n centerY = 0,\n leadThickness = 0.055,\n leadDepth = 0.11,\n ...geometryOptions\n }: ArchedDiamondLatticeWindowOptions = {}) {\n super();\n\n this.opening = archedOpeningMetrics({ width, rectHeight, archHeight, centerY });\n\n const geometry = new ArchedDiamondLatticeWindowGeometry({\n width,\n rectHeight,\n archHeight,\n centerY,\n leadThickness,\n leadDepth,\n ...geometryOptions,\n });\n this.cellsX = geometry.cellsX;\n this.cellsY = geometry.cellsY;\n this.fittedGrid = geometry.fittedGrid;\n\n const leadColorObj = new Color(leadColor);\n\n if (glass) {\n const openingShape = new Shape();\n traceArchedOpeningOutline(openingShape, this.opening);\n const openingGeo = new ShapeGeometry(openingShape, ARCHED_SHAPE_CURVE_SEGMENTS);\n const glassMaterial = new MeshPhysicalMaterial({\n color: new Color(glassColor),\n emissive: glassEmissive ? new Color(glassEmissive) : new Color(0x000000),\n emissiveIntensity: glassEmissiveIntensity,\n transparent: true,\n depthWrite: false,\n roughness: 0.08,\n metalness: 0,\n transmission: glassEmissive ? 0.5 : 0.88,\n thickness: leadDepth * 0.5,\n side: DoubleSide,\n });\n this.glass = new Mesh(openingGeo, glassMaterial);\n this.glass.renderOrder = 0;\n this.glass.castShadow = false;\n this.glass.receiveShadow = false;\n this.add(this.glass);\n }\n\n const latticeMaterial = new MeshStandardMaterial({\n color: leadColorObj,\n roughness: 0.7,\n metalness: 0.35,\n polygonOffset: true,\n polygonOffsetFactor: -1,\n polygonOffsetUnits: -1,\n });\n\n this.lattice = new Mesh(geometry, latticeMaterial);\n this.lattice.castShadow = true;\n this.lattice.renderOrder = 1;\n this.add(this.lattice);\n\n const frameGeo = buildArchedDiamondLatticeFrameGeometry(\n this.opening,\n leadThickness,\n leadDepth,\n );\n this.frame = new Mesh(\n frameGeo,\n new MeshStandardMaterial({\n color: leadColorObj,\n roughness: 0.7,\n metalness: 0.35,\n }),\n );\n this.frame.castShadow = true;\n this.frame.renderOrder = 2;\n this.add(this.frame);\n }\n}\n","import {\n Color,\n ColorRepresentation,\n DoubleSide,\n Group,\n Mesh,\n MeshPhysicalMaterial,\n MeshStandardMaterial,\n PlaneGeometry,\n} from \"three\";\nimport type { DiamondLatticeGrid } from \"../../geometry/architecture/diamondLattice\";\nimport {\n DiamondLatticeWindowGeometry,\n type DiamondLatticeWindowGeometryOptions,\n} from \"../../geometry/architecture/DiamondLatticeWindowGeometry\";\n\nexport interface DiamondLatticeWindowOptions extends DiamondLatticeWindowGeometryOptions {\n /** Lead + outer frame tint. Defaults to `#0c0f14`. */\n leadColor?: ColorRepresentation;\n /**\n * Optional glass pane centered in the lead depth (`z = 0`), visible from both sides.\n * Mad-science uses an emissive sky mesh in the scene instead.\n */\n glass?: boolean;\n glassColor?: ColorRepresentation;\n /** Glass emissive for moonlit / storm backlight. Defaults to off. */\n glassEmissive?: ColorRepresentation;\n glassEmissiveIntensity?: number;\n}\n\n/**\n * Diamond lattice window — diagonal lead cames with axis-aligned quarrels (`<>`).\n *\n * Local frame: centered on the opening, XY plane facing +Z. Lead is centered on\n * `z = 0`; optional glass sits in the same plane (both faces). Pair with\n * a scene-owned backing plane behind the wall.\n */\nexport class DiamondLatticeWindow extends Group {\n readonly lattice: Mesh<DiamondLatticeWindowGeometry, MeshStandardMaterial>;\n readonly glass?: Mesh<PlaneGeometry, MeshPhysicalMaterial>;\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: DiamondLatticeGrid;\n\n constructor({\n leadColor = \"#0c0f14\",\n glass = false,\n glassColor = \"#6a7d8c\",\n glassEmissive,\n glassEmissiveIntensity = 0,\n centerY = 0,\n leadDepth = 0.11,\n ...geometryOptions\n }: DiamondLatticeWindowOptions = {}) {\n super();\n\n const geometry = new DiamondLatticeWindowGeometry({\n centerY,\n leadDepth,\n ...geometryOptions,\n });\n this.cellsX = geometry.cellsX;\n this.cellsY = geometry.cellsY;\n this.fittedGrid = geometry.fittedGrid;\n\n const leadMaterial = new MeshStandardMaterial({\n color: new Color(leadColor),\n roughness: 0.7,\n metalness: 0.35,\n polygonOffset: true,\n polygonOffsetFactor: -1,\n polygonOffsetUnits: -1,\n });\n\n this.lattice = new Mesh(geometry, leadMaterial);\n this.lattice.castShadow = true;\n this.lattice.renderOrder = 1;\n this.add(this.lattice);\n\n if (glass) {\n const w = geometryOptions.width ?? 4.5;\n const h = geometryOptions.height ?? 5.5;\n const glassMaterial = new MeshPhysicalMaterial({\n color: new Color(glassColor),\n emissive: glassEmissive ? new Color(glassEmissive) : new Color(0x000000),\n emissiveIntensity: glassEmissiveIntensity,\n transparent: true,\n depthWrite: false,\n roughness: 0.08,\n metalness: 0,\n transmission: glassEmissive ? 0.5 : 0.88,\n thickness: leadDepth * 0.5,\n side: DoubleSide,\n });\n this.glass = new Mesh(new PlaneGeometry(w, h), glassMaterial);\n this.glass.position.y = centerY;\n this.glass.renderOrder = 0;\n this.glass.castShadow = false;\n this.glass.receiveShadow = false;\n this.add(this.glass);\n }\n }\n}","import {\n Color,\n ColorRepresentation,\n DoubleSide,\n Group,\n Mesh,\n MeshPhysicalMaterial,\n MeshStandardMaterial,\n PlaneGeometry,\n} from \"three\";\nimport type { GregorianLatticeGrid } from \"../../geometry/architecture/gregorianLattice\";\nimport {\n GregorianLatticeWindowGeometry,\n type GregorianLatticeWindowGeometryOptions,\n} from \"../../geometry/architecture/GregorianLatticeWindowGeometry\";\n\nexport interface GregorianLatticeWindowOptions extends GregorianLatticeWindowGeometryOptions {\n /** Frame + mullion tint. Defaults to `#5c4033` (wood). */\n mullionColor?: ColorRepresentation;\n /** Optional glass pane coplanar with the mullions (same Z center). */\n glass?: boolean;\n glassColor?: ColorRepresentation;\n glassEmissive?: ColorRepresentation;\n glassEmissiveIntensity?: number;\n}\n\n/**\n * Gregorian lattice window — rectangular pane grid with orthogonal mullions.\n *\n * Local frame: centered on the opening, XY plane facing +Z. Mullions and\n * optional glass share `z = 0`.\n */\nexport class GregorianLatticeWindow extends Group {\n readonly mullions: Mesh<GregorianLatticeWindowGeometry, MeshStandardMaterial>;\n readonly glass?: Mesh<PlaneGeometry, MeshPhysicalMaterial>;\n readonly cellsX: number;\n readonly cellsY: number;\n readonly fittedGrid: GregorianLatticeGrid;\n\n constructor({\n mullionColor = \"#5c4033\",\n glass = false,\n glassColor = \"#6a7d8c\",\n glassEmissive,\n glassEmissiveIntensity = 0,\n ...geometryOptions\n }: GregorianLatticeWindowOptions = {}) {\n super();\n\n const geometry = new GregorianLatticeWindowGeometry(geometryOptions);\n this.cellsX = geometry.cellsX;\n this.cellsY = geometry.cellsY;\n this.fittedGrid = geometry.fittedGrid;\n\n const mullionMaterial = new MeshStandardMaterial({\n color: new Color(mullionColor),\n roughness: 0.85,\n metalness: 0.05,\n });\n\n this.mullions = new Mesh(geometry, mullionMaterial);\n this.mullions.castShadow = true;\n this.mullions.renderOrder = 1;\n this.add(this.mullions);\n\n if (glass) {\n const w = geometryOptions.width ?? 4.5;\n const h = geometryOptions.height ?? 5.5;\n const glassMaterial = new MeshPhysicalMaterial({\n color: new Color(glassColor),\n emissive: glassEmissive ? new Color(glassEmissive) : new Color(0x000000),\n emissiveIntensity: glassEmissiveIntensity,\n transparent: true,\n depthWrite: false,\n roughness: 0.08,\n metalness: 0,\n transmission: glassEmissive ? 0.5 : 0.88,\n thickness: 0.02,\n side: DoubleSide,\n });\n this.glass = new Mesh(new PlaneGeometry(w, h), glassMaterial);\n this.glass.renderOrder = 0;\n this.glass.castShadow = false;\n this.glass.receiveShadow = false;\n this.add(this.glass);\n }\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { BookGeometry, type BookGeometryOptions } from \"../../geometry/books/BookGeometry\";\n\nexport interface BookOptions extends BookGeometryOptions {\n /** Cover tint. Defaults to `#8b0000`. */\n coverColor?: ColorRepresentation;\n /** Page block tint. Defaults to `#ffffff`. */\n pageColor?: ColorRepresentation;\n}\n\n/**\n * Book prefab — cover shell and page block with separate material groups.\n *\n * Local frame: spine at X=0, fore-edge at +X, sits on the Y=0 plane.\n */\nexport class Book extends Mesh<BookGeometry, MeshStandardMaterial[]> {\n readonly width: number;\n readonly height: number;\n readonly depth: number;\n readonly coverThickness: number;\n readonly pageIndent: number;\n\n constructor({\n coverColor = \"#8b0000\",\n pageColor = \"#ffffff\",\n ...geometryOptions\n }: BookOptions = {}) {\n const geometry = new BookGeometry(geometryOptions);\n\n super(geometry, [\n new MeshStandardMaterial({\n color: new Color(coverColor),\n metalness: 0.1,\n roughness: 0.7,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(pageColor),\n flatShading: true,\n }),\n ]);\n\n this.width = geometry.width;\n this.height = geometry.height;\n this.depth = geometry.depth;\n this.coverThickness = geometry.coverThickness;\n this.pageIndent = geometry.pageIndent;\n }\n}","import { DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { JarGeometry } from \"../../geometry/bottles/JarGeometry\";\n\n/**\n * Material indices\n * 0. Jar\n * 1. Cork\n */\nexport class Jar extends Mesh<JarGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new JarGeometry(), [\n new MeshStandardMaterial({\n color: 0x88ccaa,\n transparent: true,\n depthWrite: false,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.5,\n side: DoubleSide,\n }),\n new MeshStandardMaterial({\n color: 0x8b4513,\n roughness: 1.0,\n }),\n ]);\n }\n}\n","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { ColorPalette } from \"../../constants/ColorPalette\";\nimport { PotionBottleGeometry } from \"../../geometry/bottles/PotionBottleGeometry\";\n\n/**\n * Potion bottle, with optional liquid fill\n *\n * Material indices\n * 0. Bottle\n * 1. Cork\n * 2. Liquid (optional)\n */\nexport class PotionBottle extends Mesh<PotionBottleGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new PotionBottleGeometry(), [\n new MeshStandardMaterial({\n color: 0x88ccff,\n transparent: true,\n depthWrite: false,\n opacity: 0.5,\n roughness: 0.1,\n metalness: 0.3,\n }),\n new MeshStandardMaterial({\n color: 0x8b4513,\n roughness: 1.0,\n }),\n new MeshStandardMaterial({\n color: ColorPalette.PINK_SHERBET,\n transparent: true,\n depthWrite: false,\n opacity: 0.5,\n }),\n ]);\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshPhysicalMaterial } from \"three\";\nimport { WineBottleGeometry, type WineBottleGeometryOptions } from \"../../geometry/bottles/WineBottleGeometry\";\n\nexport interface WineBottleOptions extends WineBottleGeometryOptions {\n /** Glass tint. Defaults to `#556b2f`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Wine bottle prefab — translucent green glass.\n */\nexport class WineBottle extends Mesh<WineBottleGeometry, MeshPhysicalMaterial> {\n constructor({ color = \"#556b2f\", ...geometryOptions }: WineBottleOptions = {}) {\n super(\n new WineBottleGeometry(geometryOptions),\n new MeshPhysicalMaterial({\n color: new Color(color),\n roughness: 0.1,\n transmission: 0.9,\n thickness: 0.2,\n metalness: 0,\n clearcoat: 1.0,\n clearcoatRoughness: 0.1,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n CrossHeadstoneGeometry,\n type CrossHeadstoneGeometryOptions,\n} from \"../../geometry/cemetery/CrossHeadstoneGeometry\";\n\nexport interface CrossHeadstoneOptions extends CrossHeadstoneGeometryOptions {\n /** Stone tint. Defaults to `#777777`. */\n color?: ColorRepresentation;\n /** Surface roughness. Defaults to `0.8`. */\n roughness?: number;\n}\n\n/**\n * Cross headstone prefab.\n */\nexport class CrossHeadstone extends Mesh<CrossHeadstoneGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly height: number;\n\n constructor({ color = \"#777777\", roughness = 0.8, ...geometryOptions }: CrossHeadstoneOptions = {}) {\n const geometry = new CrossHeadstoneGeometry(geometryOptions);\n\n super(geometry, new MeshStandardMaterial({ color: new Color(color), roughness }));\n\n this.width = geometry.width;\n this.height = geometry.height;\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { MausoleumGeometry } from \"../../geometry/cemetery/MausoleumGeometry\";\n\n/**\n * Material indices:\n * 0. Base\n * 1. Building\n * 2. Roof\n * 3. Arched entrance\n */\nexport class Mausoleum extends Mesh<MausoleumGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(\n new MausoleumGeometry(),\n [\n new MeshStandardMaterial({ color: 0x808080, flatShading: true }), // Base\n new MeshStandardMaterial({ color: 0x696969, flatShading: true }), // Building\n new MeshStandardMaterial({ color: 0x505050, flatShading: true }), // Roof\n new MeshStandardMaterial({ color: 0x404040, flatShading: true }), // Arched entrance\n ],\n );\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n ObeliskHeadstoneGeometry,\n type ObeliskHeadstoneGeometryOptions,\n} from \"../../geometry/cemetery/ObeliskHeadstoneGeometry\";\n\nexport interface ObeliskHeadstoneOptions extends ObeliskHeadstoneGeometryOptions {\n /** Stone tint. Defaults to `#777777`. */\n color?: ColorRepresentation;\n /** Surface roughness. Defaults to `0.8`. */\n roughness?: number;\n}\n\n/**\n * Obelisk headstone prefab.\n */\nexport class ObeliskHeadstone extends Mesh<ObeliskHeadstoneGeometry, MeshStandardMaterial> {\n readonly totalHeight: number;\n\n constructor({ color = \"#777777\", roughness = 0.8, ...geometryOptions }: ObeliskHeadstoneOptions = {}) {\n const geometry = new ObeliskHeadstoneGeometry(geometryOptions);\n\n super(geometry, new MeshStandardMaterial({ color: new Color(color), roughness }));\n\n this.totalHeight = geometry.totalHeight;\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { RoundedHeadstoneGeometry } from \"../../geometry/cemetery/RoundedHeadstoneGeometry\";\n\nexport class RoundedHeadstone extends Mesh<RoundedHeadstoneGeometry, MeshStandardMaterial> {\n constructor(width = 0.6, height = 1.0, depth = 0.2, radius = 0.6) {\n super(\n new RoundedHeadstoneGeometry(width, height, depth, radius),\n new MeshStandardMaterial({ color: 0x777777, roughness: 0.8 })\n );\n }\n}\n","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { SquareHeadstoneGeometry } from \"../../geometry/cemetery/SquareHeadstoneGeometry\";\n\nexport class SquareHeadstone extends Mesh<SquareHeadstoneGeometry, MeshStandardMaterial> {\n constructor(width = 0.5, height = 0.8, depth = 0.15) {\n super(\n new SquareHeadstoneGeometry(width, height, depth),\n new MeshStandardMaterial({ color: 0x777777, roughness: 0.8 })\n );\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n StoneFencePostGeometry,\n type StoneFencePostGeometryOptions,\n} from \"../../geometry/fence/StoneFencePostGeometry\";\n\nexport interface StoneFencePostOptions extends StoneFencePostGeometryOptions {\n /** Stone tint. Defaults to `#8b7d7b`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Stone fence post prefab.\n */\nexport class StoneFencePost extends Mesh<StoneFencePostGeometry, MeshStandardMaterial> {\n readonly height: number;\n\n constructor({ color = \"#8b7d7b\", ...geometryOptions }: StoneFencePostOptions = {}) {\n const geometry = new StoneFencePostGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({ color: new Color(color), flatShading: true }),\n );\n\n this.height = geometry.height;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n WroughtIronBarGeometry,\n type WroughtIronBarGeometryOptions,\n} from \"../../geometry/fence/WroughtIronBarGeometry\";\n\nexport interface WroughtIronBarOptions extends WroughtIronBarGeometryOptions {\n /** Iron tint. Defaults to `#333333`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Wrought-iron fence post prefab.\n */\nexport class WroughtIronBar extends Mesh<WroughtIronBarGeometry, MeshStandardMaterial> {\n readonly barHeight: number;\n\n constructor({ color = \"#333333\", ...geometryOptions }: WroughtIronBarOptions = {}) {\n const geometry = new WroughtIronBarGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n metalness: 0.8,\n roughness: 0.4,\n }),\n );\n\n this.barHeight = geometry.barHeight;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n WroughtIronFenceGeometry,\n type WroughtIronFenceGeometryOptions,\n} from \"../../geometry/fence/WroughtIronFenceGeometry\";\n\nexport interface WroughtIronFenceOptions extends WroughtIronFenceGeometryOptions {\n /** Iron tint. Defaults to `#333333`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Wrought-iron fence run prefab.\n */\nexport class WroughtIronFence extends Mesh<WroughtIronFenceGeometry, MeshStandardMaterial> {\n readonly count: number;\n\n constructor({ color = \"#333333\", ...geometryOptions }: WroughtIronFenceOptions = {}) {\n const geometry = new WroughtIronFenceGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n metalness: 0.8,\n roughness: 0.4,\n }),\n );\n\n this.count = geometry.count;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { BookshelfGeometry, type BookshelfGeometryOptions } from \"../../geometry/furniture/BookshelfGeometry\";\n\nexport interface BookshelfOptions extends BookshelfGeometryOptions {\n /** Frame tint. Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Bookshelf prefab — framed shelving unit.\n */\nexport class Bookshelf extends Mesh<BookshelfGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly height: number;\n\n constructor({ color = \"#8b4513\", ...geometryOptions }: BookshelfOptions = {}) {\n const geometry = new BookshelfGeometry(geometryOptions);\n\n super(geometry, new MeshStandardMaterial({ color: new Color(color) }));\n\n this.width = geometry.width;\n this.height = geometry.height;\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { DeskGeometry } from \"../../geometry/furniture/DeskGeometry\";\n\n/**\n * Material indices:\n * 0. Desk surface\n * 1. Desk legs\n */\nexport class Desk extends Mesh<DeskGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new DeskGeometry(), [\n new MeshStandardMaterial({ color: 0x8b5a2b }), // Desk surface\n new MeshStandardMaterial({ color: 0x4b3621 }), // Desk legs\n ]);\n }\n}\n","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { LeafGeometry, type LeafGeometryOptions } from \"../../geometry/leafs/LeafGeometry\";\n\nexport interface LeafOptions extends LeafGeometryOptions {\n /** Leaf tint. Defaults to `#a8702c`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Folded autumn leaf prefab — {@link LeafGeometry} with flat-shaded double-sided\n * material matching the graveyard blowing-leaves look.\n *\n * Local frame: tip at +Y, base at −Y, fold rises along +Z.\n */\nexport class Leaf extends Mesh<LeafGeometry, MeshStandardMaterial> {\n readonly size: number;\n readonly lift: number;\n\n constructor({ color = \"#a8702c\", ...geometryOptions }: LeafOptions = {}) {\n const geometry = new LeafGeometry(geometryOptions);\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.05,\n flatShading: true,\n side: DoubleSide,\n }),\n );\n\n this.size = geometry.size;\n this.lift = geometry.lift;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { CandleGeometry, type CandleGeometryOptions } from \"../../geometry/lighting/CandleGeometry\";\n\nexport interface CandleOptions extends CandleGeometryOptions {\n /** Wax stick tint. Defaults to `#ffffff`. */\n stickColor?: ColorRepresentation;\n /** Flame surface tint. Defaults to `#ffd700`. */\n flameColor?: ColorRepresentation;\n /** Flame emissive tint. Defaults to `#ffa500`. */\n flameEmissive?: ColorRepresentation;\n /** Flame emissive strength. Defaults to `0.35`. */\n flameEmissiveIntensity?: number;\n}\n\n/**\n * Candle prefab — wax stick and emissive flame (separate material groups).\n */\nexport class Candle extends Mesh<CandleGeometry, MeshStandardMaterial[]> {\n readonly height: number;\n\n constructor({\n stickColor = \"#ffffff\",\n flameColor = \"#ffd700\",\n flameEmissive = \"#ffa500\",\n flameEmissiveIntensity = 0.35,\n ...geometryOptions\n }: CandleOptions = {}) {\n const geometry = new CandleGeometry(geometryOptions);\n\n super(geometry, [\n new MeshStandardMaterial({ color: new Color(stickColor), flatShading: true }),\n new MeshStandardMaterial({\n color: new Color(flameColor),\n emissive: new Color(flameEmissive),\n emissiveIntensity: flameEmissiveIntensity,\n flatShading: true,\n toneMapped: false,\n }),\n ]);\n\n this.height = geometry.height;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { FlameGeometry, type FlameGeometryOptions } from \"../../geometry/lighting/FlameGeometry\";\n\nexport interface FlameOptions extends FlameGeometryOptions {\n /** Surface tint. Defaults to `#ffd700`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffa500`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.35`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Emissive flame prefab — parametric teardrop volume for candles and lanterns.\n *\n * Local frame: base at Y=0, tip at Y=`height`.\n */\nexport class Flame extends Mesh<FlameGeometry, MeshStandardMaterial> {\n readonly height: number;\n readonly radius: number;\n readonly segmentsU: number;\n readonly segmentsV: number;\n\n constructor({\n color = \"#ffd700\",\n emissive = \"#ffa500\",\n emissiveIntensity = 0.35,\n ...geometryOptions\n }: FlameOptions = {}) {\n const geometry = new FlameGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n flatShading: true,\n toneMapped: false,\n }),\n );\n\n this.height = geometry.height;\n this.radius = geometry.radius;\n this.segmentsU = geometry.segmentsU;\n this.segmentsV = geometry.segmentsV;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n HangingLanternGeometry,\n type HangingLanternGeometryOptions,\n} from \"../../geometry/lighting/HangingLanternGeometry\";\n\nexport interface HangingLanternOptions extends HangingLanternGeometryOptions {\n /** Wrought-iron tint for mount and cage. Defaults to `#171a1f`. */\n color?: ColorRepresentation;\n /** Mount iron tint (chain + cap). Defaults to `color`. */\n mountColor?: ColorRepresentation;\n /** Cage strut tint. Defaults to `color`. */\n cageColor?: ColorRepresentation;\n /** Inner lamp tint (emissive octahedron). Defaults to `#ffb45a`. */\n lampColor?: ColorRepresentation;\n /** Inner lamp emissive strength. Defaults to `1.4`. */\n lampEmissiveIntensity?: number;\n /** Inner lamp opacity for a glass-pane read. Defaults to `0.88`. */\n lampOpacity?: number;\n}\n\n/**\n * Hanging wrought-iron lantern — open cage struts around a solid emissive\n * inner octahedron (glass-pane lamp). Mount, cage, and lamp use separate\n * material groups. Pair {@link GlowHalo} and {@link FlameFlickerEffect} at\n * `cageCenterY` for bloom and flicker.\n *\n * Local frame: origin at the chain top (hang point).\n */\nexport class HangingLantern extends Mesh<HangingLanternGeometry, MeshStandardMaterial[]> {\n readonly drop: number;\n readonly cageCenterY: number;\n\n constructor({\n color = \"#171a1f\",\n mountColor,\n cageColor,\n lampColor = \"#ffb45a\",\n lampEmissiveIntensity = 1.4,\n lampOpacity = 0.88,\n inner = true,\n ...geometryOptions\n }: HangingLanternOptions = {}) {\n const geometry = new HangingLanternGeometry({ inner, ...geometryOptions });\n const lamp = new Color(lampColor);\n\n const materials: MeshStandardMaterial[] = [\n new MeshStandardMaterial({\n color: new Color(mountColor ?? color),\n metalness: 0.7,\n roughness: 0.5,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(cageColor ?? color),\n metalness: 0.7,\n roughness: 0.5,\n flatShading: true,\n }),\n ];\n\n if (inner) {\n materials.push(\n new MeshStandardMaterial({\n color: lamp,\n emissive: lamp,\n emissiveIntensity: lampEmissiveIntensity,\n transparent: lampOpacity < 1,\n opacity: lampOpacity,\n roughness: 0.35,\n metalness: 0,\n flatShading: true,\n side: DoubleSide,\n toneMapped: false,\n }),\n );\n }\n\n super(geometry, materials);\n\n this.drop = geometry.drop;\n this.cageCenterY = geometry.cageCenterY;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n WallSconceGeometry,\n type WallSconceGeometryOptions,\n} from \"../../geometry/lighting/WallSconceGeometry\";\n\nexport interface WallSconceOptions extends WallSconceGeometryOptions {\n /** Wrought-iron tint for mount and frame. Defaults to `#1c1e24`. */\n color?: ColorRepresentation;\n /** Mount iron tint (plate + bracket). Defaults to `color`. */\n mountColor?: ColorRepresentation;\n /** Frame iron tint (cap + bowl). Defaults to `color`. */\n frameColor?: ColorRepresentation;\n /** Glass chimney tint. Defaults to `#e8a058`. */\n lampColor?: ColorRepresentation;\n /** Glass emissive strength. Defaults to `1.4`. */\n lampEmissiveIntensity?: number;\n /** Glass opacity. Defaults to `0.88`. */\n lampOpacity?: number;\n}\n\n/**\n * Wall-mounted oil-lamp sconce — iron mount and cap/bowl frame around an\n * emissive glass chimney. Pair {@link GlowHalo} and {@link FlameFlickerEffect}\n * at `(lightCenterX, lightCenterY, lightCenterZ)` for bloom and flicker.\n *\n * Local frame: faces +X from a −X wall.\n */\nexport class WallSconce extends Mesh<WallSconceGeometry, MeshStandardMaterial[]> {\n readonly lightCenterX: number;\n readonly lightCenterY: number;\n readonly lightCenterZ: number;\n\n constructor({\n color = \"#1c1e24\",\n mountColor,\n frameColor,\n lampColor = \"#e8a058\",\n lampEmissiveIntensity = 1.4,\n lampOpacity = 0.88,\n inner = true,\n ...geometryOptions\n }: WallSconceOptions = {}) {\n const geometry = new WallSconceGeometry({ inner, ...geometryOptions });\n const lamp = new Color(lampColor);\n\n const materials: MeshStandardMaterial[] = [\n new MeshStandardMaterial({\n color: new Color(mountColor ?? color),\n metalness: 0.65,\n roughness: 0.55,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(frameColor ?? color),\n metalness: 0.65,\n roughness: 0.55,\n flatShading: true,\n }),\n ];\n\n if (inner) {\n materials.push(\n new MeshStandardMaterial({\n color: lamp,\n emissive: lamp,\n emissiveIntensity: lampEmissiveIntensity,\n transparent: lampOpacity < 1,\n opacity: lampOpacity,\n roughness: 0.35,\n metalness: 0,\n flatShading: true,\n side: DoubleSide,\n toneMapped: false,\n }),\n );\n }\n\n super(geometry, materials);\n\n this.lightCenterX = geometry.lightCenterX;\n this.lightCenterY = geometry.lightCenterY;\n this.lightCenterZ = geometry.lightCenterZ;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { LanternGeometry, type LanternGeometryOptions } from \"../../geometry/lighting/LanternGeometry\";\n\nexport interface LanternOptions extends LanternGeometryOptions {\n /** Frame tint (base, roof, handle). Defaults to `#8b4513`. */\n color?: ColorRepresentation;\n /** Glass lamp tint. Defaults to `#ffd700`. */\n lampColor?: ColorRepresentation;\n /** Glass emissive strength. Defaults to `1.2`. */\n lampEmissiveIntensity?: number;\n /** Glass opacity. Defaults to `0.75`. */\n lampOpacity?: number;\n}\n\n/**\n * Tabletop lantern — frame around an emissive glass body. Geometry only; add\n * {@link GlowHalo} and {@link FlameFlickerEffect} at `lampCenterY` in the\n * scene.\n *\n * Local frame: sits on the Y=0 plane.\n */\nexport class Lantern extends Mesh<LanternGeometry, MeshStandardMaterial[]> {\n readonly lampCenterY: number;\n\n constructor({\n color = \"#8b4513\",\n lampColor = \"#ffd700\",\n lampEmissiveIntensity = 1.2,\n lampOpacity = 0.75,\n inner = true,\n ...geometryOptions\n }: LanternOptions = {}) {\n\n const geometry = new LanternGeometry({ inner, ...geometryOptions });\n const lamp = new Color(lampColor);\n\n const materials: MeshStandardMaterial[] = [\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.85,\n metalness: 0.04,\n flatShading: true,\n }),\n ];\n\n if (inner) {\n materials.push(\n new MeshStandardMaterial({\n color: lamp,\n emissive: lamp,\n emissiveIntensity: lampEmissiveIntensity,\n transparent: lampOpacity < 1,\n opacity: lampOpacity,\n roughness: 0.35,\n metalness: 0,\n flatShading: true,\n side: DoubleSide,\n toneMapped: false,\n }),\n );\n }\n\n super(geometry, materials);\n\n this.lampCenterY = geometry.lampCenterY;\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { BoulderGeometry, type BoulderGeometryOptions } from \"../../geometry/rocks/BoulderGeometry\";\n\nexport interface BoulderOptions extends BoulderGeometryOptions {\n /** Stone tint. Defaults to `#6f6f6f`. */\n color?: ColorRepresentation;\n /** Faceted low-poly shading. Defaults to `true`. */\n flatShading?: boolean;\n}\n\n/**\n * Boulder prefab — a {@link BoulderGeometry} lumped by coherent 3D noise, with a\n * matte flat-shaded stone material. Centered on the origin; casts and receives\n * shadows. Vary `seed` per instance for a field of unique boulders.\n */\nexport class Boulder extends Mesh<BoulderGeometry, MeshStandardMaterial> {\n readonly radius: number;\n\n constructor({ color = \"#6f6f6f\", flatShading = true, ...geometryOptions }: BoulderOptions = {}) {\n const geometry = new BoulderGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 1,\n metalness: 0,\n flatShading,\n }),\n );\n\n this.radius = geometry.radius;\n this.castShadow = true;\n this.receiveShadow = true;\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { MossyRockGeometry, type MossyRockGeometryOptions } from \"../../geometry/rocks/MossyRockGeometry\";\n\nexport interface MossyRockOptions extends MossyRockGeometryOptions {\n /** Rock tint. Defaults to `#808080`. */\n rockColor?: ColorRepresentation;\n /** Moss tint. Defaults to `#4b8b3b`. */\n mossColor?: ColorRepresentation;\n /** Moss opacity. Defaults to `0.8`. */\n mossOpacity?: number;\n}\n\n/**\n * Mossy rock prefab — grey stone with a translucent green moss shell.\n *\n * Material groups: `0` rock, `1` moss.\n */\nexport class MossyRock extends Mesh<MossyRockGeometry, MeshStandardMaterial[]> {\n constructor({\n rockColor = \"#808080\",\n mossColor = \"#4b8b3b\",\n mossOpacity = 0.8,\n ...geometryOptions\n }: MossyRockOptions = {}) {\n super(new MossyRockGeometry(geometryOptions), [\n new MeshStandardMaterial({ color: new Color(rockColor), flatShading: true }),\n new MeshStandardMaterial({\n color: new Color(mossColor),\n flatShading: true,\n opacity: mossOpacity,\n transparent: mossOpacity < 1,\n }),\n ]);\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { RockGeometry, type RockGeometryOptions } from \"../../geometry/rocks/RockGeometry\";\n\nexport interface RockOptions extends RockGeometryOptions {\n /** Stone tint. Defaults to `#808080`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Single rock prefab — noisy sphere mesh.\n */\nexport class Rock extends Mesh<RockGeometry, MeshStandardMaterial> {\n constructor({ color = \"#808080\", ...geometryOptions }: RockOptions = {}) {\n super(\n new RockGeometry(geometryOptions),\n new MeshStandardMaterial({ color: new Color(color), flatShading: true }),\n );\n }\n}","import { ConeGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial } from \"three\";\n\nclass BunsenBurner extends Group {\n constructor() {\n super();\n\n // Base geometry\n const baseGeometry = new CylinderGeometry(0.3, 0.4, 0.1, 16);\n const baseMaterial = new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.6,\n metalness: 0.3,\n });\n const base = new Mesh(baseGeometry, baseMaterial);\n base.position.y = 0.05;\n\n // Burner tube geometry\n const tubeGeometry = new CylinderGeometry(0.1, 0.1, 0.7, 16);\n const tubeMaterial = new MeshStandardMaterial({\n color: 0x555555,\n roughness: 0.5,\n metalness: 0.4,\n });\n const tube = new Mesh(tubeGeometry, tubeMaterial);\n tube.position.y = 0.4;\n\n // Flame geometry\n const flameGeometry = new ConeGeometry(0.075, 0.2, 16);\n const flameMaterial = new MeshStandardMaterial({\n color: 0xff5500,\n emissive: 0xff5500,\n emissiveIntensity: 0.6,\n transparent: true,\n opacity: 0.8,\n });\n const flame = new Mesh(flameGeometry, flameMaterial);\n flame.position.y = 0.8;\n\n this.add(base, tube, flame);\n }\n}\n\nexport { BunsenBurner };\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial, SphereGeometry } from \"three\";\n\nclass ElectricPanel extends Group {\n constructor() {\n super();\n\n const panelGeometry = new BoxGeometry(3, 4, 0.1);\n const panelMaterial = new MeshStandardMaterial({\n color: 0x2e2e2e,\n roughness: 0.8,\n metalness: 0.6,\n });\n\n const switchGeometry = new BoxGeometry(0.2, 0.5, 0.2);\n const switchMaterial = new MeshStandardMaterial({\n color: 0xaaaaaa,\n roughness: 0.5,\n metalness: 0.7,\n });\n\n const dialGeometry = new CylinderGeometry(0.3, 0.3, 0.1, 16);\n const dialMaterial = new MeshStandardMaterial({\n color: 0x555555,\n roughness: 0.7,\n metalness: 0.5,\n });\n\n const panel = new Mesh(panelGeometry, panelMaterial);\n\n for (let i = -1; i <= 1; i++) {\n const toggleSwitch = new Mesh(switchGeometry, switchMaterial);\n toggleSwitch.position.set(i, 1.5, 0.1);\n panel.add(toggleSwitch);\n }\n\n const dial = new Mesh(dialGeometry, dialMaterial);\n dial.rotation.x = Math.PI / 2;\n dial.position.set(0, 0.5, 0.15);\n panel.add(dial);\n\n const lightGeometry = new SphereGeometry(0.15, 8, 8);\n const lightMaterial = new MeshStandardMaterial({\n color: 0xff0000,\n emissive: 0xff0000,\n emissiveIntensity: 0.5,\n });\n const light = new Mesh(lightGeometry, lightMaterial);\n light.position.set(0, -1, 0.1);\n panel.add(light);\n\n this.add(panel);\n }\n}\n\nexport { ElectricPanel };","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshPhysicalMaterial } from \"three\";\nimport {\n ErlenmeyerFlaskGeometry,\n type ErlenmeyerFlaskGeometryOptions,\n} from \"../../geometry/science/ErlenmeyerFlaskGeometry\";\n\nexport interface ErlenmeyerFlaskOptions extends ErlenmeyerFlaskGeometryOptions {\n /** Glass tint. Defaults to `#88ccff`. */\n color?: ColorRepresentation;\n /** Glass opacity. Defaults to `0.4`. */\n opacity?: number;\n}\n\n/**\n * Erlenmeyer flask prefab — translucent glass vessel.\n */\nexport class ErlenmeyerFlask extends Mesh<ErlenmeyerFlaskGeometry, MeshPhysicalMaterial> {\n constructor({\n color = \"#88ccff\",\n opacity = 0.4,\n ...geometryOptions\n }: ErlenmeyerFlaskOptions = {}) {\n super(\n new ErlenmeyerFlaskGeometry(geometryOptions),\n new MeshPhysicalMaterial({\n color: new Color(color),\n transparent: true,\n opacity,\n roughness: 0.1,\n metalness: 0.1,\n reflectivity: 0.8,\n transmission: 0.9,\n side: DoubleSide,\n }),\n );\n }\n}","import { FlorenceFlaskGeometry } from \"../../geometry/science/FlorenceFlaskGeometry\";\nimport { DoubleSide, Mesh, MeshPhysicalMaterial } from \"three\";\n\nexport class FlorenceFlask extends Mesh<FlorenceFlaskGeometry, MeshPhysicalMaterial> {\n constructor() {\n super(\n new FlorenceFlaskGeometry(),\n new MeshPhysicalMaterial({\n color: 0x88ccff,\n transparent: true,\n depthWrite: false,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.1,\n reflectivity: 0.8,\n transmission: 0.9,\n side: DoubleSide,\n }),\n );\n }\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial, SphereGeometry } from \"three\";\n\nclass LeverPanel extends Group {\n constructor() {\n super();\n\n // New panel for levers\n const leverPanelGeometry = new BoxGeometry(2, 3, 0.1);\n const leverPanelMaterial = new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.8,\n metalness: 0.5,\n });\n const leverPanel = new Mesh(leverPanelGeometry, leverPanelMaterial);\n\n // Lever geometry\n const leverBaseGeometry = new CylinderGeometry(0.1, 0.1, 0.2, 8);\n const leverHandleGeometry = new CylinderGeometry(0.05, 0.05, 1, 8);\n\n // Lever material\n const leverMaterial = new MeshStandardMaterial({\n color: 0xaaaaaa,\n roughness: 0.5,\n metalness: 0.7,\n });\n\n // Create multiple levers\n const levers = [];\n for (let i = -0.5; i <= 0.5; i += 0.5) {\n // Lever base\n const leverBase = new Mesh(leverBaseGeometry, leverMaterial);\n leverBase.position.set(i, 1, 0.1);\n\n // Lever handle\n const leverHandle = new Mesh(leverHandleGeometry, leverMaterial);\n leverHandle.position.y = 0.5; // Position handle on top of the base\n // leverHandle.rotation.x = Math.PI / 4; // Tilt forward along the x-axis\n leverBase.add(leverHandle);\n\n // Group base and handle as a lever\n levers.push(leverHandle);\n this.add(leverBase);\n }\n\n // Position the panel in the scene\n this.add(leverPanel);\n }\n}\n\nexport { LeverPanel };\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial } from \"three\";\n\nclass Microscope extends Group {\n constructor() {\n super();\n\n // Base geometry\n const baseGeometry = new BoxGeometry(1, 0.2, 0.5);\n const baseMaterial = new MeshStandardMaterial({\n color: 0x444444,\n roughness: 0.6,\n metalness: 0.3,\n });\n const base = new Mesh(baseGeometry, baseMaterial);\n base.position.y = 0.1;\n\n // Arm geometry\n const armGeometry = new BoxGeometry(0.2, 1, 0.2);\n const arm = new Mesh(armGeometry, baseMaterial);\n arm.position.set(0, 0.6, -0.2);\n\n // Eyepiece geometry\n const eyepieceGeometry = new CylinderGeometry(0.1, 0.1, 0.4, 8);\n const eyepieceMaterial = new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.5,\n metalness: 0.6,\n });\n const eyepiece = new Mesh(eyepieceGeometry, eyepieceMaterial);\n eyepiece.position.set(0, 1.1, -0.35);\n eyepiece.rotation.x = -Math.PI / 4; // Angle the eyepiece for viewing\n\n // Stage geometry\n const stageGeometry = new BoxGeometry(0.6, 0.1, 0.6);\n const stageMaterial = new MeshStandardMaterial({\n color: 0x555555,\n roughness: 0.8,\n metalness: 0.2,\n });\n const stage = new Mesh(stageGeometry, stageMaterial);\n stage.position.set(0, 0.6, 0);\n\n // Assemble microscope\n this.add(base, arm, eyepiece, stage);\n }\n}\n\nexport { Microscope };\n","import { CylinderGeometry, DoubleSide, Group, Mesh, MeshStandardMaterial } from \"three\";\nimport { MortarGeometry } from \"../../geometry/science/MortarGeometry\";\n\nclass MortarAndPestle extends Group {\n constructor() {\n super();\n\n // Mortar geometry\n const mortarGeometry = new MortarGeometry();\n\n // Pestle geometry\n const pestleGeometry = new CylinderGeometry(0.2, 0.3, 1.5, 8);\n pestleGeometry.translate(0, 0.75, 0); // Offset to make the end rounded\n\n // Materials\n const mortarMaterial = new MeshStandardMaterial({\n color: 0x5c4033, // Dark earthy tone\n roughness: 1.0,\n metalness: 0.0,\n side: DoubleSide, // Render inside and outside\n });\n\n const pestleMaterial = new MeshStandardMaterial({\n color: 0x8b5a2b, // Slightly lighter earthy color\n roughness: 0.8,\n metalness: 0.1,\n });\n\n // Meshes\n const mortar = new Mesh(mortarGeometry, mortarMaterial);\n mortar.castShadow = true;\n const pestle = new Mesh(pestleGeometry, pestleMaterial);\n pestle.castShadow = true;\n\n // Position and rotate the pestle to rest in the mortar\n pestle.position.set(0.3, 1.3, 0);\n pestle.rotation.z = Math.PI / 4;\n\n // Group for easy manipulation\n this.add(mortar, pestle);\n }\n}\n\nexport { MortarAndPestle };\n","import { BoxGeometry, Mesh, MeshStandardMaterial } from \"three\";\n\nexport interface PanelOptions {\n width?: number;\n height?: number;\n depth?: number;\n}\n\n/**\n * Prefab for a panel.\n * Designed to be used as a control panel for switches, lights, levels, dials, and gauges.\n */\nexport class Panel extends Mesh {\n public geometry: BoxGeometry;\n public material: MeshStandardMaterial;\n\n constructor({ width = 3, height = 4, depth = 0.1 }: PanelOptions = {}) {\n super();\n\n this.geometry = new BoxGeometry(width, height, depth);\n this.material = new MeshStandardMaterial({\n color: 0x2e2e2e,\n roughness: 0.8,\n metalness: 0.6,\n });\n }\n}\n","import { Mesh, MeshStandardMaterial, SphereGeometry } from \"three\";\n\nexport interface PanelLightOptions {\n radius?: number;\n color?: number;\n emissive?: number;\n emissiveIntensity?: number;\n}\n\n/**\n * Prefab for a panel light.\n * Designed to appear as a LED light\n */\nexport class PanelLight extends Mesh {\n public geometry: SphereGeometry;\n public material: MeshStandardMaterial;\n\n constructor({\n radius = 0.15, //\n color = 0xffc7c7,\n emissive = 0xff0000,\n emissiveIntensity = 0.5,\n }: PanelLightOptions = {}) {\n super();\n\n this.geometry = new SphereGeometry(radius, 8, 8);\n this.material = new MeshStandardMaterial({\n color: color,\n emissive: emissive,\n emissiveIntensity: emissiveIntensity,\n });\n }\n}\n","import { CatmullRomCurve3, Group, Mesh, MeshStandardMaterial, TubeGeometry, Vector3 } from \"three\";\n\nclass SpiralTube extends Group {\n constructor() {\n super();\n\n const spiralLength = 100;\n const heightIncrement = 0.05;\n const curve = new CatmullRomCurve3(\n Array.from({ length: spiralLength }, (_, i) => {\n const angle = i * 0.2;\n return new Vector3(\n Math.cos(angle) * 0.4,\n i * heightIncrement,\n Math.sin(angle) * 0.4,\n );\n }),\n );\n\n const tubeGeometry = new TubeGeometry(curve, 200, 0.1, 8, false);\n const glassMaterial = new MeshStandardMaterial({\n color: 0x88ccff,\n transparent: true,\n opacity: 0.3,\n roughness: 0.1,\n metalness: 0.2,\n emissive: 0x88ccff,\n emissiveIntensity: 0.2,\n });\n const multiSpiralTube = new Mesh(tubeGeometry, glassMaterial);\n this.add(multiSpiralTube);\n }\n}\n\nexport { SpiralTube };","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { StandGeometry, type StandGeometryOptions } from \"../../geometry/science/StandGeometry\";\n\nexport interface StandOptions extends StandGeometryOptions {\n /** Metal tint. Defaults to `#888888`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Laboratory stand prefab — ring and legs.\n */\nexport class Stand extends Mesh<StandGeometry, MeshStandardMaterial> {\n constructor({ color = \"#888888\", ...geometryOptions }: StandOptions = {}) {\n super(\n new StandGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 0.7,\n metalness: 0.3,\n }),\n );\n }\n}","import { DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport { TeslaCoilGeometry } from \"../../geometry/science/TeslaCoilGeometry\";\n\n/**\n * Material indices\n * 0: Base\n * 1: Coil\n */\nexport class TeslaCoil extends Mesh<TeslaCoilGeometry, MeshStandardMaterial[]> {\n constructor() {\n super(new TeslaCoilGeometry(), [\n new MeshStandardMaterial({\n color: 0x333333,\n roughness: 0.6,\n metalness: 0.5,\n }),\n new MeshStandardMaterial({\n color: 0xff6600,\n roughness: 0.5,\n metalness: 0.8,\n side: DoubleSide,\n }),\n ]);\n }\n}\n","import { DoubleSide, Mesh, MeshPhysicalMaterial } from \"three\";\nimport { TestTubeGeometry } from \"../../geometry/science/TestTubeGeometry\";\n\nexport class TestTube extends Mesh<TestTubeGeometry, MeshPhysicalMaterial> {\n constructor(radiusTop = 0.2, radiusBottom = 0.2, height = 3, segments = 32) {\n super(\n new TestTubeGeometry(radiusTop, radiusBottom, height, segments),\n new MeshPhysicalMaterial({\n color: 0x88ccff,\n transparent: true,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.1,\n reflectivity: 0.8,\n transmission: 0.9,\n depthWrite: false,\n side: DoubleSide,\n }),\n );\n }\n}\n","import { BoxGeometry, Color, ColorRepresentation, DoubleSide, Group, Mesh, MeshStandardMaterial } from \"three\";\nimport { TestTubeGeometry } from \"../../geometry/science/TestTubeGeometry\";\n\nexport interface TestTubeRackOptions {\n /** Number of tubes. Defaults to `3`. */\n count?: number;\n /** Liquid color per tube; cycles when fewer entries than tubes. */\n colors?: ColorRepresentation[];\n}\n\n/**\n * Wooden rack with test tubes and emissive liquid fills.\n *\n * Glass shells use `DoubleSide` and `depthWrite: false`; liquid draws first\n * (`renderOrder` 1), glass second (`renderOrder` 2) so fills stay visible at\n * most camera angles.\n */\nexport class TestTubeRack extends Group {\n readonly count: number;\n\n constructor({\n count = 3,\n colors = [\"#00ffaa\", \"#ff00aa\", \"#aa00ff\"],\n }: TestTubeRackOptions = {}) {\n super();\n\n this.count = count;\n\n const rackGeometry = new BoxGeometry(3, 0.2, 1);\n const rackMaterial = new MeshStandardMaterial({\n color: 0x8b4513,\n roughness: 0.7,\n metalness: 0.3,\n });\n const rack = new Mesh(rackGeometry, rackMaterial);\n rack.position.y = 0.5;\n rack.castShadow = true;\n\n const testTubeGeometry = new TestTubeGeometry(0.1, 0.1, 1, 16);\n const glassMaterial = new MeshStandardMaterial({\n color: 0xaaaaaa,\n transparent: true,\n opacity: 0.4,\n roughness: 0.1,\n metalness: 0.5,\n depthWrite: false,\n side: DoubleSide,\n });\n\n for (let i = 0; i < count; i++) {\n const testTube = new Mesh(testTubeGeometry, glassMaterial);\n const xPosition = (i - (count - 1) / 2) * 0.8;\n testTube.position.set(xPosition, 1, 0);\n testTube.castShadow = true;\n testTube.renderOrder = 2;\n\n const liquidGeometry = new TestTubeGeometry(0.099, 0.099, 0.5, 16, false);\n const liquidColor = colors[i % colors.length]!;\n const liquidMaterial = new MeshStandardMaterial({\n color: new Color(liquidColor),\n emissive: new Color(liquidColor),\n emissiveIntensity: 0.5,\n transparent: true,\n opacity: 0.6,\n depthWrite: false,\n side: DoubleSide,\n });\n\n const liquid = new Mesh(liquidGeometry, liquidMaterial);\n liquid.position.set(0, -0.25, 0);\n liquid.renderOrder = 1;\n testTube.add(liquid);\n\n rack.add(testTube);\n }\n\n this.add(rack);\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { BurstGeometry, type BurstGeometryOptions } from \"../../geometry/shapes/BurstGeometry\";\n\nexport interface BurstOptions extends BurstGeometryOptions {\n /** Surface tint. Defaults to `#ffff00`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffd700`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.25`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Burst shape prefab.\n */\nexport class Burst extends Mesh<BurstGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#ffff00\",\n emissive = \"#ffd700\",\n emissiveIntensity = 0.25,\n ...geometryOptions\n }: BurstOptions = {}) {\n super(\n new BurstGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { GearGeometry, type GearGeometryOptions } from \"../../geometry/shapes/GearGeometry\";\n\nexport interface GearOptions extends GearGeometryOptions {\n /** Metal tint. Defaults to `#aaaaaa`. */\n color?: ColorRepresentation;\n}\n\n/**\n * Gear shape prefab.\n */\nexport class Gear extends Mesh<GearGeometry, MeshStandardMaterial> {\n constructor({ color = \"#aaaaaa\", ...geometryOptions }: GearOptions = {}) {\n super(\n new GearGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n metalness: 0.8,\n roughness: 0.2,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { HeartGeometry, type HeartGeometryOptions } from \"../../geometry/shapes/HeartGeometry\";\n\nexport interface HeartOptions extends HeartGeometryOptions {\n /** Surface tint. Defaults to `#c62828`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#c61416`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.25`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Heart shape prefab.\n */\nexport class Heart extends Mesh<HeartGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#c62828\",\n emissive = \"#c61416\",\n emissiveIntensity = 0.25,\n ...geometryOptions\n }: HeartOptions = {}) {\n super(\n new HeartGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { HexagonGeometry, type HexagonGeometryOptions } from \"../../geometry/shapes/HexagonGeometry\";\n\nexport interface HexagonOptions extends HexagonGeometryOptions {\n /** Surface tint. Defaults to `#ffffff`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffffff`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.1`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Hexagon tile prefab.\n */\nexport class Hexagon extends Mesh<HexagonGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#ffffff\",\n emissive = \"#ffffff\",\n emissiveIntensity = 0.1,\n ...geometryOptions\n }: HexagonOptions = {}) {\n super(\n new HexagonGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { StarGeometry, type StarGeometryOptions } from \"../../geometry/shapes/StarGeometry\";\n\nexport interface StarOptions extends StarGeometryOptions {\n /** Surface tint. Defaults to `#ffff00`. */\n color?: ColorRepresentation;\n /** Emissive tint. Defaults to `#ffd700`. */\n emissive?: ColorRepresentation;\n /** Emissive strength. Defaults to `0.25`. */\n emissiveIntensity?: number;\n}\n\n/**\n * Star shape prefab.\n */\nexport class Star extends Mesh<StarGeometry, MeshStandardMaterial> {\n constructor({\n color = \"#ffff00\",\n emissive = \"#ffd700\",\n emissiveIntensity = 0.25,\n ...geometryOptions\n }: StarOptions = {}) {\n super(\n new StarGeometry(geometryOptions),\n new MeshStandardMaterial({\n color: new Color(color),\n emissive: new Color(emissive),\n emissiveIntensity,\n metalness: 0.1,\n roughness: 0.3,\n flatShading: true,\n }),\n );\n }\n}","import { Mesh, MeshStandardMaterial } from \"three\";\nimport { BoneGeometry } from \"../../geometry/skeleton/BoneGeometry\";\n\nexport class Bone extends Mesh<BoneGeometry, MeshStandardMaterial> {\n constructor() {\n super(new BoneGeometry(), new MeshStandardMaterial({ color: 0xffffff }));\n }\n}\n","import { Color, ColorRepresentation, Mesh, MeshStandardMaterial } from \"three\";\nimport { TreeGeometry, type TreeGeometryOptions } from \"../../geometry/trees/TreeGeometry\";\n\nexport interface TreeOptions extends TreeGeometryOptions {\n /** Trunk tint. Defaults to `#8b4513`. */\n trunkColor?: ColorRepresentation;\n /** Leaf tint. Defaults to `#228b22`. */\n leafColor?: ColorRepresentation;\n}\n\n/**\n * Low-poly tree prefab — trunk and leaf clusters with separate material groups.\n */\nexport class Tree extends Mesh<TreeGeometry, MeshStandardMaterial[]> {\n readonly trunkHeight: number;\n\n constructor({\n trunkColor = \"#8b4513\",\n leafColor = \"#228b22\",\n ...geometryOptions\n }: TreeOptions = {}) {\n const geometry = new TreeGeometry(geometryOptions);\n\n super(geometry, [\n new MeshStandardMaterial({\n color: new Color(trunkColor),\n roughness: 0.9,\n metalness: 0,\n flatShading: true,\n }),\n new MeshStandardMaterial({\n color: new Color(leafColor),\n roughness: 0.8,\n metalness: 0,\n flatShading: true,\n }),\n ]);\n\n this.trunkHeight = geometry.trunkHeight;\n }\n}","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n TerrainMoundGeometry,\n type TerrainMoundGeometryOptions,\n} from \"../../geometry/terrain/TerrainMoundGeometry\";\n\nexport interface TerrainMoundOptions extends TerrainMoundGeometryOptions {\n /** Surface tint. Defaults to `#3a5a3a`. */\n color?: ColorRepresentation;\n /** Faceted low-poly shading. Defaults to `true`. */\n flatShading?: boolean;\n}\n\n/**\n * Rounded terrain mound prefab — a {@link TerrainMoundGeometry} with a matte,\n * flat-shaded material. Base sits on Y=0; drop it into a scene as a diorama\n * ground or a small rise. Casts and receives shadows.\n */\nexport class TerrainMound extends Mesh<TerrainMoundGeometry, MeshStandardMaterial> {\n readonly radius: number;\n readonly height: number;\n\n constructor({ color = \"#3a5a3a\", flatShading = true, ...geometryOptions }: TerrainMoundOptions = {}) {\n const geometry = new TerrainMoundGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 1,\n metalness: 0,\n flatShading,\n side: DoubleSide,\n }),\n );\n\n this.radius = geometry.radius;\n this.height = geometry.height;\n this.castShadow = true;\n this.receiveShadow = true;\n }\n}\n","import { Color, ColorRepresentation, DoubleSide, Mesh, MeshStandardMaterial } from \"three\";\nimport {\n TerrainPlaneGeometry,\n type TerrainPlaneGeometryOptions,\n} from \"../../geometry/terrain/TerrainPlaneGeometry\";\n\nexport interface TerrainPlaneOptions extends TerrainPlaneGeometryOptions {\n /** Surface tint. Defaults to `#3a5a3a`. */\n color?: ColorRepresentation;\n /** Faceted low-poly shading. Defaults to `true`. */\n flatShading?: boolean;\n}\n\n/**\n * Rectangular terrain patch prefab — a {@link TerrainPlaneGeometry} with a matte,\n * flat-shaded material. Base grid on Y=0; drop it into a scene as a diorama ground\n * or a tileable terrain field. Casts and receives shadows.\n */\nexport class TerrainPlane extends Mesh<TerrainPlaneGeometry, MeshStandardMaterial> {\n readonly width: number;\n readonly depth: number;\n\n constructor({ color = \"#3a5a3a\", flatShading = true, ...geometryOptions }: TerrainPlaneOptions = {}) {\n const geometry = new TerrainPlaneGeometry(geometryOptions);\n\n super(\n geometry,\n new MeshStandardMaterial({\n color: new Color(color),\n roughness: 1,\n metalness: 0,\n flatShading,\n side: DoubleSide,\n }),\n );\n\n this.width = geometry.width;\n this.depth = geometry.depth;\n this.castShadow = true;\n this.receiveShadow = true;\n }\n}\n","import { DataTexture, NearestFilter, RepeatWrapping, RGBAFormat, UnsignedByteType } from \"three\";\n\n/**\n * Create a checkerboard texture\n *\n * Example:\n * ```\n * const material = new MeshStandardMaterial();\n * material.map = createCheckerboardTexture(8);\n * ```\n */\nexport const checkerboardTexture = (size: number): DataTexture => {\n const data = new Uint8Array(4 * size * size);\n for (let i = 0; i < size * size; i++) {\n const stride = i * 4;\n const color = (i % size ^ Math.floor(i / size)) & 1 ? 255 : 0;\n data[stride] = color; // red\n data[stride + 1] = color; // green\n data[stride + 2] = color; // blue\n data[stride + 3] = 255; // alpha\n }\n\n const texture = new DataTexture(data, size, size, RGBAFormat, UnsignedByteType);\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.minFilter = NearestFilter;\n texture.needsUpdate = true;\n\n return texture;\n};\n","import { Box3, Object3D, Vector3 } from \"three\";\nimport { BoxSide } from \"../constants/BoxSide\";\n\n/**\n * Aligns an array of Object3D objects (or subclasses) to a specified side\n * (left, right, top, bottom, front, or back) based on their world-space bounding boxes.\n */\nexport function alignToEdge<T extends Object3D>(objects: T[], side: BoxSide): void {\n if (objects.length === 0) {\n throw new Error(\"No objects provided for alignment.\");\n }\n\n const worldBoundingBox = new Box3();\n const worldPosition = new Vector3();\n\n // Precompute world-space bounding boxes and positions for all objects\n const objectData = objects.map((object) => {\n worldBoundingBox.setFromObject(object); // Accounts for scale and rotation\n object.getWorldPosition(worldPosition);\n\n return {\n object,\n boundingBox: worldBoundingBox.clone(), // Clone to avoid overwriting\n worldPosition: worldPosition.clone(),\n };\n });\n\n // Compute the reference alignment value based on the specified side\n const referenceValue = objectData.reduce(\n (acc, { boundingBox }) => {\n switch (side) {\n case BoxSide.LEFT:\n return Math.min(acc, boundingBox.min.x);\n case BoxSide.RIGHT:\n return Math.max(acc, boundingBox.max.x);\n case BoxSide.BOTTOM:\n return Math.min(acc, boundingBox.min.y);\n case BoxSide.TOP:\n return Math.max(acc, boundingBox.max.y);\n case BoxSide.BACK:\n return Math.min(acc, boundingBox.min.z);\n case BoxSide.FRONT:\n return Math.max(acc, boundingBox.max.z);\n default:\n throw new Error(`Unsupported side type: ${side}`);\n }\n },\n side === BoxSide.RIGHT || side === BoxSide.TOP || side === BoxSide.FRONT ? -Infinity : Infinity,\n );\n\n // Align each object to the computed reference value\n objectData.forEach(({ object, boundingBox }) => {\n switch (side) {\n case BoxSide.LEFT:\n object.position.x += referenceValue - boundingBox.min.x;\n break;\n case BoxSide.RIGHT:\n object.position.x += referenceValue - boundingBox.max.x;\n break;\n case BoxSide.BOTTOM:\n object.position.y += referenceValue - boundingBox.min.y;\n break;\n case BoxSide.TOP:\n object.position.y += referenceValue - boundingBox.max.y;\n break;\n case BoxSide.BACK:\n object.position.z += referenceValue - boundingBox.min.z;\n break;\n case BoxSide.FRONT:\n object.position.z += referenceValue - boundingBox.max.z;\n break;\n }\n });\n}\n","import { Direction } from \"../constants/Direction\";\nimport { Box3, Object3D, Vector3 } from \"three\";\n\n/**\n * Aligns an array of `Object3D` objects along a specified direction with optional spacing.\n */\nexport function alignToRow<T extends Object3D>(\n objects: T[],\n direction: Vector3 = Direction.RIGHT,\n spacing: number = 0,\n): void {\n // Ensure the direction vector is normalized\n const alignmentDirection = direction.clone().normalize();\n\n // Start the position tracker for alignment\n let currentPosition = new Vector3();\n const worldBoundingBox = new Box3();\n\n // Align each object\n objects.forEach((object) => {\n // Compute the world-space bounding box\n worldBoundingBox.setFromObject(object); // Accounts for scale and rotation\n\n // Calculate the object's size along the alignment direction\n const sizeVector = new Vector3(\n worldBoundingBox.max.x - worldBoundingBox.min.x,\n worldBoundingBox.max.y - worldBoundingBox.min.y,\n worldBoundingBox.max.z - worldBoundingBox.min.z,\n );\n const size = sizeVector.dot(alignmentDirection);\n\n // Compute the object's center in world space\n const objectCenter = new Vector3();\n worldBoundingBox.getCenter(objectCenter);\n\n // Adjust the object's position so its center aligns with the current position\n const offset = alignmentDirection.clone().multiplyScalar(size / 2);\n object.position.copy(currentPosition.clone().add(offset).sub(objectCenter).add(object.position));\n\n // Update the position tracker for the next object\n currentPosition.add(alignmentDirection.clone().multiplyScalar(size + spacing));\n });\n}\n","import { Box3, BufferGeometry, Float32BufferAttribute, InstancedMesh, Matrix4, Object3D, Quaternion, Vector3 } from \"three\";\n\n//------------------------------\n// Object3D\n//------------------------------\n\n/**\n * Align an Object3D to a surface by adjusting its position.\n */\nexport function alignObjectToSurface(object: Object3D, targetPosition: Vector3, offset: Vector3 = new Vector3(0, 0, 0)): void {\n const boundingBox = new Box3().setFromObject(object);\n\n if (!boundingBox.isEmpty()) {\n const min = boundingBox.min;\n\n // Compute bottom center in world space\n const bottomCenter = new Vector3((min.x + boundingBox.max.x) / 2, min.y, (min.z + boundingBox.max.z) / 2);\n object.localToWorld(bottomCenter);\n\n // Calculate adjustment vector in world space\n const adjustment = targetPosition.clone().sub(bottomCenter).add(offset);\n\n // Transform adjustment to local space and apply\n const localAdjustment = object.worldToLocal(adjustment.clone());\n object.position.add(localAdjustment);\n } else {\n console.warn(\"The object has no geometry or is not visible.\");\n }\n}\n\n//------------------------------\n// Buffer Geometry\n//------------------------------\n\n/**\n * Align a BufferGeometry to a surface by adjusting its vertices.\n */\nexport function alignBufferGeometryToSurface(geometry: BufferGeometry, targetPositionY: number): void {\n const boundingBox = new Box3().setFromBufferAttribute(new Float32BufferAttribute(geometry.attributes.position.array, 3));\n\n if (!boundingBox.isEmpty()) {\n const minY = boundingBox.min.y;\n\n // Translate the geometry to align the bottom to the target position\n geometry.translate(0, targetPositionY - minY, 0);\n } else {\n console.warn(\"The geometry is empty or invalid.\");\n }\n}\n\n//------------------------------\n// Instanced Mesh\n//------------------------------\n\n/**\n * Align an InstancedMesh to a surface.\n */\nexport function alignInstancedMeshToSurface(\n instancedMesh: InstancedMesh,\n targetPosition: Vector3,\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n // Compute the bounding box for the entire InstancedMesh\n const boundingBox = new Box3().setFromObject(instancedMesh);\n\n if (!boundingBox.isEmpty()) {\n // Find the bottom Y coordinate of the bounding box\n const minY = boundingBox.min.y;\n\n // Compute the adjustment needed to align the bottom of the InstancedMesh to the target position\n const adjustment = new Vector3(0, targetPosition.y - minY, 0).add(offset);\n\n // Transform adjustment to local space and apply to position\n const localAdjustment = instancedMesh.worldToLocal(adjustment.clone());\n instancedMesh.position.add(localAdjustment);\n } else {\n console.warn(\"The InstancedMesh has no geometry or is not visible.\");\n }\n}\n\n/**\n * Align a specific instance in an InstancedMesh to a surface.\n */\nexport function alignInstancedMeshIndexToSurface(\n instancedMesh: InstancedMesh,\n targetPosition: Vector3,\n instanceIndex: number,\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n const boundingBox = new Box3().setFromObject(instancedMesh);\n\n if (!boundingBox.isEmpty()) {\n const minY = boundingBox.min.y;\n\n // Get the instance's current transformation matrix\n const matrix = new Matrix4();\n instancedMesh.getMatrixAt(instanceIndex, matrix);\n\n // Decompose the matrix to extract position, rotation, and scale\n const position = new Vector3();\n const quaternion = new Quaternion();\n const scale = new Vector3();\n matrix.decompose(position, quaternion, scale);\n\n // Transform targetPosition to the instanced mesh's local space\n const localTargetPosition = instancedMesh.worldToLocal(targetPosition.clone());\n\n // Adjust the position of the instance\n position.y = localTargetPosition.y - minY + offset.y;\n\n // Recompose the matrix and update the instance\n matrix.compose(position, quaternion, scale);\n instancedMesh.setMatrixAt(instanceIndex, matrix);\n\n // Mark the instance matrix as needing an update\n instancedMesh.instanceMatrix.needsUpdate = true;\n } else {\n console.warn(\"The instanced mesh has invalid geometry.\");\n }\n}\n","import { Box3, Mesh, Object3D, Vector3 } from \"three\";\n\n//------------------------------\n// Object3D\n//------------------------------\n\n/**\n * Centers an `Object3D` relative to a specified target position with an optional offset.\n *\n * This function calculates the bounding box center of the given `Object3D` and adjusts\n * its position so that it is centered at the specified target position, with an optional\n * offset applied. The centering respects the object's current transformation, including\n * its scale and rotation.\n */\nexport function centerObject<T extends Object3D>(object: T, target = new Vector3(0, 0, 0), offset = new Vector3(0, 0, 0)) {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n const totalOffset = new Vector3().addVectors(target, offset);\n const adjustment = new Vector3().subVectors(totalOffset, center);\n\n object.position.add(adjustment);\n}\n\n/**\n * Centers the geometry of an `Object3D` relative to a target position with an optional offset.\n *\n * This function calculates the bounding box center of the given `Object3D` and adjusts its\n * geometry's position by translating it such that the geometry is centered at the specified\n * target position, with an optional offset applied. Unlike modifying the `position` property,\n * this function directly translates the geometry within the object's local space.\n */\nexport function centerObjectGeometry<T extends Object3D>(\n object: T,\n target: Vector3 = new Vector3(0, 0, 0),\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n const totalTarget = new Vector3().addVectors(target, offset);\n\n object.translateX(totalTarget.x - center.x);\n object.translateY(totalTarget.y - center.y);\n object.translateZ(totalTarget.z - center.z);\n object.updateMatrixWorld(true);\n}\n\n//------------------------------\n// Mesh\n//------------------------------\n\n/**\n * Centers the geometry of a `Mesh` relative to a target position with an optional offset.\n *\n * This function calculates the bounding box center of the `Mesh` geometry and adjusts its\n * position by translating the geometry such that it is centered at the specified target\n * position, with an optional offset applied. The function modifies the geometry directly,\n * leaving the `Mesh`'s transformation properties (`position`, `rotation`, `scale`) unchanged.\n */\nexport function centerMeshGeometry<T extends Mesh>(\n mesh: T,\n target: Vector3 = new Vector3(0, 0, 0),\n offset: Vector3 = new Vector3(0, 0, 0),\n): void {\n // Compute the bounding box for the geometry\n mesh.geometry.computeBoundingBox();\n const box = mesh.geometry.boundingBox;\n\n if (box) {\n const center = box.getCenter(new Vector3());\n const totalTarget = new Vector3().addVectors(target, offset);\n const translationOffset = new Vector3().subVectors(totalTarget, center);\n\n mesh.geometry.translate(translationOffset.x, translationOffset.y, translationOffset.z);\n }\n}\n\nexport const Center = {\n object: centerObject,\n objectGeometry: centerObjectGeometry,\n meshGeometry: centerMeshGeometry,\n};\n","//------------------------------\n// Hex\n//------------------------------\n\n/**\n * Convert hex color code color string to RGB array\n */\nexport function parseHexCode(hex: string): [number, number, number] {\n const bigint = parseInt(hex.slice(1), 16);\n return [\n (bigint >> 16) & 255, // r\n (bigint >> 8) & 255, // g\n bigint & 255, // b\n ];\n}\n\nexport function hexToHsl(hex: number): [number, number, number] {\n const [r, g, b] = hexToRgb(hex);\n return rgbToHsl(r, g, b);\n}\n\n/**\n * Convert hexadecimal literal numeric color value to RGB array\n * @param hex\n */\nexport function hexToRgb(hex: number): [number, number, number] {\n const r = (hex >> 16) & 0xff;\n const g = (hex >> 8) & 0xff;\n const b = hex & 0xff;\n\n return [r, g, b];\n}\n\n//------------------------------\n// HSL\n//------------------------------\n\n/**\n * Example usage:\n * ```\n * const h = 200; // Hue\n * const s = 75; // Saturation\n * const l = 50; // Lightness\n *\n * const [ r, g, b ] = hslToHex(h, s, l);\n * ```\n */\nexport function hslToHex(h: number, s: number, l: number): [number, number, number] {\n s /= 100;\n l /= 100;\n\n function hueToRgb(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n }\n\n let r: number, g: number, b: number;\n\n if (s === 0) {\n r = g = b = l; // Achromatic (grey)\n } else {\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n r = hueToRgb(p, q, h / 360 + 1 / 3);\n g = hueToRgb(p, q, h / 360);\n b = hueToRgb(p, q, h / 360 - 1 / 3);\n }\n\n // Convert RGB to hex\n const toHexValue = (x: number): number => Math.round(x * 255);\n\n return [\n toHexValue(r),\n toHexValue(g),\n toHexValue(b),\n ];\n}\n\nexport function hslToRgb(h: number, s: number, l: number): [number, number, number] {\n s /= 100;\n l /= 100;\n const k = (n: number) => (n + h / 30) % 12;\n const a = s * Math.min(l, 1 - l);\n const f = (n: number) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));\n\n return [f(0) * 255, f(8) * 255, f(4) * 255];\n}\n\n//------------------------------\n// RGB\n//------------------------------\n\nexport function normalizeRgb(r: number, g: number, b: number): [number, number, number] {\n return [r / 255, g / 255, b / 255];\n}\n\nexport function rgbToHex(r: number, g: number, b: number): number {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n\n return (r << 16) + (g << 8) + b;\n}\n\n/**\n * Converts an RGB color to HSL.\n *\n * Example usage:\n * ```\n * const rgbColor = { r: 255, g: 0, b: 0 }; // Red\n * const hslColor = rgbToHsl(rgbColor.r, rgbColor.g, rgbColor.b);\n * console.log(hslColor); // Output: { h: 0, s: 100, l: 50 }\n * ```\n */\nexport function rgbToHsl(r: number, g: number, b: number): [number, number, number] {\n // Normalize r, g, b values to the range 0–1\n r /= 255;\n g /= 255;\n b /= 255;\n\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const delta = max - min;\n\n let h = 0;\n let s = 0;\n const l = (max + min) / 2;\n\n // Calculate hue\n if (delta !== 0) {\n if (max === r) {\n h = ((g - b) / delta + (g < b ? 6 : 0)) * 60;\n } else if (max === g) {\n h = ((b - r) / delta + 2) * 60;\n } else if (max === b) {\n h = ((r - g) / delta + 4) * 60;\n }\n }\n\n // Calculate saturation\n if (delta !== 0) {\n s = delta / (1 - Math.abs(2 * l - 1));\n }\n\n // Convert h and s to percentages\n h = Math.round(h);\n s = Math.round(s * 100);\n const lPercent = Math.round(l * 100);\n\n return [ h, s, lPercent ];\n}\n\n//------------------------------\n// Distance functions\n//------------------------------\n\n/**\n * Calculate the Euclidean distance between two colors in RGB space\n * distance = sqrt((r1 - r2)^2 + (g1 - g2)^2 + (b1 - b2)^2)\n */\nexport function calculateDistance(color1: [number, number, number], color2: [number, number, number]): number {\n return Math.sqrt(\n Math.pow(color1[0] - color2[0], 2) +\n Math.pow(color1[1] - color2[1], 2) +\n Math.pow(color1[2] - color2[2], 2),\n );\n}\n\n/**\n * Calculate the sum of absolute differences for each channel\n * difference = |r1 - r2| + |g1 - g2| + |b1 - b2|\n */\nexport function calculateChannelDifference(color1: [number, number, number], color2: [number, number, number]): number {\n return (\n Math.abs(color1[0] - color2[0]) + //\n Math.abs(color1[1] - color2[1]) +\n Math.abs(color1[2] - color2[2])\n );\n}\n\nexport function findClosestColor(inputColor: number, dataset: number[]): number | null {\n const inputRgb = hexToRgb(inputColor);\n let closestColor = null;\n let smallestDistance = Infinity;\n\n for (const entry of dataset) {\n const colorRgb = hexToRgb(entry);\n const distance = calculateDistance(inputRgb, colorRgb);\n\n if (distance < smallestDistance) {\n smallestDistance = distance;\n closestColor = entry;\n }\n }\n\n return closestColor;\n}\n\nexport function findClosestColorChannelWise(inputColor: number, dataset: number[]): number | null {\n const inputRgb = hexToRgb(inputColor);\n let closestColor = null;\n let smallestDifference = Infinity;\n\n for (const entry of dataset) {\n const colorRgb = hexToRgb(entry);\n const difference = calculateChannelDifference(inputRgb, colorRgb);\n\n if (difference < smallestDifference) {\n smallestDifference = difference;\n closestColor = entry;\n }\n }\n\n return closestColor;\n}\n\n//------------------------------\n// Palette generation\n//------------------------------\n\n/**\n * Example usage:\n * ```\n * const baseHue = Math.floor(Math.random() * 360);\n * const color1 = getAnalogousColors(baseHue);\n * const color2 = getAnalogousColors(baseHue);\n * ```\n */\nexport function getAnalogousColors(baseHue: number): [number, number, number] {\n const h = (baseHue + Math.floor(-30 + Math.random() * 61)) % 360; // ±30 degrees from baseHue\n const s = Math.floor(60 + Math.random() * 21); // Saturation: 60 - 80\n const l = Math.floor(50 + Math.random() * 21); // Lightness: 50 - 70\n return hslToRgb(h, s, l);\n}\n","import { Mesh, Vector3 } from \"three\";\n\n/**\n * Get the closest point on a mesh to a specified point.\n *\n * Example usage:\n * ```ts\n * const point = new Vector3(5, 2, 1); // The point to check against the mesh\n * const closestPoint = getClosestPointOnMesh(point, targetMesh);\n * ```\n */\nexport function findClosestPoint(point: Vector3, mesh: Mesh) {\n if (!mesh.geometry.isBufferGeometry) {\n throw new Error(\"Mesh must have a BufferGeometry.\");\n }\n\n const geometry = mesh.geometry;\n const positionAttribute = geometry.getAttribute(\"position\");\n const closestPoint = new Vector3();\n const tempPoint = new Vector3();\n let minDistance = Infinity;\n\n for (let i = 0; i < positionAttribute.count; i++) {\n tempPoint.fromBufferAttribute(positionAttribute, i);\n const distance = tempPoint.distanceTo(point);\n\n if (distance < minDistance) {\n minDistance = distance;\n closestPoint.copy(tempPoint);\n }\n }\n\n // Transform the closest point to world space (if the mesh is transformed)\n mesh.localToWorld(closestPoint);\n\n return closestPoint;\n}\n","import { Vector2 } from \"three\";\n\n/**\n * Normalizes a time value `t` between a minimum and maximum value.\n * @param t - The value to normalize.\n * @param min - The minimum value of the range.\n * @param max - The maximum value of the range.\n * @returns A normalized value between 0 and 1.\n */\nfunction normalizeT(t: number, min: number, max: number): number {\n return Math.max(0, Math.min(1, (t - min) / (max - min)));\n}\n\n/**\n * Generates an array of interpolated 2D points using an easing function.\n * @param curveFunction - The easing function to apply to the normalized value.\n * @param startRadius - The starting radius for interpolation.\n * @param endRadius - The ending radius for interpolation.\n * @param startHeight - The starting height for interpolation.\n * @param endHeight - The ending height for interpolation.\n * @param segments - The number of segments for interpolation (default is 20).\n * @param min - The minimum value of the normalization range (default is 0).\n * @param max - The maximum value of the normalization range (default is 1).\n * @returns An array of `Vector2` points representing the interpolated curve.\n */\nexport function interpolateCurve(\n curveFunction: (t: number) => number,\n startRadius: number,\n endRadius: number,\n startHeight: number,\n endHeight: number,\n segments: number = 20,\n min: number = 0,\n max: number = 1\n): Vector2[] {\n const points: Vector2[] = [];\n\n for (let i = 0; i <= segments; i++) {\n const t = i / segments; // Normalized value between 0 and 1\n const easedT = curveFunction(normalizeT(t, min, max));\n const x = startRadius + easedT * (endRadius - startRadius);\n const y = startHeight + t * (endHeight - startHeight);\n points.push(new Vector2(x, y));\n }\n\n return points;\n}\n","import { ParametricCurve } from \"../constants/ParametricCurve\";\nimport { Vector2 } from \"three\";\n\n/**\n * Function to create cubic Bezier curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createCubicCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the cubic curve\n * new THREE.Vector2(1.5, 3), // First control point (outward curve)\n * new THREE.Vector2(1.5, 4), // Second control point (outward curve)\n * new THREE.Vector2(0.5, 5), // End of the curve\n * 24, // Resolution of the quadratic curve\n * ),\n * ]\n * ```\n */\nexport const createCubicCurvePoints = (start: Vector2, control1: Vector2, control2: Vector2, end: Vector2, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.cubic(t, start.x, control1.x, control2.x, end.x);\n const y = ParametricCurve.cubic(t, start.y, control1.y, control2.y, end.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create damped curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createDampedCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the damped curve\n * new THREE.Vector2(1.5, 5), // End of the damped curve\n * 5, // Damping factor\n * 24, // Resolution of the damped curve\n * ),\n * ]\n * ```\n */\nexport const createDampedCurvePoints = (start: Vector2, end: Vector2, damping: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.damped(t, damping) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create exponential curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createExponentialCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the exponential curve\n * new THREE.Vector2(1.5, 5), // End of the exponential curve\n * 0.5, // Base of the exponential function\n * 2, // Exponential factor\n * 24 // Resolution of the exponential curve\n * ),\n * ]\n * ```\n */\nexport const createExponentialCurvePoints = (start: Vector2, end: Vector2, base: number, factor: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.exponential(t, base, factor) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create logarithmic curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createLogarithmicCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the logarithmic curve\n * new THREE.Vector2(1.5, 5), // End of the logarithmic curve\n * 0.5, // Base of the logarithmic function\n * 10, // Logarithmic factor\n * 24, // Resolution of the logarithmic curve\n * ),\n * ]\n * ```\n */\nexport const createLogarithmicCurvePoints = (start: Vector2, end: Vector2, base: number, factor: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.logarithmic(t, base, factor) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create parabolic curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createParabolicCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start point\n * new THREE.Vector2(0.5, 5), // End point\n * 1, // Coefficient for t^2 (controls curvature)\n * 0, // Coefficient for t (linear component)\n * 0, // Constant term (vertical offset)\n * 24, // Resolution\n * ),\n * ]\n * ```\n */\nexport const createParabolicCurvePoints = (start: Vector2, end: Vector2, a: number, b: number, c: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = a * t * t + b * t + c + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create quadratic Bezier curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createQuadraticCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the quadratic curve\n * new THREE.Vector2(1.5, 5), // Control point (outward curve)\n * new THREE.Vector2(0.5, 5), // End of the curve\n * 24, // Resolution of the quadratic curve\n * ),\n * ]\n * ```\n */\nexport const createQuadraticCurvePoints = (start: Vector2, control: Vector2, end: Vector2, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.quadratic(t, start.x, control.x, end.x);\n const y = ParametricCurve.quadratic(t, start.y, control.y, end.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\n/**\n * Function to create sigmoid curve points\n *\n * Example:\n * ```\n * const points = [\n * ...ParametricCurveUtils.createSigmoidCurvePoints(\n * new THREE.Vector2(0.5, 2), // Start of the sigmoid curve\n * new THREE.Vector2(1.5, 5), // End of the sigmoid curve\n * 20, // Sigmoid steepness factor\n * 24, // Resolution of the sigmoid curve\n * ),\n * ]\n */\nexport const createSigmoidCurvePoints = (start: Vector2, end: Vector2, a: number, segments = 24) => {\n let curvePoints = [];\n for (let i = 0; i <= segments; i++) {\n const t = i / segments;\n const x = ParametricCurve.sigmoid(t, a) * (end.x - start.x) + start.x;\n const y = start.y + t * (end.y - start.y);\n curvePoints.push(new Vector2(x, y));\n }\n return curvePoints;\n};\n\nexport const ParametricCurveUtils = {\n createCubicCurvePoints,\n createDampedCurvePoints,\n createExponentialCurvePoints,\n createLogarithmicCurvePoints,\n createParabolicCurvePoints,\n createQuadraticCurvePoints,\n createSigmoidCurvePoints,\n};\n","/**\n * Generates vertices for two triangles based upon a quad.\n *\n * Example usages:\n *\n * Create a face of a box:\n * ```\n * const frontQuad = createQuad(\n * [-1, -1, 1], // Bottom-left\n * [ 1, -1, 1], // Bottom-right\n * [-1, 1, 1], // Top-left\n * [ 1, 1, 1], // Top-right\n * [ 0, 0, 1] // Normal (facing forward)\n * );\n * ```\n *\n * Assembling a box:\n * ```\n * const vertices = [\n * ...createQuad([-1, -1, 1], [1, -1, 1], [-1, 1, 1], [1, 1, 1], [0, 0, 1]), // Front face\n * ...createQuad([1, -1, -1], [-1, -1, -1], [1, 1, -1], [-1, 1, -1], [0, 0, -1]), // Back face\n * ...createQuad([-1, 1, 1], [1, 1, 1], [-1, 1, -1], [1, 1, -1], [0, 1, 0]), // Top face\n * ...createQuad([-1, -1, -1], [1, -1, -1], [-1, -1, 1], [1, -1, 1], [0, -1, 0]), // Bottom face\n * ...createQuad([-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1], [-1, 0, 0]), // Left face\n * ...createQuad([1, -1, 1], [1, -1, -1], [1, 1, 1], [1, 1, -1], [1, 0, 0]), // Right face\n * ];\n * ```\n *\n * Generating Buffer Geometry:\n * ```\n * const positions = [];\n * const normals = [];\n * const uvs = [];\n *\n * for (const vertex of vertices) {\n * positions.push(...vertex.pos);\n * normals.push(...vertex.norm);\n * uvs.push(...vertex.uv);\n * }\n *\n * const geometry = new THREE.BufferGeometry();\n * geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3));\n * geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(normals), 3));\n * geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2));\n * ```\n */\nexport function createQuad(\n p1: [number, number, number], //\n p2: [number, number, number],\n p3: [number, number, number],\n p4: [number, number, number],\n normal?: [number, number, number],\n uv1: [number, number] = [0, 0],\n uv2: [number, number] = [1, 0],\n uv3: [number, number] = [0, 1],\n uv4: [number, number] = [1, 1],\n) {\n const normalVector = normal || calculateNormal(p1, p2, p3);\n\n return [\n // Triangle 1\n { pos: p1, norm: normalVector, uv: uv1 },\n { pos: p2, norm: normalVector, uv: uv2 },\n { pos: p4, norm: normalVector, uv: uv4 },\n // Triangle 2\n { pos: p1, norm: normalVector, uv: uv1 },\n { pos: p4, norm: normalVector, uv: uv4 },\n { pos: p3, norm: normalVector, uv: uv3 },\n ];\n}\n\n/**\n * Compute normal based on the quad’s vertices (using the cross product of two edges).\n */\nexport function calculateNormal(\n p1: [number, number, number],\n p2: [number, number, number],\n p3: [number, number, number],\n): [number, number, number] {\n // Edge vectors\n const u: [number, number, number] = [\n p2[0] - p1[0],\n p2[1] - p1[1],\n p2[2] - p1[2],\n ];\n const v: [number, number, number] = [\n p3[0] - p1[0],\n p3[1] - p1[1],\n p3[2] - p1[2],\n ];\n\n // Cross product to calculate normal\n const normal: [number, number, number] = [\n u[1] * v[2] - u[2] * v[1],\n u[2] * v[0] - u[0] * v[2],\n u[0] * v[1] - u[1] * v[0],\n ];\n\n // Normalize the normal vector\n const length = Math.sqrt(normal[0] ** 2 + normal[1] ** 2 + normal[2] ** 2);\n return normal.map((val) => val / length) as [number, number, number];\n}\n","/**\n * Set a random timeout that will call the callback function with a random delay between minDelay and maxDelay.\n *\n * Example usage:\n * ```\n * setRandomTimeout(() => {\n * console.log(`Callback ${i} executed!`);\n * }, 100, 500); // Random timeout between 100ms and 500ms\n * ```\n */\nexport function setRandomTimeout(callback: () => void, minDelay: number, maxDelay: number) {\n const delay = minDelay + Math.random() * (maxDelay - minDelay);\n\n return setTimeout(callback, delay);\n}\n\n/**\n * Set a random interval that will call the callback function with a random delay between minDelay and maxDelay.\n *\n * Example usage:\n * ```\n * const clearRandomInterval = setRandomInterval(() => {\n * console.log('Random interval executed!');\n * }, 500, 1500); // Random delay between 500ms and 1500ms\n * ```\n */\nexport function setRandomInterval(callback: () => void, minDelay: number, maxDelay: number): () => void {\n let timeoutId: ReturnType<typeof setTimeout>;\n\n function scheduleNext() {\n const delay = minDelay + Math.random() * (maxDelay - minDelay);\n timeoutId = setTimeout(() => {\n callback();\n scheduleNext(); // Schedule the next execution\n }, delay);\n }\n\n scheduleNext();\n\n // Return a function to allow clearing the interval\n return () => clearTimeout(timeoutId);\n}\n","/**\n * Planar UV Mapping\n * Projects UVs onto the geometry from a single direction (like shining a projector onto a surface).\n *\n * Example:\n * ```\n * const vertices = [\n * [-1, -1, 1],\n * [1, -1, 1],\n * [-1, 1, 1],\n * [1, 1, 1],\n * ];\n *\n * const uvs = planarUVMapping(vertices, 'z'); // Project onto the Z-axis\n */\nexport function planarUVMapping(vertices: [number, number, number][], axis: 'x' | 'y' | 'z'): [number, number][] {\n return vertices.map(([x, y, z]) => {\n switch (axis) {\n case 'x': return [y, z]; // Use Y and Z for X-axis projection\n case 'y': return [x, z]; // Use X and Z for Y-axis projection\n case 'z': return [x, y]; // Use X and Y for Z-axis projection\n default: throw new Error(`Invalid axis: ${axis}`);\n }\n });\n}\n\n/**\n * Cubic UV Mapping\n * Applies a texture by projecting UVs along each face of a cube.\n *\n * Example usage:\n * ```\n * const cubeVertices = [\n * [-1, -1, 1],\n * [1, -1, 1],\n * [-1, 1, 1],\n * [1, 1, 1],\n * ];\n *\n * const cubeUVs = cubicUVMappingBatch(cubeVertices);\n * ```\n */\nexport function cubicUVMapping(vertex: [number, number, number]): [number, number] {\n const [x, y, z] = vertex;\n const absX = Math.abs(x), absY = Math.abs(y), absZ = Math.abs(z);\n\n if (absX >= absY && absX >= absZ) { // X face\n return [z > 0 ? z : -z, y];\n } else if (absY >= absX && absY >= absZ) { // Y face\n return [x, z > 0 ? z : -z];\n } else { // Z face\n return [x, y];\n }\n}\n\nexport function cubicUVMappingBatch(vertices: [number, number, number][]): [number, number][] {\n return vertices.map((vertex) => cubicUVMapping(vertex));\n}\n\n/**\n * Spherical UV Mapping\n * Wraps UVs around the geometry as if the texture were projected from a globe.\n *\n * Example usage:\n * ```\n * const sphereVertices = [\n * [1, 0, 0],\n * [0, 1, 0],\n * [0, 0, 1],\n * ];\n *\n * const sphereUVs = sphericalUVMapping(sphereVertices);\n * ```\n */\nexport function sphericalUVMapping(vertices: [number, number, number][]): [number, number][] {\n return vertices.map(([x, y, z]) => {\n const theta = Math.atan2(z, x); // Angle around the Y-axis\n const phi = Math.acos(y / Math.sqrt(x ** 2 + y ** 2 + z ** 2)); // Angle from the Y-axis\n const u = (theta / (2 * Math.PI)) + 0.5; // Map theta to [0, 1]\n const v = 1 - (phi / Math.PI); // Map phi to [0, 1]\n return [u, v];\n });\n}\n\n/**\n * Cylindrical UV Mapping\n * Projects UV coordinates onto the surface as though the texture is\n * wrapped around the cylinder's height and circumference.\n *\n * Example usage:\n * ```\n * const cylinderVertices = [\n * [1, 0, 0], // Vertex on the \"equator\"\n * [0, 1, 0], // Vertex on the top\n * [0, -1, 1], // Vertex on the bottom\n * [-1, 0, 0], // Opposite side of the equator\n * ];\n *\n * const cylinderUVs = cylindricalUVMapping(cylinderVertices);\n * ```\n */\nexport function cylindricalUVMapping(vertices: [number, number, number][]): [number, number][] {\n return vertices.map(([x, y, z]) => {\n const theta = Math.atan2(z, x); // Angle around the Y-axis (circumference)\n const u = (theta / (2 * Math.PI)) + 0.5; // Map theta to [0, 1]\n const v = y; // Use Y-axis as the vertical component (height)\n return [u, v];\n });\n}\n\n/**\n * Polar UV Mapping\n * Map textures onto circular or radial geometries, such as discs or dome-like structures.\n * Maps the radial distance from the center of the geometry to the v coordinate\n * and the angular position to the u coordinate.\n *\n * const discVertices = [\n * [1, 0, 0], // Vertex at (1, 0, 0)\n * [0, 0, 1], // Vertex at (0, 0, 1)\n * [-1, 0, 0], // Vertex at (-1, 0, 0)\n * [0, 0, -1], // Vertex at (0, 0, -1)\n * ];\n *\n * const polarUVs = polarUVMapping(discVertices);\n */\nexport function polarUVMapping(vertices: [number, number, number][]): [number, number][] {\n return vertices.map(([x, y, z]) => {\n const radius = Math.sqrt(x ** 2 + z ** 2); // Distance from the Y-axis (polar radius)\n const theta = Math.atan2(z, x); // Angle around the Y-axis (polar angle)\n\n const u = (theta / (2 * Math.PI)) + 0.5; // Map angle to [0, 1]\n const v = radius; // Use radial distance for v\n return [u, v];\n });\n}\n\n/**\n * Generic Normalization Function\n * This function will normalize 2D UV coordinates based on given bounds.\n *\n * Full pipeline:\n * - Compute UVs\n * - Calculate bounds\n * - Normalize UVs\n *\n * Example usage:\n * ```\n * const planarMapping = (vertex: [number, number, number]) => [vertex[0], vertex[1]];\n * const uvs = vertices.map(mappingFunction);\n * const { minBounds, maxBounds } = calculateUVBounds(uvs);\n * const normalizedUVs = normalizeUVBatch(uvs, minBounds, maxBounds);\n * ```\n */\nexport function normalizeUV(\n uv: [number, number],\n minU: number,\n maxU: number,\n minV: number,\n maxV: number\n): [number, number] {\n return [\n (uv[0] - minU) / (maxU - minU),\n (uv[1] - minV) / (maxV - minV),\n ];\n}\n\n/**\n * Batch Normalization for Multiple UVs\n * If you have multiple UVs, normalize them all based on the overall min/max bounds.\n */\nexport function normalizeUVBatch(\n uvs: [number, number][],\n minBounds: [number, number],\n maxBounds: [number, number]\n): [number, number][] {\n const [minU, minV] = minBounds;\n const [maxU, maxV] = maxBounds;\n\n return uvs.map((uv) => normalizeUV(uv, minU, maxU, minV, maxV));\n}\n\n/**\n * Finding Bounds for a List of UVs\n * calculate the min and max values dynamically.\n */\nexport function calculateUVBounds(uvs: [number, number][]): { minBounds: [number, number]; maxBounds: [number, number] } {\n const minU = Math.min(...uvs.map((uv) => uv[0]));\n const maxU = Math.max(...uvs.map((uv) => uv[0]));\n const minV = Math.min(...uvs.map((uv) => uv[1]));\n const maxV = Math.max(...uvs.map((uv) => uv[1]));\n\n return {\n minBounds: [minU, minV],\n maxBounds: [maxU, maxV],\n };\n}\n"],"mappings":"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"}