@kerros/editor 0.0.0-stage → 0.1.0-rc.1

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.
Files changed (345) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -2
  3. package/dist/SitePlanner.js +1189 -0
  4. package/dist/SitePlanner.js.map +1 -0
  5. package/dist/adapters/basemap.js +11 -0
  6. package/dist/adapters/basemap.js.map +1 -0
  7. package/dist/adapters/persistence.js +121 -0
  8. package/dist/adapters/persistence.js.map +1 -0
  9. package/dist/adapters/status.js +11 -0
  10. package/dist/adapters/status.js.map +1 -0
  11. package/dist/adapters/useProjectPersistence.js +56 -0
  12. package/dist/adapters/useProjectPersistence.js.map +1 -0
  13. package/dist/components/AiImportPanel.js +635 -0
  14. package/dist/components/AiImportPanel.js.map +1 -0
  15. package/dist/components/AnalysisPreview.js +179 -0
  16. package/dist/components/AnalysisPreview.js.map +1 -0
  17. package/dist/components/ElevatorPanel.js +120 -0
  18. package/dist/components/ElevatorPanel.js.map +1 -0
  19. package/dist/components/Icons.js +57 -0
  20. package/dist/components/Icons.js.map +1 -0
  21. package/dist/components/ImportDialog.js +467 -0
  22. package/dist/components/ImportDialog.js.map +1 -0
  23. package/dist/components/Inspector.js +1184 -0
  24. package/dist/components/Inspector.js.map +1 -0
  25. package/dist/components/NavigatePanel.js +301 -0
  26. package/dist/components/NavigatePanel.js.map +1 -0
  27. package/dist/components/NavigationGraph.js +234 -0
  28. package/dist/components/NavigationGraph.js.map +1 -0
  29. package/dist/components/StructureExplorer.js +510 -0
  30. package/dist/components/StructureExplorer.js.map +1 -0
  31. package/dist/components/StructureView.js +286 -0
  32. package/dist/components/StructureView.js.map +1 -0
  33. package/dist/components/controls.js +209 -0
  34. package/dist/components/controls.js.map +1 -0
  35. package/dist/components/graphLayout.js +27 -0
  36. package/dist/components/graphLayout.js.map +1 -0
  37. package/dist/host.js +175 -0
  38. package/dist/host.js.map +1 -0
  39. package/dist/i18n.js +88 -0
  40. package/dist/i18n.js.map +1 -0
  41. package/dist/import/analysisPreview.js +41 -0
  42. package/dist/import/analysisPreview.js.map +1 -0
  43. package/dist/import/brief.js +29 -0
  44. package/dist/import/brief.js.map +1 -0
  45. package/dist/import/checkpoint.js +50 -0
  46. package/dist/import/checkpoint.js.map +1 -0
  47. package/dist/import/detect.js +120 -0
  48. package/dist/import/detect.js.map +1 -0
  49. package/dist/import/documentSvg.js +49 -0
  50. package/dist/import/documentSvg.js.map +1 -0
  51. package/dist/import/instructions.js +20 -0
  52. package/dist/import/instructions.js.map +1 -0
  53. package/dist/import/openings.js +61 -0
  54. package/dist/import/openings.js.map +1 -0
  55. package/dist/import/planImport.js +233 -0
  56. package/dist/import/planImport.js.map +1 -0
  57. package/dist/import/register.js +47 -0
  58. package/dist/import/register.js.map +1 -0
  59. package/dist/import/runs.js +67 -0
  60. package/dist/import/runs.js.map +1 -0
  61. package/dist/import/session.js +23 -0
  62. package/dist/import/session.js.map +1 -0
  63. package/dist/import/types.js +13 -0
  64. package/dist/import/types.js.map +1 -0
  65. package/dist/import/usage.js +29 -0
  66. package/dist/import/usage.js.map +1 -0
  67. package/dist/import/walls.js +112 -0
  68. package/dist/import/walls.js.map +1 -0
  69. package/dist/index.js +178 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/map/CabinMaterials.js +81 -0
  72. package/dist/map/CabinMaterials.js.map +1 -0
  73. package/dist/map/CabinMirror.js +43 -0
  74. package/dist/map/CabinMirror.js.map +1 -0
  75. package/dist/map/Doors.js +80 -0
  76. package/dist/map/Doors.js.map +1 -0
  77. package/dist/map/ElevatorCabin.js +93 -0
  78. package/dist/map/ElevatorCabin.js.map +1 -0
  79. package/dist/map/FixtureLights.js +117 -0
  80. package/dist/map/FixtureLights.js.map +1 -0
  81. package/dist/map/MapCanvas.js +2161 -0
  82. package/dist/map/MapCanvas.js.map +1 -0
  83. package/dist/map/Passenger.js +69 -0
  84. package/dist/map/Passenger.js.map +1 -0
  85. package/dist/map/SceneLayer.js +1534 -0
  86. package/dist/map/SceneLayer.js.map +1 -0
  87. package/dist/map/UndergroundContext.js +153 -0
  88. package/dist/map/UndergroundContext.js.map +1 -0
  89. package/dist/map/ambience.js +194 -0
  90. package/dist/map/ambience.js.map +1 -0
  91. package/dist/map/architecture.js +305 -0
  92. package/dist/map/architecture.js.map +1 -0
  93. package/dist/map/bathMusic.js +92 -0
  94. package/dist/map/bathMusic.js.map +1 -0
  95. package/dist/map/cameraAim.js +33 -0
  96. package/dist/map/cameraAim.js.map +1 -0
  97. package/dist/map/elevators.js +56 -0
  98. package/dist/map/elevators.js.map +1 -0
  99. package/dist/map/excavation.js +52 -0
  100. package/dist/map/excavation.js.map +1 -0
  101. package/dist/map/exteriors.js +25 -0
  102. package/dist/map/exteriors.js.map +1 -0
  103. package/dist/map/features.js +218 -0
  104. package/dist/map/features.js.map +1 -0
  105. package/dist/map/fences.js +29 -0
  106. package/dist/map/fences.js.map +1 -0
  107. package/dist/map/journey.js +112 -0
  108. package/dist/map/journey.js.map +1 -0
  109. package/dist/map/levels.js +6 -0
  110. package/dist/map/levels.js.map +1 -0
  111. package/dist/map/lighting.js +143 -0
  112. package/dist/map/lighting.js.map +1 -0
  113. package/dist/map/loadBasemap.js +26 -0
  114. package/dist/map/loadBasemap.js.map +1 -0
  115. package/dist/map/materials.js +183 -0
  116. package/dist/map/materials.js.map +1 -0
  117. package/dist/map/poolLighting.js +39 -0
  118. package/dist/map/poolLighting.js.map +1 -0
  119. package/dist/map/projection.js +24 -0
  120. package/dist/map/projection.js.map +1 -0
  121. package/dist/map/rampGeometry.js +38 -0
  122. package/dist/map/rampGeometry.js.map +1 -0
  123. package/dist/map/route.js +107 -0
  124. package/dist/map/route.js.map +1 -0
  125. package/dist/map/stairSurfaces.js +115 -0
  126. package/dist/map/stairSurfaces.js.map +1 -0
  127. package/dist/map/surfaces.js +136 -0
  128. package/dist/map/surfaces.js.map +1 -0
  129. package/dist/map/textures.js +95 -0
  130. package/dist/map/textures.js.map +1 -0
  131. package/dist/map/underground.js +34 -0
  132. package/dist/map/underground.js.map +1 -0
  133. package/dist/map/walk.js +433 -0
  134. package/dist/map/walk.js.map +1 -0
  135. package/dist/map/walkContext.js +46 -0
  136. package/dist/map/walkContext.js.map +1 -0
  137. package/dist/map/walkDimensions.js +7 -0
  138. package/dist/map/walkDimensions.js.map +1 -0
  139. package/dist/map/walkJourney.js +85 -0
  140. package/dist/map/walkJourney.js.map +1 -0
  141. package/dist/map/walkSurfaces.js +106 -0
  142. package/dist/map/walkSurfaces.js.map +1 -0
  143. package/dist/map/wallJoins.js +70 -0
  144. package/dist/map/wallJoins.js.map +1 -0
  145. package/dist/map/water.js +274 -0
  146. package/dist/map/water.js.map +1 -0
  147. package/dist/model/authoring.js +99 -0
  148. package/dist/model/authoring.js.map +1 -0
  149. package/dist/model/boundaries.js +548 -0
  150. package/dist/model/boundaries.js.map +1 -0
  151. package/dist/model/coverage.js +30 -0
  152. package/dist/model/coverage.js.map +1 -0
  153. package/dist/model/document.js +52 -0
  154. package/dist/model/document.js.map +1 -0
  155. package/dist/model/doors.js +47 -0
  156. package/dist/model/doors.js.map +1 -0
  157. package/dist/model/factory.js +56 -0
  158. package/dist/model/factory.js.map +1 -0
  159. package/dist/model/geometry.js +454 -0
  160. package/dist/model/geometry.js.map +1 -0
  161. package/dist/model/history.js +29 -0
  162. package/dist/model/history.js.map +1 -0
  163. package/dist/model/imports.js +45 -0
  164. package/dist/model/imports.js.map +1 -0
  165. package/dist/model/inference.js +182 -0
  166. package/dist/model/inference.js.map +1 -0
  167. package/dist/model/materials.js +11 -0
  168. package/dist/model/materials.js.map +1 -0
  169. package/dist/model/mutations.js +157 -0
  170. package/dist/model/mutations.js.map +1 -0
  171. package/dist/model/navigation.js +275 -0
  172. package/dist/model/navigation.js.map +1 -0
  173. package/dist/model/ontology.js +109 -0
  174. package/dist/model/ontology.js.map +1 -0
  175. package/dist/model/passages.js +5 -0
  176. package/dist/model/passages.js.map +1 -0
  177. package/dist/model/portals.js +42 -0
  178. package/dist/model/portals.js.map +1 -0
  179. package/dist/model/precision.js +11 -0
  180. package/dist/model/precision.js.map +1 -0
  181. package/dist/model/project.js +31 -0
  182. package/dist/model/project.js.map +1 -0
  183. package/dist/model/ramps.js +10 -0
  184. package/dist/model/ramps.js.map +1 -0
  185. package/dist/model/roomNavigation.js +87 -0
  186. package/dist/model/roomNavigation.js.map +1 -0
  187. package/dist/model/routeClearance.js +72 -0
  188. package/dist/model/routeClearance.js.map +1 -0
  189. package/dist/model/spaces.js +104 -0
  190. package/dist/model/spaces.js.map +1 -0
  191. package/dist/model/stairGeometry.js +40 -0
  192. package/dist/model/stairGeometry.js.map +1 -0
  193. package/dist/model/stairTraversal.js +48 -0
  194. package/dist/model/stairTraversal.js.map +1 -0
  195. package/dist/model/topology.js +63 -0
  196. package/dist/model/topology.js.map +1 -0
  197. package/dist/model/types.js +35 -0
  198. package/dist/model/types.js.map +1 -0
  199. package/dist/model/validate.js +240 -0
  200. package/dist/model/validate.js.map +1 -0
  201. package/dist/model/vertical.js +129 -0
  202. package/dist/model/vertical.js.map +1 -0
  203. package/dist/model/walls.js +261 -0
  204. package/dist/model/walls.js.map +1 -0
  205. package/dist/planner/DrawingDock.js +231 -0
  206. package/dist/planner/DrawingDock.js.map +1 -0
  207. package/dist/planner/FloorControls.js +93 -0
  208. package/dist/planner/FloorControls.js.map +1 -0
  209. package/dist/planner/MapSettings.js +143 -0
  210. package/dist/planner/MapSettings.js.map +1 -0
  211. package/dist/planner/PlannerHelp.js +57 -0
  212. package/dist/planner/PlannerHelp.js.map +1 -0
  213. package/dist/planner/ProjectSidebar.js +246 -0
  214. package/dist/planner/ProjectSidebar.js.map +1 -0
  215. package/dist/planner/floors.js +18 -0
  216. package/dist/planner/floors.js.map +1 -0
  217. package/dist/planner/useDrawingTools.js +341 -0
  218. package/dist/planner/useDrawingTools.js.map +1 -0
  219. package/dist/planner/useMapDisplay.js +51 -0
  220. package/dist/planner/useMapDisplay.js.map +1 -0
  221. package/dist/planner/usePlannerKeyboard.js +138 -0
  222. package/dist/planner/usePlannerKeyboard.js.map +1 -0
  223. package/dist/planner/useReferenceAlignment.js +50 -0
  224. package/dist/planner/useReferenceAlignment.js.map +1 -0
  225. package/dist/styles.css +4931 -0
  226. package/dist/theme/index.js +34 -0
  227. package/dist/theme/index.js.map +1 -0
  228. package/dist/types/SitePlanner.d.ts +5 -0
  229. package/dist/types/adapters/basemap.d.ts +2 -0
  230. package/dist/types/adapters/persistence.d.ts +29 -0
  231. package/dist/types/adapters/status.d.ts +4 -0
  232. package/dist/types/adapters/useProjectPersistence.d.ts +13 -0
  233. package/dist/types/components/AiImportPanel.d.ts +9 -0
  234. package/dist/types/components/AnalysisPreview.d.ts +4 -0
  235. package/dist/types/components/ElevatorPanel.d.ts +18 -0
  236. package/dist/types/components/Icons.d.ts +8 -0
  237. package/dist/types/components/ImportDialog.d.ts +42 -0
  238. package/dist/types/components/Inspector.d.ts +38 -0
  239. package/dist/types/components/NavigatePanel.d.ts +27 -0
  240. package/dist/types/components/NavigationGraph.d.ts +10 -0
  241. package/dist/types/components/StructureExplorer.d.ts +8 -0
  242. package/dist/types/components/StructureView.d.ts +22 -0
  243. package/dist/types/components/controls.d.ts +52 -0
  244. package/dist/types/components/graphLayout.d.ts +9 -0
  245. package/dist/types/editor/host.d.ts +9 -0
  246. package/dist/types/editor/index.d.ts +2 -0
  247. package/dist/types/i18n.d.ts +85 -0
  248. package/dist/types/import/analysisPreview.d.ts +27 -0
  249. package/dist/types/import/brief.d.ts +22 -0
  250. package/dist/types/import/checkpoint.d.ts +49 -0
  251. package/dist/types/import/detect.d.ts +34 -0
  252. package/dist/types/import/documentSvg.d.ts +2 -0
  253. package/dist/types/import/index.d.ts +10 -0
  254. package/dist/types/import/instructions.d.ts +7 -0
  255. package/dist/types/import/openings.d.ts +22 -0
  256. package/dist/types/import/planImport.d.ts +22 -0
  257. package/dist/types/import/register.d.ts +25 -0
  258. package/dist/types/import/runs.d.ts +31 -0
  259. package/dist/types/import/session.d.ts +33 -0
  260. package/dist/types/import/types.d.ts +56 -0
  261. package/dist/types/import/usage.d.ts +10 -0
  262. package/dist/types/import/walls.d.ts +37 -0
  263. package/dist/types/map/CabinMaterials.d.ts +18 -0
  264. package/dist/types/map/CabinMirror.d.ts +13 -0
  265. package/dist/types/map/Doors.d.ts +11 -0
  266. package/dist/types/map/ElevatorCabin.d.ts +20 -0
  267. package/dist/types/map/FixtureLights.d.ts +35 -0
  268. package/dist/types/map/MapCanvas.d.ts +87 -0
  269. package/dist/types/map/Passenger.d.ts +18 -0
  270. package/dist/types/map/SceneLayer.d.ts +306 -0
  271. package/dist/types/map/UndergroundContext.d.ts +18 -0
  272. package/dist/types/map/ambience.d.ts +29 -0
  273. package/dist/types/map/architecture.d.ts +8 -0
  274. package/dist/types/map/bathMusic.d.ts +14 -0
  275. package/dist/types/map/cameraAim.d.ts +20 -0
  276. package/dist/types/map/elevators.d.ts +16 -0
  277. package/dist/types/map/excavation.d.ts +9 -0
  278. package/dist/types/map/exteriors.d.ts +3 -0
  279. package/dist/types/map/features.d.ts +33 -0
  280. package/dist/types/map/fences.d.ts +4 -0
  281. package/dist/types/map/journey.d.ts +36 -0
  282. package/dist/types/map/levels.d.ts +4 -0
  283. package/dist/types/map/lighting.d.ts +103 -0
  284. package/dist/types/map/loadBasemap.d.ts +4 -0
  285. package/dist/types/map/materials.d.ts +38 -0
  286. package/dist/types/map/poolLighting.d.ts +11 -0
  287. package/dist/types/map/projection.d.ts +9 -0
  288. package/dist/types/map/rampGeometry.d.ts +8 -0
  289. package/dist/types/map/route.d.ts +59 -0
  290. package/dist/types/map/stairSurfaces.d.ts +29 -0
  291. package/dist/types/map/surfaces.d.ts +36 -0
  292. package/dist/types/map/textures.d.ts +8 -0
  293. package/dist/types/map/underground.d.ts +30 -0
  294. package/dist/types/map/walk.d.ts +232 -0
  295. package/dist/types/map/walkContext.d.ts +11 -0
  296. package/dist/types/map/walkDimensions.d.ts +5 -0
  297. package/dist/types/map/walkJourney.d.ts +33 -0
  298. package/dist/types/map/walkSurfaces.d.ts +27 -0
  299. package/dist/types/map/wallJoins.d.ts +6 -0
  300. package/dist/types/map/water.d.ts +12 -0
  301. package/dist/types/model/authoring.d.ts +38 -0
  302. package/dist/types/model/boundaries.d.ts +41 -0
  303. package/dist/types/model/coverage.d.ts +8 -0
  304. package/dist/types/model/document.d.ts +9 -0
  305. package/dist/types/model/doors.d.ts +19 -0
  306. package/dist/types/model/factory.d.ts +5 -0
  307. package/dist/types/model/geometry.d.ts +99 -0
  308. package/dist/types/model/history.d.ts +10 -0
  309. package/dist/types/model/host.d.ts +154 -0
  310. package/dist/types/model/imports.d.ts +7 -0
  311. package/dist/types/model/inference.d.ts +46 -0
  312. package/dist/types/model/live.d.ts +60 -0
  313. package/dist/types/model/materials.d.ts +28 -0
  314. package/dist/types/model/mutations.d.ts +178 -0
  315. package/dist/types/model/navigation.d.ts +70 -0
  316. package/dist/types/model/ontology.d.ts +43 -0
  317. package/dist/types/model/passages.d.ts +2 -0
  318. package/dist/types/model/portals.d.ts +9 -0
  319. package/dist/types/model/precision.d.ts +11 -0
  320. package/dist/types/model/project.d.ts +8 -0
  321. package/dist/types/model/ramps.d.ts +7 -0
  322. package/dist/types/model/roomNavigation.d.ts +15 -0
  323. package/dist/types/model/routeClearance.d.ts +11 -0
  324. package/dist/types/model/spaces.d.ts +46 -0
  325. package/dist/types/model/stairGeometry.d.ts +27 -0
  326. package/dist/types/model/stairTraversal.d.ts +8 -0
  327. package/dist/types/model/topology.d.ts +14 -0
  328. package/dist/types/model/types.d.ts +369 -0
  329. package/dist/types/model/validate.d.ts +38 -0
  330. package/dist/types/model/vertical.d.ts +145 -0
  331. package/dist/types/model/walls.d.ts +71 -0
  332. package/dist/types/planner/DrawingDock.d.ts +16 -0
  333. package/dist/types/planner/FloorControls.d.ts +17 -0
  334. package/dist/types/planner/MapSettings.d.ts +16 -0
  335. package/dist/types/planner/PlannerHelp.d.ts +3 -0
  336. package/dist/types/planner/ProjectSidebar.d.ts +32 -0
  337. package/dist/types/planner/floors.d.ts +3 -0
  338. package/dist/types/planner/types.d.ts +3 -0
  339. package/dist/types/planner/useDrawingTools.d.ts +52 -0
  340. package/dist/types/planner/useMapDisplay.d.ts +29 -0
  341. package/dist/types/planner/usePlannerKeyboard.d.ts +18 -0
  342. package/dist/types/planner/useReferenceAlignment.d.ts +30 -0
  343. package/dist/types/schema/index.d.ts +25 -0
  344. package/dist/types/theme/index.d.ts +55 -0
  345. package/package.json +52 -4
@@ -0,0 +1,305 @@
1
+ import * as t from "three";
2
+ import { rotate as o0, openRing as Y, distance as n0, segmentProjection as j, pointInRing as r0 } from "../model/geometry.js";
3
+ import { metricUVs as e0 } from "./surfaces.js";
4
+ import { RoundedBoxGeometry as s0 } from "three/addons/geometries/RoundedBoxGeometry.js";
5
+ const a0 = (i, w = 0.8) => new t.MeshStandardMaterial({ color: i, roughness: w }), c = (i, w, S, d, m, n, z, D) => {
6
+ const Z = w > 0.35 && S > 0.25 && d > 0.1 ? new s0(w, S, d, 1, Math.min(0.035, d * 0.12)) : new t.BoxGeometry(w, S, d);
7
+ e0(Z);
8
+ const F = new t.Mesh(Z, D);
9
+ return F.position.set(m, n, z + d / 2), F.castShadow = !0, F.receiveShadow = !0, i.add(F), F;
10
+ };
11
+ function H(i, w, S, d, m) {
12
+ const n = S.clone().sub(w);
13
+ if (n.length() < 1e-3) return;
14
+ const z = new t.Mesh(new t.CylinderGeometry(d, d, n.length(), 10), m);
15
+ z.position.copy(w).add(S).multiplyScalar(0.5), z.quaternion.setFromUnitVectors(new t.Vector3(0, 1, 0), n.normalize()), z.castShadow = !0, i.add(z);
16
+ }
17
+ function c0() {
18
+ const i = [], w = [];
19
+ for (let d = 0; d < 2; d++)
20
+ for (let m = 0; m <= 10; m++) {
21
+ const n = m / 10;
22
+ i.push((n - 0.5) * 0.305, (d - 0.5) * 0.36, 0.02 + 0.025 * Math.sin(n * Math.PI * 2) + d * 0.012);
23
+ }
24
+ for (let d = 0; d < 10; d++)
25
+ w.push(d, d + 1, d + 12, d, d + 12, d + 11);
26
+ const S = new t.BufferGeometry();
27
+ return S.setAttribute("position", new t.Float32BufferAttribute(i, 3)), S.setIndex(w), S.computeVertexNormals(), S;
28
+ }
29
+ function f0(i, w, S, d) {
30
+ const m = new t.Group();
31
+ m.userData.entityId = S, m.userData.roof = !0;
32
+ const z = i.sections.reduce((o, u) => {
33
+ const v = Y(u.footprint);
34
+ return o + Math.abs(
35
+ v.reduce((b, y, x) => {
36
+ const e = v[(x + 1) % v.length];
37
+ return b + y[0] * e[1] - e[0] * y[1];
38
+ }, 0)
39
+ ) / 2;
40
+ }, 0) > 180, D = z ? d.get("roof", i.color) : new t.MeshStandardMaterial({
41
+ color: i.color,
42
+ roughness: 0.74,
43
+ metalness: 0.03,
44
+ side: t.DoubleSide
45
+ }), Z = d.solid("#b7b3a7"), F = d.metal("#4c5555"), r = c0();
46
+ function s(o, u, v) {
47
+ const b = w(u), y = w(v), x = w(j(u, ...o.ridge).point), e = w(j(v, ...o.ridge).point);
48
+ let a = [
49
+ new t.Vector3(...b, o.eave),
50
+ new t.Vector3(...y, o.eave),
51
+ new t.Vector3(...e, o.peak),
52
+ new t.Vector3(...x, o.peak)
53
+ ];
54
+ if (a = a.filter((f, p) => p === 0 || f.distanceTo(a[p - 1]) > 1e-3), a.length > 2 && a.at(-1).distanceTo(a[0]) < 1e-3 && a.pop(), a.length < 3) return;
55
+ let l = a[1].clone().sub(a[0]).cross(a[2].clone().sub(a[0])).normalize();
56
+ l.z < 0 && (a.reverse(), l.negate());
57
+ const h = a[1].clone().sub(a[0]).normalize(), R = l.clone().cross(h).normalize(), G = a[0], A = a.map((f) => [f.clone().sub(G).dot(h), f.clone().sub(G).dot(R)]), P = a.flatMap((f) => f.toArray()), N = [];
58
+ for (let f = 1; f < a.length - 1; f++) N.push(0, f, f + 1);
59
+ const V = new t.BufferGeometry();
60
+ V.setAttribute("position", new t.Float32BufferAttribute(P, 3)), V.setIndex(N), V.computeVertexNormals(), V.setAttribute("uv", new t.Float32BufferAttribute(A.flat(), 2));
61
+ const I = new t.Mesh(V, D);
62
+ I.castShadow = I.receiveShadow = !0, m.add(I);
63
+ const k = Math.min(...A.map((f) => f[0])), C = Math.max(...A.map((f) => f[0])), J = Math.min(...A.map((f) => f[1])), T = Math.max(...A.map((f) => f[1])), U = [], L = !z && (C - k) / 0.3 * ((T - J) / 0.33) <= 1200;
64
+ if (z) {
65
+ const f = Math.max(0.6, Math.ceil((C - k) / 108) * 0.6);
66
+ for (let p = Math.ceil(k / f) * f; p < C; p += f) {
67
+ const B = [];
68
+ A.forEach((g, q) => {
69
+ const E = A[(q + 1) % A.length];
70
+ (g[0] <= p && E[0] > p || E[0] <= p && g[0] > p) && B.push(g[1] + (E[1] - g[1]) * (p - g[0]) / (E[0] - g[0]));
71
+ }), B.sort((g, q) => g - q);
72
+ for (let g = 0; g + 1 < B.length; g += 2) {
73
+ const q = (E) => G.clone().addScaledVector(h, p).addScaledVector(R, E).addScaledVector(l, 0.025);
74
+ H(m, q(B[g]), q(B[g + 1]), 0.018, F);
75
+ }
76
+ }
77
+ }
78
+ if (L)
79
+ for (let f = J + 0.19; f < T; f += 0.33)
80
+ for (let p = k + 0.16; p < C; p += 0.3)
81
+ [
82
+ [-0.153, -0.18],
83
+ [0.153, -0.18],
84
+ [0.153, 0.18],
85
+ [-0.153, 0.18]
86
+ ].every(([B, g]) => r0([p + B, f + g], A)) && U.push(
87
+ new t.Matrix4().makeBasis(h, R, l).setPosition(G.clone().addScaledVector(h, p).addScaledVector(R, f).addScaledVector(l, 0.018))
88
+ );
89
+ if (U.length) {
90
+ const f = new t.InstancedMesh(r, D, U.length);
91
+ U.forEach((p, B) => {
92
+ f.setMatrixAt(B, p);
93
+ const g = new t.Color().setScalar(0.92 + B % 11 * 0.015);
94
+ f.setColorAt(B, g);
95
+ }), f.instanceMatrix.needsUpdate = !0, f.castShadow = f.receiveShadow = !0, m.add(f);
96
+ }
97
+ if (!L && !z) return;
98
+ const W = new t.Vector3(...b, o.eave - 0.08), K = new t.Vector3(...y, o.eave - 0.08);
99
+ H(m, W, K, 0.07, Z), H(
100
+ m,
101
+ W.clone().add(new t.Vector3(0, 0, -0.12)),
102
+ K.clone().add(new t.Vector3(0, 0, -0.12)),
103
+ 0.045,
104
+ F
105
+ ), L && x[0] === e[0] && x[1] === e[1] && H(
106
+ m,
107
+ new t.Vector3(...x, o.peak + 0.05),
108
+ new t.Vector3(...b, o.eave + 0.05),
109
+ 0.09,
110
+ D
111
+ );
112
+ }
113
+ return i.sections.forEach((o) => {
114
+ const u = Y(o.footprint);
115
+ if (Math.abs(o.peak - o.eave) < 1e-3) {
116
+ const b = new t.Shape(u.map((e) => new t.Vector2(...w(e)))), y = new t.ExtrudeGeometry(b, { depth: 0.14, bevelEnabled: !1 });
117
+ y.translate(0, 0, -0.14), e0(y);
118
+ const x = new t.Mesh(y, D);
119
+ x.position.z = o.peak, x.castShadow = x.receiveShadow = !0, m.add(x);
120
+ return;
121
+ }
122
+ u.forEach((b, y) => s(o, b, u[(y + 1) % u.length])), n0(o.ridge[0], o.ridge[1]) <= 26 && H(
123
+ m,
124
+ new t.Vector3(...w(o.ridge[0]), o.peak + 0.08),
125
+ new t.Vector3(...w(o.ridge[1]), o.peak + 0.08),
126
+ 0.13,
127
+ D
128
+ );
129
+ }), m.traverse((o) => {
130
+ o instanceof t.Mesh && (o.userData.entityId = S);
131
+ }), m;
132
+ }
133
+ function h0(i, w, S, d, m) {
134
+ const n = new t.Group(), [z, D] = w(i.position), Z = o0([1, 0], i.rotation), F = w([i.position[0] + Z[0], i.position[1] + Z[1]]);
135
+ n.position.set(z, D, S + (i.baseHeight ?? 0)), n.rotation.z = Math.atan2(F[1] - D, F[0] - z);
136
+ const r = i.width, s = i.depth, o = i.height, u = i.material ? d.get(i.material, i.color ?? "#f2f3ef") : d.solid(i.color ?? "#ddd7c8", i.model === "car" ? 0.3 : 0.72), v = d.get("oak", "#bca27e"), b = d.solid("#f1eee6"), y = d.solid("#3b4240"), x = d.metal("#858e8c");
137
+ if (i.model === "bed") {
138
+ c(n, r, s, 0.25, 0, 0, 0.12, v), c(n, r - 0.05, s - 0.05, 0.22, 0, 0, 0.37, b), c(n, r - 0.1, s * 0.67, 0.06, 0, -s * 0.12, 0.59, u), c(n, r, 0.09, 0.85, 0, s / 2, 0.06, v);
139
+ for (const e of r > 1.3 ? [-r * 0.24, r * 0.24] : [0]) {
140
+ const a = c(n, r > 1.3 ? r * 0.4 : r * 0.8, 0.43, 0.12, e, s * 0.32, 0.59, b);
141
+ a.rotation.z = 0.02;
142
+ }
143
+ } else if (i.model === "sofa") {
144
+ c(n, r, s, 0.4, 0, 0, 0.1, u), c(n, r, 0.19, 0.72, 0, s * 0.4, 0.1, u);
145
+ for (const e of [-r * 0.45, r * 0.45]) c(n, 0.15, s, 0.65, e, 0, 0.1, u);
146
+ for (let e = 0; e < 3; e++)
147
+ c(n, (r - 0.38) / 3 - 0.025, s * 0.7, 0.15, -(r - 0.38) / 3 + e * (r - 0.38) / 3, -0.03, 0.5, u);
148
+ } else if (i.model === "dining") {
149
+ c(n, r, s, 0.065, 0, 0, o, v);
150
+ for (const e of [-r * 0.4, r * 0.4])
151
+ for (const a of [-s * 0.35, s * 0.35]) c(n, 0.065, 0.065, o, e, a, 0, y);
152
+ if (o > 0.6)
153
+ for (const e of [-r * 0.3, r * 0.3])
154
+ for (const a of [-1, 1]) {
155
+ c(n, 0.43, 0.43, 0.07, e, a * (s / 2 + 0.38), 0.44, v), c(n, 0.43, 0.055, 0.43, e, a * (s / 2 + 0.59), 0.44, v);
156
+ for (const l of [-0.15, 0.15]) c(n, 0.045, 0.3, 0.44, e + l, a * (s / 2 + 0.38), 0, y);
157
+ }
158
+ } else if (i.model === "cabinet" || i.model === "counter") {
159
+ c(n, r, s, o, 0, 0, 0, u);
160
+ const e = Math.max(1, Math.round(r / 0.55));
161
+ for (let a = 0; a < e; a++) {
162
+ const l = -r / 2 + (a + 0.5) * r / e;
163
+ c(n, r / e - 0.015, 0.025, o - 0.06, l, -s / 2 - 0.015, 0.03, u), c(n, 0.018, 0.035, 0.18, l + r / e * 0.32, -s / 2 - 0.045, o * 0.55, x);
164
+ }
165
+ i.model === "counter" && c(n, r + 0.04, s + 0.035, 0.045, 0, 0, o, d.get("tile", "#777b73"));
166
+ } else if (i.model === "toilet") {
167
+ const e = new t.Mesh(new t.SphereGeometry(0.5, 16, 12), b);
168
+ e.scale.set(r, s * 0.8, 0.3), e.position.z = 0.35, n.add(e), c(n, r * 0.75, 0.15, 0.63, 0, s * 0.35, 0, b), c(n, r * 0.55, s * 0.5, 0.3, 0, 0, 0, b);
169
+ } else if (i.model === "basin") {
170
+ c(n, r, s, o - 0.12, 0, 0, 0, v), c(n, r + 0.04, s + 0.04, 0.1, 0, 0, o - 0.1, b);
171
+ const e = new t.Mesh(new t.SphereGeometry(0.2, 16, 8), a0("#b6c3c2"));
172
+ e.scale.set(1, 0.8, 0.15), e.position.z = o + 5e-3, n.add(e), H(n, new t.Vector3(0, s * 0.3, o), new t.Vector3(0, s * 0.3, o + 0.2), 0.022, x);
173
+ } else if (i.model === "sauna") {
174
+ for (let e = 0; e < 8; e++) c(n, r, 0.09, 0.06, 0, -s / 2 + e * s / 8, 0.48, v);
175
+ for (let e = 0; e < 5; e++) c(n, r, 0.095, 0.06, 0, s / 2 - 0.5 + e * 0.1, 0.98, v);
176
+ c(n, 0.3, 0.3, 0.6, r / 2 - 0.25, -s / 2 + 0.2, 0, y);
177
+ } else if (i.model === "shower") {
178
+ const e = new t.MeshStandardMaterial({
179
+ color: "#bbdbde",
180
+ transparent: !0,
181
+ opacity: 0.22,
182
+ roughness: 0.15,
183
+ side: t.DoubleSide,
184
+ depthWrite: !1
185
+ });
186
+ c(n, r, 0.025, o, 0, s / 2, 0, e), c(n, 0.025, s, o, r / 2, 0, 0, e), H(
187
+ n,
188
+ new t.Vector3(-r * 0.35, s * 0.4, 0.4),
189
+ new t.Vector3(-r * 0.35, s * 0.4, o - 0.1),
190
+ 0.015,
191
+ x
192
+ ), c(n, 0.22, 0.18, 0.025, -r * 0.35, s * 0.25, o - 0.1, x);
193
+ } else if (i.model === "tree" || i.model === "shrub") {
194
+ i.model === "tree" && H(
195
+ n,
196
+ new t.Vector3(0, 0, 0),
197
+ new t.Vector3(0.12, 0, o * 0.73),
198
+ 0.085,
199
+ d.get("plaster", "#dedbd0")
200
+ );
201
+ for (let e = 0; e < 9; e++) {
202
+ const a = d.shaded(
203
+ d.solid(e % 3 === 0 ? "#58764a" : e % 3 === 1 ? "#425f3b" : "#78945a", 0.95)
204
+ ), l = new t.IcosahedronGeometry(1, 2), h = l.getAttribute("position"), R = [];
205
+ for (let P = 0; P < h.count; P++) {
206
+ const N = h.getX(P), V = h.getY(P), I = h.getZ(P), k = 1 + Math.sin(N * 12 + e) * Math.sin(V * 9 - e) * Math.sin(I * 11) * 0.14;
207
+ h.setXYZ(P, N * k, V * k, I * k);
208
+ const C = 0.66 + (I + 1) * 0.17;
209
+ R.push(C, C, C);
210
+ }
211
+ l.setAttribute("color", new t.Float32BufferAttribute(R, 3)), l.computeVertexNormals();
212
+ const G = new t.Mesh(l, a), A = e * 2.399;
213
+ G.position.set(
214
+ Math.cos(A) * r * 0.24,
215
+ Math.sin(A) * s * 0.24,
216
+ i.model === "tree" ? o * 0.64 + e % 3 * 0.35 : o * 0.45
217
+ ), G.scale.set(r * 0.35, s * 0.35, i.model === "tree" ? o * 0.28 : o * 0.55), G.castShadow = G.receiveShadow = !0, n.add(G);
218
+ }
219
+ } else if (i.model === "lamp") {
220
+ if (H(n, new t.Vector3(0, 0, 0), new t.Vector3(0, 0, o), 0.035, y), c(
221
+ n,
222
+ 0.18,
223
+ 0.18,
224
+ 0.12,
225
+ 0,
226
+ 0,
227
+ o - 0.15,
228
+ new t.MeshStandardMaterial({ color: "#f4dfae", emissive: "#ffcf79", emissiveIntensity: m ? 2 : 0.2 })
229
+ ), m) {
230
+ const e = new t.PointLight("#ffd197", 9, 5, 2);
231
+ e.position.z = o, n.add(e);
232
+ }
233
+ } else if (i.model === "car") {
234
+ const e = new t.Group(), a = Math.max(r, s), l = Math.min(r, s), h = Math.max(1.2, o);
235
+ s > r && (e.rotation.z = Math.PI / 2), n.add(e);
236
+ const R = d.glass(m), G = d.solid("#23262a", 0.62), A = d.metal("#b3b8bc"), P = d.solid("#9c2f28", 0.42), N = h * 0.09, V = h * 0.2, I = h * 0.63, k = h * 0.73, C = h * 0.98, J = a * 0.3, T = h * 0.22, U = l * 0.12, L = a * 0.1, W = -a * 0.25, K = a * 0.02, f = -a * 0.19;
237
+ c(e, a - 0.3, l - 0.16, V - N, 0, 0, N, G), c(e, a - 0.5, l - 0.08, I - V, 0, 0, V, u);
238
+ for (const M of [-1, 1]) c(e, 0.3, l - 0.24, I - V - 0.04, M * (a / 2 - 0.14), 0, V, u);
239
+ for (const M of [-1, 1]) c(e, 0.34, l - 0.15, I - V - 0.02, M * (a / 2 - 0.29), 0, V, u);
240
+ c(e, a * 0.68, l, k - (I - 0.1), -a * 0.16, 0, I - 0.1, u);
241
+ for (const M of [-J, J]) c(e, T * 2.6, l + 0.05, h * 0.2, M, 0, h * 0.3, u);
242
+ const p = c(e, a / 2 - L, l - 0.07, h * 0.05, (a / 2 + L) / 2, 0, I - 0.03, u);
243
+ p.rotation.y = 0.03, c(e, a / 2 + W, l - 0.07, h * 0.05, (-a / 2 + W) / 2, 0, k - 0.02, u), c(e, K - f, l * 0.84, h * 0.05, (K + f) / 2, 0, C - h * 0.05, u);
244
+ for (const M of [-1, 1]) {
245
+ const O = c(
246
+ e,
247
+ L - W,
248
+ 0.03,
249
+ C - k,
250
+ (L + W) / 2,
251
+ M * l * 0.43,
252
+ k,
253
+ R
254
+ );
255
+ O.rotation.x = M * 0.1;
256
+ }
257
+ const B = (M, O, $) => {
258
+ const Q = C - k, _ = M - O, X = c(
259
+ e,
260
+ 0.03,
261
+ l * 0.76,
262
+ Math.hypot(Q, _),
263
+ (M + O) / 2,
264
+ 0,
265
+ (k + C) / 2 - Math.hypot(Q, _) / 2,
266
+ $
267
+ );
268
+ return X.rotation.y = -Math.atan2(_, Q), X;
269
+ };
270
+ B(L, K, R), B(W, f, R);
271
+ for (const M of [-1, 1]) c(e, 0.16, 0.1, 0.09, L - 0.1, M * (l / 2 + 0.04), k - 0.06, G);
272
+ const g = new t.CylinderGeometry(T, T, U, 20), q = new t.CylinderGeometry(T * 0.62, T * 0.62, U + 0.01, 14);
273
+ for (const M of [-J, J])
274
+ for (const O of [-1, 1]) {
275
+ const $ = O * (l / 2 - U / 2 - 0.015), Q = new t.Mesh(g, y);
276
+ Q.position.set(M, $, T), e.add(Q);
277
+ const _ = new t.Mesh(q, A);
278
+ _.position.set(M, $, T), e.add(_);
279
+ }
280
+ const E = a / 2 + 0.03;
281
+ c(e, 0.06, l * 0.42, h * 0.13, E, 0, h * 0.37, G), c(e, 0.06, l * 0.6, h * 0.09, E - 0.01, 0, V + 0.03, G);
282
+ const t0 = d.solid("#cfd3d0", 0.22);
283
+ for (const M of [-1, 1])
284
+ c(e, 0.07, l * 0.18, h * 0.06, E - 0.01, M * l * 0.28, h * 0.51, t0), c(e, 0.07, l * 0.2, h * 0.07, -E + 0.01, M * l * 0.27, h * 0.58, P);
285
+ c(e, 0.05, l * 0.26, 0.11, -E + 0.01, 0, h * 0.25, b);
286
+ } else if (i.model === "vent") {
287
+ const e = Math.min(r, s) * 0.4, a = new t.CatmullRomCurve3([
288
+ new t.Vector3(0, s * 0.1, o),
289
+ new t.Vector3(0, -s * 0.45, o),
290
+ new t.Vector3(0, -s * 0.7, o - e),
291
+ new t.Vector3(0, -s * 0.7, o - e * 1.8)
292
+ ]), l = new t.Mesh(new t.TubeGeometry(a, 16, e, 14, !1), d.metal("#394f48"));
293
+ n.add(l);
294
+ const h = new t.Mesh(new t.CircleGeometry(e * 0.94, 14), d.solid("#172722"));
295
+ h.position.set(0, -s * 0.7, o - e * 1.8), h.rotation.x = Math.PI, n.add(h);
296
+ } else i.model === "chimney" ? (c(n, r, s, o, 0, 0, 0, d.get("brick", i.color ?? "#c0b8a7")), c(n, r + 0.16, s + 0.16, 0.12, 0, 0, o, x)) : c(n, r, s, o, 0, 0, 0, u);
297
+ return n.traverse((e) => {
298
+ e instanceof t.Mesh && (e.userData.entityId = i.id, e.castShadow = !0, e.receiveShadow = !0);
299
+ }), n;
300
+ }
301
+ export {
302
+ h0 as makeFixture,
303
+ f0 as makeRoof
304
+ };
305
+ //# sourceMappingURL=architecture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architecture.js","sources":["../../../../src/map/architecture.ts"],"sourcesContent":["import * as THREE from 'three';\nimport type { BuildingRoof, Point, RoofSection, SiteObject } from '../model/types';\nimport { distance, openRing, pointInRing, rotate, segmentProjection } from '../model/geometry';\nimport { MaterialLibrary } from './materials';\nimport { metricUVs } from './surfaces';\nimport { RoundedBoxGeometry } from 'three/addons/geometries/RoundedBoxGeometry.js';\n\ntype ProjectXY = (point: Point) => Point;\nconst standard = (color: string, roughness = 0.8) => new THREE.MeshStandardMaterial({ color, roughness });\nconst box = (\n group: THREE.Group,\n w: number,\n d: number,\n h: number,\n x: number,\n y: number,\n z: number,\n material: THREE.Material,\n) => {\n const geometry =\n w > 0.35 && d > 0.25 && h > 0.1\n ? new RoundedBoxGeometry(w, d, h, 1, Math.min(0.035, h * 0.12))\n : new THREE.BoxGeometry(w, d, h);\n metricUVs(geometry);\n const mesh = new THREE.Mesh(geometry, material);\n mesh.position.set(x, y, z + h / 2);\n mesh.castShadow = true;\n mesh.receiveShadow = true;\n group.add(mesh);\n return mesh;\n};\nfunction cylinder(group: THREE.Group, a: THREE.Vector3, b: THREE.Vector3, r: number, material: THREE.Material) {\n const delta = b.clone().sub(a);\n if (delta.length() < 0.001) return;\n const mesh = new THREE.Mesh(new THREE.CylinderGeometry(r, r, delta.length(), 10), material);\n mesh.position.copy(a).add(b).multiplyScalar(0.5);\n mesh.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), delta.normalize());\n mesh.castShadow = true;\n group.add(mesh);\n}\n\nfunction tileGeometry() {\n const points: number[] = [],\n indices: number[] = [];\n for (let y = 0; y < 2; y++)\n for (let i = 0; i <= 10; i++) {\n const x = i / 10;\n points.push((x - 0.5) * 0.305, (y - 0.5) * 0.36, 0.02 + 0.025 * Math.sin(x * Math.PI * 2) + y * 0.012);\n }\n for (let i = 0; i < 10; i++) {\n indices.push(i, i + 1, i + 12, i, i + 12, i + 11);\n }\n const g = new THREE.BufferGeometry();\n g.setAttribute('position', new THREE.Float32BufferAttribute(points, 3));\n g.setIndex(indices);\n g.computeVertexNormals();\n return g;\n}\n\n/** Convex eaves fan into a ridge. Each plane receives actual interlocking tile geometry. */\nexport function makeRoof(\n roof: BuildingRoof,\n projectXY: ProjectXY,\n id: string,\n materials: MaterialLibrary,\n): THREE.Group {\n const group = new THREE.Group();\n group.userData.entityId = id;\n group.userData.roof = true;\n const area = roof.sections.reduce((sum, section) => {\n const ring = openRing(section.footprint);\n return (\n sum +\n Math.abs(\n ring.reduce((a, p, i) => {\n const q = ring[(i + 1) % ring.length];\n return a + p[0] * q[1] - q[0] * p[1];\n }, 0),\n ) /\n 2\n );\n }, 0);\n const sheetMetal = area > 180;\n const roofMaterial = sheetMetal\n ? materials.get('roof', roof.color)\n : new THREE.MeshStandardMaterial({\n color: roof.color,\n roughness: 0.74,\n metalness: 0.03,\n side: THREE.DoubleSide,\n });\n const trim = materials.solid('#b7b3a7'),\n gutter = materials.metal('#4c5555'),\n tiles = tileGeometry();\n function plane(section: RoofSection, a: Point, b: Point) {\n const pa = projectXY(a),\n pb = projectXY(b),\n ra = projectXY(segmentProjection(a, ...section.ridge).point),\n rb = projectXY(segmentProjection(b, ...section.ridge).point);\n let points = [\n new THREE.Vector3(...pa, section.eave),\n new THREE.Vector3(...pb, section.eave),\n new THREE.Vector3(...rb, section.peak),\n new THREE.Vector3(...ra, section.peak),\n ];\n points = points.filter((p, i) => i === 0 || p.distanceTo(points[i - 1]) > 0.001);\n if (points.length > 2 && points.at(-1)!.distanceTo(points[0]) < 0.001) points.pop();\n if (points.length < 3) return;\n let normal = points[1].clone().sub(points[0]).cross(points[2].clone().sub(points[0])).normalize();\n if (normal.z < 0) {\n points.reverse();\n normal.negate();\n }\n const u = points[1].clone().sub(points[0]).normalize(),\n v = normal.clone().cross(u).normalize(),\n base = points[0];\n const polygon = points.map(p => [p.clone().sub(base).dot(u), p.clone().sub(base).dot(v)] as Point);\n const positions = points.flatMap(p => p.toArray()),\n indices: number[] = [];\n for (let i = 1; i < points.length - 1; i++) indices.push(0, i, i + 1);\n const geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n geometry.setIndex(indices);\n geometry.computeVertexNormals();\n geometry.setAttribute('uv', new THREE.Float32BufferAttribute(polygon.flat(), 2));\n const face = new THREE.Mesh(geometry, roofMaterial);\n face.castShadow = face.receiveShadow = true;\n group.add(face);\n const minX = Math.min(...polygon.map(p => p[0])),\n maxX = Math.max(...polygon.map(p => p[0])),\n minY = Math.min(...polygon.map(p => p[1])),\n maxY = Math.max(...polygon.map(p => p[1]));\n const matrices: THREE.Matrix4[] = [];\n // Clay tiles, fascia boards, gutters and ridge poles are all house-scale flourishes. On a large\n // roof the tile scan alone runs to hundreds of thousands of iterations — each with a point-in-ring\n // test — and emits as many instances; the trims meanwhile draw as bright seams straight across\n // what should read as one sheet. Past a modest budget the plane is left plain, which is what the\n // roof of a department store or a warehouse actually is.\n const detailed = !sheetMetal && ((maxX - minX) / 0.3) * ((maxY - minY) / 0.33) <= 1200;\n if (sheetMetal) {\n // Raised standing seams remain legible when texture mipmaps fade at city scale.\n const spacing = Math.max(0.6, Math.ceil((maxX - minX) / 108) * 0.6);\n for (let x = Math.ceil(minX / spacing) * spacing; x < maxX; x += spacing) {\n const cuts: number[] = [];\n polygon.forEach((a, i) => {\n const b = polygon[(i + 1) % polygon.length];\n if ((a[0] <= x && b[0] > x) || (b[0] <= x && a[0] > x))\n cuts.push(a[1] + ((b[1] - a[1]) * (x - a[0])) / (b[0] - a[0]));\n });\n cuts.sort((a, b) => a - b);\n for (let i = 0; i + 1 < cuts.length; i += 2) {\n const at = (y: number) =>\n base.clone().addScaledVector(u, x).addScaledVector(v, y).addScaledVector(normal, 0.025);\n cylinder(group, at(cuts[i]), at(cuts[i + 1]), 0.018, gutter);\n }\n }\n }\n if (detailed)\n for (let y = minY + 0.19; y < maxY; y += 0.33)\n for (let x = minX + 0.16; x < maxX; x += 0.3) {\n if (\n !(\n [\n [-0.153, -0.18],\n [0.153, -0.18],\n [0.153, 0.18],\n [-0.153, 0.18],\n ] as Point[]\n ).every(([dx, dy]) => pointInRing([x + dx, y + dy], polygon))\n )\n continue;\n matrices.push(\n new THREE.Matrix4()\n .makeBasis(u, v, normal)\n .setPosition(base.clone().addScaledVector(u, x).addScaledVector(v, y).addScaledVector(normal, 0.018)),\n );\n }\n if (matrices.length) {\n const batch = new THREE.InstancedMesh(tiles, roofMaterial, matrices.length);\n matrices.forEach((matrix, i) => {\n batch.setMatrixAt(i, matrix);\n const tone = new THREE.Color().setScalar(0.92 + (i % 11) * 0.015);\n batch.setColorAt(i, tone);\n });\n batch.instanceMatrix.needsUpdate = true;\n batch.castShadow = batch.receiveShadow = true;\n group.add(batch);\n }\n if (!detailed && !sheetMetal) return;\n // White fascia and rain gutter along the eave.\n const edgeA = new THREE.Vector3(...pa, section.eave - 0.08),\n edgeB = new THREE.Vector3(...pb, section.eave - 0.08);\n cylinder(group, edgeA, edgeB, 0.07, trim);\n cylinder(\n group,\n edgeA.clone().add(new THREE.Vector3(0, 0, -0.12)),\n edgeB.clone().add(new THREE.Vector3(0, 0, -0.12)),\n 0.045,\n gutter,\n );\n if (detailed && ra[0] === rb[0] && ra[1] === rb[1])\n cylinder(\n group,\n new THREE.Vector3(...ra, section.peak + 0.05),\n new THREE.Vector3(...pa, section.eave + 0.05),\n 0.09,\n roofMaterial,\n );\n }\n roof.sections.forEach(section => {\n const outline = openRing(section.footprint);\n // A section with no fall is a deck, not a pitch. Fanning it from the ridge the way a sloped plane\n // is fanned lays overlapping coplanar quads over each other, whose per-quad normals disagree just\n // enough to show as creases across what should be one flat surface. Triangulate it once instead.\n if (Math.abs(section.peak - section.eave) < 0.001) {\n const shape = new THREE.Shape(outline.map(pt => new THREE.Vector2(...projectXY(pt))));\n const geometry = new THREE.ExtrudeGeometry(shape, { depth: 0.14, bevelEnabled: false });\n geometry.translate(0, 0, -0.14);\n metricUVs(geometry);\n const deck = new THREE.Mesh(geometry, roofMaterial);\n deck.position.z = section.peak;\n deck.castShadow = deck.receiveShadow = true;\n group.add(deck);\n return;\n }\n outline.forEach((a, i) => plane(section, a, outline[(i + 1) % outline.length]));\n const ridgeLength = distance(section.ridge[0], section.ridge[1]);\n if (ridgeLength <= 26)\n cylinder(\n group,\n new THREE.Vector3(...projectXY(section.ridge[0]), section.peak + 0.08),\n new THREE.Vector3(...projectXY(section.ridge[1]), section.peak + 0.08),\n 0.13,\n roofMaterial,\n );\n });\n group.traverse(o => {\n if (o instanceof THREE.Mesh) o.userData.entityId = id;\n });\n return group;\n}\n\nexport function makeFixture(\n o: SiteObject,\n projectXY: ProjectXY,\n z: number,\n materials: MaterialLibrary,\n evening: boolean,\n): THREE.Group {\n const group = new THREE.Group(),\n [x, y] = projectXY(o.position),\n direction = rotate([1, 0], o.rotation),\n along = projectXY([o.position[0] + direction[0], o.position[1] + direction[1]]);\n group.position.set(x, y, z + (o.baseHeight ?? 0));\n group.rotation.z = Math.atan2(along[1] - y, along[0] - x);\n const w = o.width,\n d = o.depth,\n h = o.height,\n paint = o.material\n ? materials.get(o.material, o.color ?? '#f2f3ef')\n : materials.solid(o.color ?? '#ddd7c8', o.model === 'car' ? 0.3 : 0.72),\n wood = materials.get('oak', '#bca27e'),\n white = materials.solid('#f1eee6'),\n dark = materials.solid('#3b4240'),\n metal = materials.metal('#858e8c');\n if (o.model === 'bed') {\n box(group, w, d, 0.25, 0, 0, 0.12, wood);\n box(group, w - 0.05, d - 0.05, 0.22, 0, 0, 0.37, white);\n box(group, w - 0.1, d * 0.67, 0.06, 0, -d * 0.12, 0.59, paint);\n box(group, w, 0.09, 0.85, 0, d / 2, 0.06, wood);\n for (const px of w > 1.3 ? [-w * 0.24, w * 0.24] : [0]) {\n const pillow = box(group, w > 1.3 ? w * 0.4 : w * 0.8, 0.43, 0.12, px, d * 0.32, 0.59, white);\n pillow.rotation.z = 0.02;\n }\n } else if (o.model === 'sofa') {\n box(group, w, d, 0.4, 0, 0, 0.1, paint);\n box(group, w, 0.19, 0.72, 0, d * 0.4, 0.1, paint);\n for (const x of [-w * 0.45, w * 0.45]) box(group, 0.15, d, 0.65, x, 0, 0.1, paint);\n for (let i = 0; i < 3; i++)\n box(group, (w - 0.38) / 3 - 0.025, d * 0.7, 0.15, -(w - 0.38) / 3 + (i * (w - 0.38)) / 3, -0.03, 0.5, paint);\n } else if (o.model === 'dining') {\n box(group, w, d, 0.065, 0, 0, h, wood);\n for (const x of [-w * 0.4, w * 0.4])\n for (const y of [-d * 0.35, d * 0.35]) box(group, 0.065, 0.065, h, x, y, 0, dark);\n if (h > 0.6)\n for (const x of [-w * 0.3, w * 0.3])\n for (const y of [-1, 1]) {\n box(group, 0.43, 0.43, 0.07, x, y * (d / 2 + 0.38), 0.44, wood);\n box(group, 0.43, 0.055, 0.43, x, y * (d / 2 + 0.59), 0.44, wood);\n for (const dx of [-0.15, 0.15]) box(group, 0.045, 0.3, 0.44, x + dx, y * (d / 2 + 0.38), 0, dark);\n }\n } else if (o.model === 'cabinet' || o.model === 'counter') {\n box(group, w, d, h, 0, 0, 0, paint);\n const panels = Math.max(1, Math.round(w / 0.55));\n for (let i = 0; i < panels; i++) {\n const x = -w / 2 + ((i + 0.5) * w) / panels;\n box(group, w / panels - 0.015, 0.025, h - 0.06, x, -d / 2 - 0.015, 0.03, paint);\n box(group, 0.018, 0.035, 0.18, x + (w / panels) * 0.32, -d / 2 - 0.045, h * 0.55, metal);\n }\n if (o.model === 'counter') box(group, w + 0.04, d + 0.035, 0.045, 0, 0, h, materials.get('tile', '#777b73'));\n } else if (o.model === 'toilet') {\n const bowl = new THREE.Mesh(new THREE.SphereGeometry(0.5, 16, 12), white);\n bowl.scale.set(w, d * 0.8, 0.3);\n bowl.position.z = 0.35;\n group.add(bowl);\n box(group, w * 0.75, 0.15, 0.63, 0, d * 0.35, 0, white);\n box(group, w * 0.55, d * 0.5, 0.3, 0, 0, 0, white);\n } else if (o.model === 'basin') {\n box(group, w, d, h - 0.12, 0, 0, 0, wood);\n box(group, w + 0.04, d + 0.04, 0.1, 0, 0, h - 0.1, white);\n const bowl = new THREE.Mesh(new THREE.SphereGeometry(0.2, 16, 8), standard('#b6c3c2'));\n bowl.scale.set(1, 0.8, 0.15);\n bowl.position.z = h + 0.005;\n group.add(bowl);\n cylinder(group, new THREE.Vector3(0, d * 0.3, h), new THREE.Vector3(0, d * 0.3, h + 0.2), 0.022, metal);\n } else if (o.model === 'sauna') {\n for (let i = 0; i < 8; i++) box(group, w, 0.09, 0.06, 0, -d / 2 + (i * d) / 8, 0.48, wood);\n for (let i = 0; i < 5; i++) box(group, w, 0.095, 0.06, 0, d / 2 - 0.5 + i * 0.1, 0.98, wood);\n box(group, 0.3, 0.3, 0.6, w / 2 - 0.25, -d / 2 + 0.2, 0, dark);\n } else if (o.model === 'shower') {\n const glass = new THREE.MeshStandardMaterial({\n color: '#bbdbde',\n transparent: true,\n opacity: 0.22,\n roughness: 0.15,\n side: THREE.DoubleSide,\n depthWrite: false,\n });\n box(group, w, 0.025, h, 0, d / 2, 0, glass);\n box(group, 0.025, d, h, w / 2, 0, 0, glass);\n cylinder(\n group,\n new THREE.Vector3(-w * 0.35, d * 0.4, 0.4),\n new THREE.Vector3(-w * 0.35, d * 0.4, h - 0.1),\n 0.015,\n metal,\n );\n box(group, 0.22, 0.18, 0.025, -w * 0.35, d * 0.25, h - 0.1, metal);\n } else if (o.model === 'tree' || o.model === 'shrub') {\n if (o.model === 'tree')\n cylinder(\n group,\n new THREE.Vector3(0, 0, 0),\n new THREE.Vector3(0.12, 0, h * 0.73),\n 0.085,\n materials.get('plaster', '#dedbd0'),\n );\n for (let i = 0; i < 9; i++) {\n const leaf = materials.shaded(\n materials.solid(i % 3 === 0 ? '#58764a' : i % 3 === 1 ? '#425f3b' : '#78945a', 0.95),\n );\n const geometry = new THREE.IcosahedronGeometry(1, 2);\n const vertices = geometry.getAttribute('position');\n const shades: number[] = [];\n for (let j = 0; j < vertices.count; j++) {\n const x = vertices.getX(j),\n y = vertices.getY(j),\n z = vertices.getZ(j);\n const r = 1 + Math.sin(x * 12 + i) * Math.sin(y * 9 - i) * Math.sin(z * 11) * 0.14;\n vertices.setXYZ(j, x * r, y * r, z * r);\n const shade = 0.66 + (z + 1) * 0.17;\n shades.push(shade, shade, shade);\n }\n geometry.setAttribute('color', new THREE.Float32BufferAttribute(shades, 3));\n geometry.computeVertexNormals();\n const mesh = new THREE.Mesh(geometry, leaf);\n const t = i * 2.399;\n mesh.position.set(\n Math.cos(t) * w * 0.24,\n Math.sin(t) * d * 0.24,\n o.model === 'tree' ? h * 0.64 + (i % 3) * 0.35 : h * 0.45,\n );\n mesh.scale.set(w * 0.35, d * 0.35, o.model === 'tree' ? h * 0.28 : h * 0.55);\n mesh.castShadow = mesh.receiveShadow = true;\n group.add(mesh);\n }\n } else if (o.model === 'lamp') {\n cylinder(group, new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, h), 0.035, dark);\n box(\n group,\n 0.18,\n 0.18,\n 0.12,\n 0,\n 0,\n h - 0.15,\n new THREE.MeshStandardMaterial({ color: '#f4dfae', emissive: '#ffcf79', emissiveIntensity: evening ? 2 : 0.2 }),\n );\n if (evening) {\n const light = new THREE.PointLight('#ffd197', 9, 5, 2);\n light.position.z = h;\n group.add(light);\n }\n } else if (o.model === 'car') {\n // A car is built along its long axis whichever of width and depth the author made the long one:\n // the garage draws its cars 4.5 wide and 1.85 deep, pointing down the bay. Local X is the\n // length from here on, +X the nose.\n //\n // The proportions are a European saloon's, which is what a Helsinki car park is full of: a long\n // bonnet, a short deck, and the glasshouse set well back over the rear axle. That set-back is\n // most of what makes a car read as a car rather than as a box with a smaller box on it — get it\n // wrong and you have drawn a van.\n const car = new THREE.Group();\n const L = Math.max(w, d),\n W = Math.min(w, d),\n H = Math.max(1.2, h);\n if (d > w) car.rotation.z = Math.PI / 2;\n group.add(car);\n const glass = materials.glass(evening);\n const trim = materials.solid('#23262a', 0.62); // grille, sills, the shadow under the car\n const chrome = materials.metal('#b3b8bc');\n const tail = materials.solid('#9c2f28', 0.42);\n // Heights, as fractions of the authored height so an odd one still builds a car.\n const clear = H * 0.09, // the air under the sills\n sill = H * 0.2, // where the painted flank starts\n bonnet = H * 0.63, // the nose: a saloon's bonnet sits well below its door tops\n belt = H * 0.73, // the shoulder: top of the doors, bottom of the glass\n roof = H * 0.98;\n // A 2.7 m wheelbase in a 4.5 m car — short overhangs, which is the other half of the look.\n const axle = L * 0.3,\n tyreR = H * 0.22,\n tyreW = W * 0.12;\n // The glasshouse, set back: the windscreen base sits just behind the front axle.\n const screenFoot = L * 0.1,\n backFoot = -L * 0.25,\n screenTop = L * 0.02,\n backTop = -L * 0.19;\n box(car, L - 0.3, W - 0.16, sill - clear, 0, 0, clear, trim);\n // The flank in bands. The whole length rises only to bonnet height; the shoulder — the top of\n // the doors — is a second band over the rear two thirds. That step is the saloon profile, and\n // it is what one full-length block gets wrong: carry the beltline forward over the wings and\n // you have drawn a van, whatever you then put on the roof.\n box(car, L - 0.5, W - 0.08, bonnet - sill, 0, 0, sill, paint);\n // The last hand's width at each end is drawn in, so the car does not end in a flat wall.\n for (const end of [-1, 1]) box(car, 0.3, W - 0.24, bonnet - sill - 0.04, end * (L / 2 - 0.14), 0, sill, paint);\n for (const end of [-1, 1]) box(car, 0.34, W - 0.15, bonnet - sill - 0.02, end * (L / 2 - 0.29), 0, sill, paint);\n box(car, L * 0.68, W, belt - (bonnet - 0.1), -L * 0.16, 0, bonnet - 0.1, paint);\n // Blistered arches over each axle, so the wheels stand in something.\n for (const x of [-axle, axle]) box(car, tyreR * 2.6, W + 0.05, H * 0.2, x, 0, H * 0.3, paint);\n // The bonnet, dropping a little toward the nose, and the boot lid a touch above the shoulder.\n const lid = box(car, L / 2 - screenFoot, W - 0.07, H * 0.05, (L / 2 + screenFoot) / 2, 0, bonnet - 0.03, paint);\n lid.rotation.y = 0.03;\n box(car, L / 2 + backFoot, W - 0.07, H * 0.05, (-L / 2 + backFoot) / 2, 0, belt - 0.02, paint);\n // Roof, narrower than the shoulder: a greenhouse that tapers is what stops the cabin reading as\n // a crate. The screens rake off it at each end.\n box(car, screenTop - backTop, W * 0.84, H * 0.05, (screenTop + backTop) / 2, 0, roof - H * 0.05, paint);\n for (const side of [-1, 1]) {\n const pane = box(\n car,\n screenFoot - backFoot,\n 0.03,\n roof - belt,\n (screenFoot + backFoot) / 2,\n side * W * 0.43,\n belt,\n glass,\n );\n pane.rotation.x = side * 0.1; // tumblehome: the glass leans in at the top\n }\n const rake = (foot: number, top: number, material: THREE.Material) => {\n const rise = roof - belt,\n run = foot - top;\n const pane = box(\n car,\n 0.03,\n W * 0.76,\n Math.hypot(rise, run),\n (foot + top) / 2,\n 0,\n (belt + roof) / 2 - Math.hypot(rise, run) / 2,\n material,\n );\n // A windscreen leans BACK: its top is rearward of its foot, which for a +X nose is a negative\n // rotation about the width axis. The rear screen leans the other way by the same rule.\n pane.rotation.y = -Math.atan2(run, rise);\n return pane;\n };\n rake(screenFoot, screenTop, glass);\n rake(backFoot, backTop, glass);\n // Mirrors on the A-pillar, which is most of what a car's plan silhouette is.\n for (const side of [-1, 1]) box(car, 0.16, 0.1, 0.09, screenFoot - 0.1, side * (W / 2 + 0.04), belt - 0.06, trim);\n // Wheels: the axle runs across the car, so a cylinder's own Y axis is already the right way up.\n const tyre = new THREE.CylinderGeometry(tyreR, tyreR, tyreW, 20),\n rim = new THREE.CylinderGeometry(tyreR * 0.62, tyreR * 0.62, tyreW + 0.01, 14);\n for (const x of [-axle, axle])\n for (const y of [-1, 1]) {\n const at = y * (W / 2 - tyreW / 2 - 0.015);\n const wheel = new THREE.Mesh(tyre, dark);\n wheel.position.set(x, at, tyreR);\n car.add(wheel);\n const cap = new THREE.Mesh(rim, chrome);\n cap.position.set(x, at, tyreR);\n car.add(cap);\n }\n // The face: a grille between the headlamps, an intake under it, and lamps that wrap a little\n // way down the wing. Nothing here is fine detail — at eye level in a bay it is all you see.\n // Proud of the chamfer, or the drawn-in nose swallows every one of them.\n const nose = L / 2 + 0.03;\n box(car, 0.06, W * 0.42, H * 0.13, nose, 0, H * 0.37, trim);\n box(car, 0.06, W * 0.6, H * 0.09, nose - 0.01, 0, sill + 0.03, trim);\n const lens = materials.solid('#cfd3d0', 0.22);\n for (const y of [-1, 1]) {\n box(car, 0.07, W * 0.18, H * 0.06, nose - 0.01, y * W * 0.28, H * 0.51, lens);\n box(car, 0.07, W * 0.2, H * 0.07, -nose + 0.01, y * W * 0.27, H * 0.58, tail);\n }\n box(car, 0.05, W * 0.26, 0.11, -nose + 0.01, 0, H * 0.25, white);\n } else if (o.model === 'vent') {\n const radius = Math.min(w, d) * 0.4;\n const pipe = new THREE.CatmullRomCurve3([\n new THREE.Vector3(0, d * 0.1, h),\n new THREE.Vector3(0, -d * 0.45, h),\n new THREE.Vector3(0, -d * 0.7, h - radius),\n new THREE.Vector3(0, -d * 0.7, h - radius * 1.8),\n ]);\n const duct = new THREE.Mesh(new THREE.TubeGeometry(pipe, 16, radius, 14, false), materials.metal('#394f48'));\n group.add(duct);\n const mouth = new THREE.Mesh(new THREE.CircleGeometry(radius * 0.94, 14), materials.solid('#172722'));\n mouth.position.set(0, -d * 0.7, h - radius * 1.8);\n mouth.rotation.x = Math.PI;\n group.add(mouth);\n } else if (o.model === 'chimney') {\n box(group, w, d, h, 0, 0, 0, materials.get('brick', o.color ?? '#c0b8a7'));\n box(group, w + 0.16, d + 0.16, 0.12, 0, 0, h, metal);\n } else box(group, w, d, h, 0, 0, 0, paint);\n group.traverse(child => {\n if (child instanceof THREE.Mesh) {\n child.userData.entityId = o.id;\n child.castShadow = true;\n child.receiveShadow = true;\n }\n });\n return group;\n}\n"],"names":["standard","color","roughness","THREE","box","group","d","h","x","y","material","geometry","RoundedBoxGeometry","metricUVs","mesh","cylinder","a","b","r","delta","tileGeometry","points","indices","i","g","makeRoof","roof","projectXY","id","materials","sheetMetal","sum","section","ring","openRing","p","q","roofMaterial","trim","gutter","tiles","plane","pa","pb","ra","segmentProjection","rb","normal","u","v","base","polygon","positions","face","minX","maxX","minY","maxY","matrices","detailed","spacing","cuts","at","dx","dy","pointInRing","batch","matrix","tone","edgeA","edgeB","outline","shape","pt","deck","distance","makeFixture","o","z","evening","direction","rotate","along","w","paint","wood","white","dark","metal","px","pillow","panels","bowl","glass","leaf","vertices","shades","j","shade","t","light","car","L","W","H","chrome","tail","clear","sill","bonnet","belt","axle","tyreR","tyreW","screenFoot","backFoot","screenTop","backTop","end","lid","side","pane","rake","foot","top","rise","run","tyre","rim","wheel","cap","nose","lens","radius","pipe","duct","mouth","child"],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ const N = [
2
+ { chord: [50, 57, 60, 65], melody: [76, 74, 69] },
3
+ // Dm7, with a ninth in the melody
4
+ { chord: [53, 60, 64, 69], melody: [72, 76, 69] },
5
+ // Fmaj7
6
+ { chord: [48, 55, 62, 67], melody: [74, 79, 76] },
7
+ // Csus2
8
+ { chord: [43, 57, 62, 65], melody: [77, 74, 69] }
9
+ // Gm9, open voicing
10
+ ], P = (e) => 440 * 2 ** ((e - 69) / 12), S = /* @__PURE__ */ new WeakMap();
11
+ function Q(e) {
12
+ const t = S.get(e);
13
+ if (t) return t;
14
+ const c = 6, p = e.createBuffer(2, Math.ceil(e.sampleRate * c), e.sampleRate);
15
+ let r = 1886351212;
16
+ for (let d = 0; d < 2; d++) {
17
+ const u = p.getChannelData(d);
18
+ for (let m = 0; m < u.length; m++) {
19
+ r = Math.imul(r, 1664525) + 1013904223 | 0;
20
+ const s = m / e.sampleRate;
21
+ u[m] = s < 0.045 ? 0 : ((r >>> 0) / 4294967295 * 2 - 1) * Math.exp(-s / 1.25) * (1 - s / c) ** 2;
22
+ }
23
+ }
24
+ return S.set(e, p), p;
25
+ }
26
+ const _ = (e, t) => q(e, t, !1), j = (e, t) => q(e, t, !0);
27
+ function q(e, t, c) {
28
+ const p = 60 / (c ? 88 : 48), r = p * 8, d = c ? [
29
+ { chord: [48, 55, 59, 64], melody: [76, 79, 74] },
30
+ { chord: [45, 52, 55, 60], melody: [72, 76, 71] },
31
+ { chord: [50, 57, 60, 65], melody: [74, 77, 76] },
32
+ { chord: [43, 53, 57, 62], melody: [74, 71, 72] }
33
+ ] : N, u = [], m = [], s = e.createGain();
34
+ s.gain.setValueAtTime(0, e.currentTime), s.gain.linearRampToValueAtTime(1, e.currentTime + 0.6);
35
+ const h = e.createBiquadFilter();
36
+ h.type = "lowpass", h.frequency.value = 3200, h.Q.value = 0.5;
37
+ const y = e.createGain();
38
+ y.gain.value = 0.72;
39
+ const A = e.createConvolver();
40
+ A.buffer = Q(e);
41
+ const R = e.createGain();
42
+ R.gain.value = c ? 0.09 : 0.48, s.connect(h), h.connect(y).connect(t), h.connect(A).connect(R).connect(t), u.push(s, h, y, A, R);
43
+ const w = (l, i) => {
44
+ const n = e.createGain();
45
+ n.gain.value = 0;
46
+ const V = e.createStereoPanner();
47
+ V.pan.value = l, n.connect(V).connect(s), u.push(n, V);
48
+ const z = [1, i ? 2.002 : 1].map((M, o) => {
49
+ const a = e.createOscillator();
50
+ a.type = !i && o === 1 ? "triangle" : "sine", a.detune.value = i ? 0 : o ? 3 : -3;
51
+ const T = e.createGain();
52
+ return T.gain.value = o ? i ? 0.22 : 0.3 : 1, a.connect(T).connect(n), a.start(), u.push(T), m.push(a), { oscillator: a, ratio: M };
53
+ });
54
+ return { note: (M, o, a, T, F, O) => {
55
+ for (const { oscillator: H, ratio: I } of z) H.frequency.setValueAtTime(P(M) * I, o);
56
+ const g = n.gain;
57
+ g.setValueAtTime(0, o), g.linearRampToValueAtTime(a, o + T), g.setValueAtTime(a, o + T + F), g.exponentialRampToValueAtTime(1e-5, o + O - 0.05), g.linearRampToValueAtTime(0, o + O);
58
+ } };
59
+ }, B = [-0.55, 0.25, -0.2, 0.6].map((l) => w(l, !1)), b = [-0.4, 0.3, 0.5, -0.25].map((l) => w(l, !0));
60
+ let f = e.currentTime + 0.05, v = 0, D = 0, C = !1, E;
61
+ const G = () => {
62
+ if (!C) {
63
+ for (; f < e.currentTime; )
64
+ f += r, v++;
65
+ for (; f < e.currentTime + r * 2; ) {
66
+ const l = d[v % d.length];
67
+ l.chord.forEach(
68
+ (i, n) => B[n].note(i, f, n ? 0.045 : 0.055, c ? 0.08 : 2, c ? 1.5 : 3, r)
69
+ ), l.melody.forEach((i, n) => {
70
+ b[D++ % b.length].note(i, f + [1, 3.5, 6][n] * p, 0.065, 0.025, 0, c ? 1.5 : 3.8);
71
+ }), f += r, v++;
72
+ }
73
+ E = setTimeout(G, 1e3);
74
+ }
75
+ };
76
+ return G(), {
77
+ nodes: u,
78
+ sources: [
79
+ ...m,
80
+ {
81
+ stop() {
82
+ C = !0, clearTimeout(E);
83
+ }
84
+ }
85
+ ]
86
+ };
87
+ }
88
+ export {
89
+ _ as bathMusic,
90
+ j as elevatorMusic
91
+ };
92
+ //# sourceMappingURL=bathMusic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bathMusic.js","sources":["../../../../src/map/bathMusic.ts"],"sourcesContent":["/** An original, quiet score for the tiled baths: suspended chords and a sparse glass-bell melody.\n * Synthesised locally, with a repeating forty-second phrase and a long stereo room tail. */\n\nconst SCORE = [\n { chord: [50, 57, 60, 65], melody: [76, 74, 69] }, // Dm7, with a ninth in the melody\n { chord: [53, 60, 64, 69], melody: [72, 76, 69] }, // Fmaj7\n { chord: [48, 55, 62, 67], melody: [74, 79, 76] }, // Csus2\n { chord: [43, 57, 62, 65], melody: [77, 74, 69] }, // Gm9, open voicing\n];\nconst hz = (midi: number) => 440 * 2 ** ((midi - 69) / 12);\nconst impulses = new WeakMap<BaseAudioContext, AudioBuffer>();\n\nfunction roomImpulse(ctx: BaseAudioContext) {\n const cached = impulses.get(ctx);\n if (cached) return cached;\n const seconds = 6;\n const buffer = ctx.createBuffer(2, Math.ceil(ctx.sampleRate * seconds), ctx.sampleRate);\n let seed = 0x706f6f6c;\n for (let channel = 0; channel < 2; channel++) {\n const data = buffer.getChannelData(channel);\n for (let i = 0; i < data.length; i++) {\n seed = (Math.imul(seed, 1664525) + 1013904223) | 0;\n const t = i / ctx.sampleRate;\n // A small pre-delay leaves the notes legible before the diffuse tiled-room reflections.\n data[i] = t < 0.045 ? 0 : (((seed >>> 0) / 0xffffffff) * 2 - 1) * Math.exp(-t / 1.25) * (1 - t / seconds) ** 2;\n }\n }\n impulses.set(ctx, buffer);\n return buffer;\n}\n\nexport const bathMusic = (ctx: BaseAudioContext, out: AudioNode) => roomMusic(ctx, out, false);\nexport const elevatorMusic = (ctx: BaseAudioContext, out: AudioNode) => roomMusic(ctx, out, true);\n\nfunction roomMusic(ctx: BaseAudioContext, out: AudioNode, elevator: boolean) {\n const BEAT = 60 / (elevator ? 88 : 48),\n CHORD_SECONDS = BEAT * 8;\n const score = elevator\n ? [\n { chord: [48, 55, 59, 64], melody: [76, 79, 74] },\n { chord: [45, 52, 55, 60], melody: [72, 76, 71] },\n { chord: [50, 57, 60, 65], melody: [74, 77, 76] },\n { chord: [43, 53, 57, 62], melody: [74, 71, 72] },\n ]\n : SCORE;\n const nodes: AudioNode[] = [];\n const oscillators: OscillatorNode[] = [];\n const bus = ctx.createGain();\n // Give the first chord a gentle entrance even outside the walk engine's cross-fade.\n bus.gain.setValueAtTime(0, ctx.currentTime);\n bus.gain.linearRampToValueAtTime(1, ctx.currentTime + 0.6);\n const low = ctx.createBiquadFilter();\n low.type = 'lowpass';\n low.frequency.value = 3200;\n low.Q.value = 0.5;\n const dry = ctx.createGain();\n dry.gain.value = 0.72;\n const reverb = ctx.createConvolver();\n reverb.buffer = roomImpulse(ctx);\n const wet = ctx.createGain();\n wet.gain.value = elevator ? 0.09 : 0.48;\n bus.connect(low);\n low.connect(dry).connect(out);\n low.connect(reverb).connect(wet).connect(out);\n nodes.push(bus, low, dry, reverb, wet);\n\n const voice = (pan: number, bell: boolean) => {\n const envelope = ctx.createGain();\n envelope.gain.value = 0;\n const stereo = ctx.createStereoPanner();\n stereo.pan.value = pan;\n envelope.connect(stereo).connect(bus);\n nodes.push(envelope, stereo);\n const tones = [1, bell ? 2.002 : 1].map((ratio, i) => {\n const oscillator = ctx.createOscillator();\n oscillator.type = !bell && i === 1 ? 'triangle' : 'sine';\n oscillator.detune.value = bell ? 0 : i ? 3 : -3;\n const gain = ctx.createGain();\n gain.gain.value = i ? (bell ? 0.22 : 0.3) : 1;\n oscillator.connect(gain).connect(envelope);\n oscillator.start();\n nodes.push(gain);\n oscillators.push(oscillator);\n return { oscillator, ratio };\n });\n const note = (midi: number, at: number, level: number, attack: number, hold: number, duration: number) => {\n for (const { oscillator, ratio } of tones) oscillator.frequency.setValueAtTime(hz(midi) * ratio, at);\n const gain = envelope.gain;\n gain.setValueAtTime(0, at);\n gain.linearRampToValueAtTime(level, at + attack);\n gain.setValueAtTime(level, at + attack + hold);\n gain.exponentialRampToValueAtTime(0.00001, at + duration - 0.05);\n gain.linearRampToValueAtTime(0, at + duration);\n };\n return { note };\n };\n const pads = [-0.55, 0.25, -0.2, 0.6].map(pan => voice(pan, false));\n const bells = [-0.4, 0.3, 0.5, -0.25].map(pan => voice(pan, true));\n let next = ctx.currentTime + 0.05;\n let bar = 0;\n let bell = 0;\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n if (stopped) return;\n // Skip elapsed bars after a background-tab stall instead of firing a backlog of notes.\n while (next < ctx.currentTime) {\n next += CHORD_SECONDS;\n bar++;\n }\n while (next < ctx.currentTime + CHORD_SECONDS * 2) {\n const phrase = score[bar % score.length];\n phrase.chord.forEach((midi, i) =>\n pads[i].note(midi, next, i ? 0.045 : 0.055, elevator ? 0.08 : 2, elevator ? 1.5 : 3, CHORD_SECONDS),\n );\n phrase.melody.forEach((midi, i) => {\n bells[bell++ % bells.length].note(midi, next + [1, 3.5, 6][i] * BEAT, 0.065, 0.025, 0, elevator ? 1.5 : 3.8);\n });\n next += CHORD_SECONDS;\n bar++;\n }\n timer = setTimeout(schedule, 1000);\n };\n schedule();\n // A fixed voice bank bounds memory for an indefinitely long walk. No new nodes per note.\n return {\n nodes,\n sources: [\n ...oscillators,\n {\n stop() {\n stopped = true;\n clearTimeout(timer);\n },\n },\n ],\n };\n}\n"],"names":["SCORE","hz","midi","impulses","roomImpulse","ctx","cached","seconds","buffer","seed","channel","data","i","t","bathMusic","out","roomMusic","elevatorMusic","elevator","BEAT","CHORD_SECONDS","score","nodes","oscillators","bus","low","dry","reverb","wet","voice","pan","bell","envelope","stereo","tones","ratio","oscillator","gain","at","level","attack","hold","duration","pads","bells","next","bar","stopped","timer","schedule","phrase"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import * as g from "maplibre-gl";
2
+ import { toLngLat as M } from "../model/geometry.js";
3
+ import { undergroundView as f } from "./underground.js";
4
+ function u(t) {
5
+ const o = t.getVerticalFieldOfView() * Math.PI / 360;
6
+ return 0.5 / Math.tan(o) * Math.max(1, t.getCanvas().clientHeight);
7
+ }
8
+ function C(t) {
9
+ const o = t.getCenter(), i = t.getCenterElevation(), a = t.getPitch() * Math.PI / 180, r = t.getBearing() * Math.PI / 180, n = g.MercatorCoordinate.fromLngLat(o, i), e = n.meterInMercatorCoordinateUnits(), s = e * 512 * 2 ** t.getZoom(), c = u(t) / s, l = Math.sin(a) * c * e, h = new g.MercatorCoordinate(
10
+ n.x - Math.sin(r) * l,
11
+ n.y + Math.cos(r) * l,
12
+ n.z + Math.cos(a) * c * e
13
+ );
14
+ return { lngLat: h.toLngLat(), altitude: h.toAltitude() };
15
+ }
16
+ function d(t, o, i, a) {
17
+ if (!o) return t;
18
+ const r = o * Math.tan(i * Math.PI / 180), n = a * Math.PI / 180, e = g.MercatorCoordinate.fromLngLat({ lng: t[0], lat: t[1] }), s = e.meterInMercatorCoordinateUnits();
19
+ e.x += r * Math.sin(n) * s, e.y -= r * Math.cos(n) * s;
20
+ const c = e.toLngLat();
21
+ return [c.lng, c.lat];
22
+ }
23
+ function P(t, o, i, a, r) {
24
+ const n = M(i, o.origin), e = r.threeD ? f(o, a, r.stack).focusElevation : 0;
25
+ return d([n[0], n[1]], e, t.getPitch(), t.getBearing());
26
+ }
27
+ export {
28
+ d as aimCenter,
29
+ C as cameraPosition,
30
+ u as cameraToCenterDistance,
31
+ P as floorAim
32
+ };
33
+ //# sourceMappingURL=cameraAim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cameraAim.js","sources":["../../../../src/map/cameraAim.ts"],"sourcesContent":["import * as maplibregl from 'maplibre-gl';\nimport type { Map as GLMap } from 'maplibre-gl';\nimport type { Point, ProjectDocument } from '../model/types';\nimport { toLngLat } from '../model/geometry';\nimport { undergroundView } from './underground';\n\nexport function cameraToCenterDistance(map: GLMap): number {\n const halfFov = (map.getVerticalFieldOfView() * Math.PI) / 360;\n return (0.5 / Math.tan(halfFov)) * Math.max(1, map.getCanvas().clientHeight);\n}\n\nexport function cameraPosition(map: GLMap) {\n const center = map.getCenter();\n const elevation = map.getCenterElevation();\n const pitch = (map.getPitch() * Math.PI) / 180;\n const bearing = (map.getBearing() * Math.PI) / 180;\n const target = maplibregl.MercatorCoordinate.fromLngLat(center, elevation);\n const mercatorUnitsPerMetre = target.meterInMercatorCoordinateUnits();\n const pixelsPerMetre = mercatorUnitsPerMetre * 512 * 2 ** map.getZoom();\n const distanceMetres = cameraToCenterDistance(map) / pixelsPerMetre;\n const horizontal = Math.sin(pitch) * distanceMetres * mercatorUnitsPerMetre;\n const eye = new maplibregl.MercatorCoordinate(\n target.x - Math.sin(bearing) * horizontal,\n target.y + Math.cos(bearing) * horizontal,\n target.z + Math.cos(pitch) * distanceMetres * mercatorUnitsPerMetre,\n );\n return { lngLat: eye.toLngLat(), altitude: eye.toAltitude() };\n}\n\n/** fit()'s depth-aim factored out and shared with the journey: with a pitched camera a plate at\n * elevation elev projects off-centre unless the ground target shifts by elev·tan(pitch) along the\n * view bearing. elev must already be the PRESENTED elevation (undergroundView().focusElevation). */\nexport function aimCenter(\n center: [number, number],\n elev: number,\n pitchDeg: number,\n bearingDeg: number,\n): [number, number] {\n if (!elev) return center;\n const shift = elev * Math.tan((pitchDeg * Math.PI) / 180),\n bearing = (bearingDeg * Math.PI) / 180;\n const target = maplibregl.MercatorCoordinate.fromLngLat({ lng: center[0], lat: center[1] }),\n unit = target.meterInMercatorCoordinateUnits();\n target.x += shift * Math.sin(bearing) * unit;\n target.y -= shift * Math.cos(bearing) * unit;\n const ll = target.toLngLat();\n return [ll.lng, ll.lat];\n}\n\n/** The map centre that brings a plan position on `floorId` under the crosshair. Anyone easing to a\n * point in the document wants this rather than the raw ground coordinate: the storey is drawn at its\n * presented elevation, and a pitched camera sees it displaced along the view bearing, so centring on\n * the ground beneath a basement leaves the thing you asked for a good ten metres off screen centre. */\nexport function floorAim(\n map: GLMap,\n project: ProjectDocument,\n position: Point,\n floorId: string | null,\n view: { threeD: boolean; stack: boolean },\n): [number, number] {\n const ll = toLngLat(position, project.origin);\n const elev = view.threeD ? undergroundView(project, floorId, view.stack).focusElevation : 0;\n return aimCenter([ll[0], ll[1]], elev, map.getPitch(), map.getBearing());\n}\n"],"names":["cameraToCenterDistance","map","halfFov","cameraPosition","center","elevation","pitch","bearing","target","maplibregl","mercatorUnitsPerMetre","pixelsPerMetre","distanceMetres","horizontal","eye","aimCenter","elev","pitchDeg","bearingDeg","shift","unit","ll","floorAim","project","position","floorId","view","toLngLat","undergroundView"],"mappings":";;;AAMO,SAASA,EAAuBC,GAAoB;AACzD,QAAMC,IAAWD,EAAI,uBAAA,IAA2B,KAAK,KAAM;AAC3D,SAAQ,MAAM,KAAK,IAAIC,CAAO,IAAK,KAAK,IAAI,GAAGD,EAAI,UAAA,EAAY,YAAY;AAC7E;AAEO,SAASE,EAAeF,GAAY;AACzC,QAAMG,IAASH,EAAI,UAAA,GACbI,IAAYJ,EAAI,mBAAA,GAChBK,IAASL,EAAI,SAAA,IAAa,KAAK,KAAM,KACrCM,IAAWN,EAAI,WAAA,IAAe,KAAK,KAAM,KACzCO,IAASC,EAAW,mBAAmB,WAAWL,GAAQC,CAAS,GACnEK,IAAwBF,EAAO,+BAAA,GAC/BG,IAAiBD,IAAwB,MAAM,KAAKT,EAAI,QAAA,GACxDW,IAAiBZ,EAAuBC,CAAG,IAAIU,GAC/CE,IAAa,KAAK,IAAIP,CAAK,IAAIM,IAAiBF,GAChDI,IAAM,IAAIL,EAAW;AAAA,IACzBD,EAAO,IAAI,KAAK,IAAID,CAAO,IAAIM;AAAA,IAC/BL,EAAO,IAAI,KAAK,IAAID,CAAO,IAAIM;AAAA,IAC/BL,EAAO,IAAI,KAAK,IAAIF,CAAK,IAAIM,IAAiBF;AAAA,EAAA;AAEhD,SAAO,EAAE,QAAQI,EAAI,SAAA,GAAY,UAAUA,EAAI,aAAW;AAC5D;AAKO,SAASC,EACdX,GACAY,GACAC,GACAC,GACkB;AAClB,MAAI,CAACF,EAAM,QAAOZ;AAClB,QAAMe,IAAQH,IAAO,KAAK,IAAKC,IAAW,KAAK,KAAM,GAAG,GACtDV,IAAWW,IAAa,KAAK,KAAM,KAC/BV,IAASC,EAAW,mBAAmB,WAAW,EAAE,KAAKL,EAAO,CAAC,GAAG,KAAKA,EAAO,CAAC,EAAA,CAAG,GACxFgB,IAAOZ,EAAO,+BAAA;AAChB,EAAAA,EAAO,KAAKW,IAAQ,KAAK,IAAIZ,CAAO,IAAIa,GACxCZ,EAAO,KAAKW,IAAQ,KAAK,IAAIZ,CAAO,IAAIa;AACxC,QAAMC,IAAKb,EAAO,SAAA;AAClB,SAAO,CAACa,EAAG,KAAKA,EAAG,GAAG;AACxB;AAMO,SAASC,EACdrB,GACAsB,GACAC,GACAC,GACAC,GACkB;AAClB,QAAML,IAAKM,EAASH,GAAUD,EAAQ,MAAM,GACtCP,IAAOU,EAAK,SAASE,EAAgBL,GAASE,GAASC,EAAK,KAAK,EAAE,iBAAiB;AAC1F,SAAOX,EAAU,CAACM,EAAG,CAAC,GAAGA,EAAG,CAAC,CAAC,GAAGL,GAAMf,EAAI,SAAA,GAAYA,EAAI,YAAY;AACzE;"}
@@ -0,0 +1,56 @@
1
+ import { add as d, rotate as a, rectangle as l, objectRotation as m, objectPosition as g } from "../model/geometry.js";
2
+ import { servedFloors as w } from "../model/vertical.js";
3
+ const v = (t) => ({
4
+ width: Math.max(0.7, t.width - 0.28),
5
+ depth: Math.max(0.7, t.depth - 0.28)
6
+ });
7
+ function S(t, n, r) {
8
+ return t.objects.filter((i) => i.kind === "elevator" && r.has(i.id) && w(t, i).some((o) => o.id === n)).map((i) => {
9
+ const { width: o, depth: e } = v(i);
10
+ return l(g(t, i), o, e, m(t, i));
11
+ });
12
+ }
13
+ const M = (t, n = 0) => Math.max(0.7, Math.min(1.6, (n % 180 ? t.depth : t.width) - 0.5)), f = (t) => {
14
+ var n;
15
+ return t.rotation + { front: 0, right: 90, back: 180, left: 270 }[((n = t.doorSides) == null ? void 0 : n[0]) ?? "front"];
16
+ }, D = (t) => {
17
+ const n = f(t) - t.rotation;
18
+ return d(t.position, a([0, (n % 180 ? t.width : t.depth) / 2 + 0.8], f(t)));
19
+ };
20
+ function P(t, n) {
21
+ const r = a([n[0] - t.position[0], n[1] - t.position[1]], -t.rotation);
22
+ return Math.abs(r[0]) < t.width / 2 - 0.2 && Math.abs(r[1]) < t.depth / 2 - 0.2;
23
+ }
24
+ function W(t, n) {
25
+ const r = [];
26
+ for (const [i, o] of [
27
+ ["front", 0],
28
+ ["right", 90],
29
+ ["back", 180],
30
+ ["left", 270]
31
+ ]) {
32
+ const e = o % 180 ? t.depth : t.width, p = o % 180 ? t.width : t.depth, c = M(t, o), u = n && (t.doorSides ?? ["front"]).includes(i), h = (s, b) => r.push(
33
+ l(d(t.position, a([s, p / 2 - 0.1], t.rotation + o)), b, 0.2, t.rotation + o)
34
+ );
35
+ if (!u) h(0, e);
36
+ else for (const s of [-1, 1]) h(s * (e + c) / 4, (e - c) / 2);
37
+ }
38
+ return r;
39
+ }
40
+ const k = (t) => ["back", "left", "right", "front"].find((n) => !(t.doorSides ?? ["front"]).includes(n));
41
+ function y(t) {
42
+ const n = { front: 0, right: 90, back: 180, left: 270 }[k(t) ?? "back"];
43
+ return d(t.position, a([0, (n % 180 ? t.width : t.depth) / 2], t.rotation + n));
44
+ }
45
+ export {
46
+ v as cabinDimensions,
47
+ S as cabinFloorVoids,
48
+ M as elevatorDoorWidth,
49
+ f as elevatorFacing,
50
+ D as elevatorLanding,
51
+ k as elevatorMirrorFace,
52
+ y as elevatorMirrorPoint,
53
+ W as elevatorWalls,
54
+ P as insideElevator
55
+ };
56
+ //# sourceMappingURL=elevators.js.map