@kerros/editor 0.0.0-stage → 0.1.0-rc.2
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.
- package/LICENSE +21 -0
- package/README.md +35 -2
- package/dist/SitePlanner.js +1189 -0
- package/dist/SitePlanner.js.map +1 -0
- package/dist/adapters/basemap.js +11 -0
- package/dist/adapters/basemap.js.map +1 -0
- package/dist/adapters/persistence.js +121 -0
- package/dist/adapters/persistence.js.map +1 -0
- package/dist/adapters/status.js +11 -0
- package/dist/adapters/status.js.map +1 -0
- package/dist/adapters/useProjectPersistence.js +56 -0
- package/dist/adapters/useProjectPersistence.js.map +1 -0
- package/dist/components/AiImportPanel.js +635 -0
- package/dist/components/AiImportPanel.js.map +1 -0
- package/dist/components/AnalysisPreview.js +179 -0
- package/dist/components/AnalysisPreview.js.map +1 -0
- package/dist/components/ElevatorPanel.js +120 -0
- package/dist/components/ElevatorPanel.js.map +1 -0
- package/dist/components/Icons.js +57 -0
- package/dist/components/Icons.js.map +1 -0
- package/dist/components/ImportDialog.js +467 -0
- package/dist/components/ImportDialog.js.map +1 -0
- package/dist/components/Inspector.js +1184 -0
- package/dist/components/Inspector.js.map +1 -0
- package/dist/components/NavigatePanel.js +301 -0
- package/dist/components/NavigatePanel.js.map +1 -0
- package/dist/components/NavigationGraph.js +234 -0
- package/dist/components/NavigationGraph.js.map +1 -0
- package/dist/components/StructureExplorer.js +510 -0
- package/dist/components/StructureExplorer.js.map +1 -0
- package/dist/components/StructureView.js +286 -0
- package/dist/components/StructureView.js.map +1 -0
- package/dist/components/controls.js +209 -0
- package/dist/components/controls.js.map +1 -0
- package/dist/components/graphLayout.js +27 -0
- package/dist/components/graphLayout.js.map +1 -0
- package/dist/host.js +175 -0
- package/dist/host.js.map +1 -0
- package/dist/i18n.js +88 -0
- package/dist/i18n.js.map +1 -0
- package/dist/import/analysisPreview.js +41 -0
- package/dist/import/analysisPreview.js.map +1 -0
- package/dist/import/brief.js +29 -0
- package/dist/import/brief.js.map +1 -0
- package/dist/import/checkpoint.js +50 -0
- package/dist/import/checkpoint.js.map +1 -0
- package/dist/import/detect.js +120 -0
- package/dist/import/detect.js.map +1 -0
- package/dist/import/documentSvg.js +49 -0
- package/dist/import/documentSvg.js.map +1 -0
- package/dist/import/instructions.js +20 -0
- package/dist/import/instructions.js.map +1 -0
- package/dist/import/openings.js +61 -0
- package/dist/import/openings.js.map +1 -0
- package/dist/import/planImport.js +233 -0
- package/dist/import/planImport.js.map +1 -0
- package/dist/import/register.js +47 -0
- package/dist/import/register.js.map +1 -0
- package/dist/import/runs.js +67 -0
- package/dist/import/runs.js.map +1 -0
- package/dist/import/session.js +23 -0
- package/dist/import/session.js.map +1 -0
- package/dist/import/types.js +13 -0
- package/dist/import/types.js.map +1 -0
- package/dist/import/usage.js +29 -0
- package/dist/import/usage.js.map +1 -0
- package/dist/import/walls.js +112 -0
- package/dist/import/walls.js.map +1 -0
- package/dist/index.js +178 -0
- package/dist/index.js.map +1 -0
- package/dist/map/CabinMaterials.js +81 -0
- package/dist/map/CabinMaterials.js.map +1 -0
- package/dist/map/CabinMirror.js +43 -0
- package/dist/map/CabinMirror.js.map +1 -0
- package/dist/map/Doors.js +80 -0
- package/dist/map/Doors.js.map +1 -0
- package/dist/map/ElevatorCabin.js +93 -0
- package/dist/map/ElevatorCabin.js.map +1 -0
- package/dist/map/FixtureLights.js +117 -0
- package/dist/map/FixtureLights.js.map +1 -0
- package/dist/map/MapCanvas.js +2161 -0
- package/dist/map/MapCanvas.js.map +1 -0
- package/dist/map/Passenger.js +69 -0
- package/dist/map/Passenger.js.map +1 -0
- package/dist/map/SceneLayer.js +1534 -0
- package/dist/map/SceneLayer.js.map +1 -0
- package/dist/map/UndergroundContext.js +153 -0
- package/dist/map/UndergroundContext.js.map +1 -0
- package/dist/map/ambience.js +194 -0
- package/dist/map/ambience.js.map +1 -0
- package/dist/map/architecture.js +305 -0
- package/dist/map/architecture.js.map +1 -0
- package/dist/map/bathMusic.js +92 -0
- package/dist/map/bathMusic.js.map +1 -0
- package/dist/map/cameraAim.js +33 -0
- package/dist/map/cameraAim.js.map +1 -0
- package/dist/map/elevators.js +56 -0
- package/dist/map/elevators.js.map +1 -0
- package/dist/map/excavation.js +52 -0
- package/dist/map/excavation.js.map +1 -0
- package/dist/map/exteriors.js +25 -0
- package/dist/map/exteriors.js.map +1 -0
- package/dist/map/features.js +218 -0
- package/dist/map/features.js.map +1 -0
- package/dist/map/fences.js +29 -0
- package/dist/map/fences.js.map +1 -0
- package/dist/map/journey.js +112 -0
- package/dist/map/journey.js.map +1 -0
- package/dist/map/levels.js +6 -0
- package/dist/map/levels.js.map +1 -0
- package/dist/map/lighting.js +143 -0
- package/dist/map/lighting.js.map +1 -0
- package/dist/map/loadBasemap.js +26 -0
- package/dist/map/loadBasemap.js.map +1 -0
- package/dist/map/materials.js +183 -0
- package/dist/map/materials.js.map +1 -0
- package/dist/map/poolLighting.js +39 -0
- package/dist/map/poolLighting.js.map +1 -0
- package/dist/map/projection.js +24 -0
- package/dist/map/projection.js.map +1 -0
- package/dist/map/rampGeometry.js +38 -0
- package/dist/map/rampGeometry.js.map +1 -0
- package/dist/map/route.js +107 -0
- package/dist/map/route.js.map +1 -0
- package/dist/map/stairSurfaces.js +115 -0
- package/dist/map/stairSurfaces.js.map +1 -0
- package/dist/map/surfaces.js +136 -0
- package/dist/map/surfaces.js.map +1 -0
- package/dist/map/textures.js +95 -0
- package/dist/map/textures.js.map +1 -0
- package/dist/map/underground.js +34 -0
- package/dist/map/underground.js.map +1 -0
- package/dist/map/walk.js +433 -0
- package/dist/map/walk.js.map +1 -0
- package/dist/map/walkContext.js +46 -0
- package/dist/map/walkContext.js.map +1 -0
- package/dist/map/walkDimensions.js +7 -0
- package/dist/map/walkDimensions.js.map +1 -0
- package/dist/map/walkJourney.js +85 -0
- package/dist/map/walkJourney.js.map +1 -0
- package/dist/map/walkSurfaces.js +106 -0
- package/dist/map/walkSurfaces.js.map +1 -0
- package/dist/map/wallJoins.js +70 -0
- package/dist/map/wallJoins.js.map +1 -0
- package/dist/map/water.js +274 -0
- package/dist/map/water.js.map +1 -0
- package/dist/model/authoring.js +99 -0
- package/dist/model/authoring.js.map +1 -0
- package/dist/model/boundaries.js +548 -0
- package/dist/model/boundaries.js.map +1 -0
- package/dist/model/coverage.js +30 -0
- package/dist/model/coverage.js.map +1 -0
- package/dist/model/document.js +52 -0
- package/dist/model/document.js.map +1 -0
- package/dist/model/doors.js +47 -0
- package/dist/model/doors.js.map +1 -0
- package/dist/model/factory.js +56 -0
- package/dist/model/factory.js.map +1 -0
- package/dist/model/geometry.js +454 -0
- package/dist/model/geometry.js.map +1 -0
- package/dist/model/history.js +29 -0
- package/dist/model/history.js.map +1 -0
- package/dist/model/imports.js +45 -0
- package/dist/model/imports.js.map +1 -0
- package/dist/model/inference.js +182 -0
- package/dist/model/inference.js.map +1 -0
- package/dist/model/materials.js +11 -0
- package/dist/model/materials.js.map +1 -0
- package/dist/model/mutations.js +157 -0
- package/dist/model/mutations.js.map +1 -0
- package/dist/model/navigation.js +275 -0
- package/dist/model/navigation.js.map +1 -0
- package/dist/model/ontology.js +109 -0
- package/dist/model/ontology.js.map +1 -0
- package/dist/model/passages.js +5 -0
- package/dist/model/passages.js.map +1 -0
- package/dist/model/portals.js +42 -0
- package/dist/model/portals.js.map +1 -0
- package/dist/model/precision.js +11 -0
- package/dist/model/precision.js.map +1 -0
- package/dist/model/project.js +31 -0
- package/dist/model/project.js.map +1 -0
- package/dist/model/ramps.js +10 -0
- package/dist/model/ramps.js.map +1 -0
- package/dist/model/roomNavigation.js +87 -0
- package/dist/model/roomNavigation.js.map +1 -0
- package/dist/model/routeClearance.js +72 -0
- package/dist/model/routeClearance.js.map +1 -0
- package/dist/model/spaces.js +104 -0
- package/dist/model/spaces.js.map +1 -0
- package/dist/model/stairGeometry.js +40 -0
- package/dist/model/stairGeometry.js.map +1 -0
- package/dist/model/stairTraversal.js +48 -0
- package/dist/model/stairTraversal.js.map +1 -0
- package/dist/model/topology.js +63 -0
- package/dist/model/topology.js.map +1 -0
- package/dist/model/types.js +35 -0
- package/dist/model/types.js.map +1 -0
- package/dist/model/validate.js +240 -0
- package/dist/model/validate.js.map +1 -0
- package/dist/model/vertical.js +129 -0
- package/dist/model/vertical.js.map +1 -0
- package/dist/model/walls.js +261 -0
- package/dist/model/walls.js.map +1 -0
- package/dist/planner/DrawingDock.js +231 -0
- package/dist/planner/DrawingDock.js.map +1 -0
- package/dist/planner/FloorControls.js +93 -0
- package/dist/planner/FloorControls.js.map +1 -0
- package/dist/planner/MapSettings.js +143 -0
- package/dist/planner/MapSettings.js.map +1 -0
- package/dist/planner/PlannerHelp.js +57 -0
- package/dist/planner/PlannerHelp.js.map +1 -0
- package/dist/planner/ProjectSidebar.js +246 -0
- package/dist/planner/ProjectSidebar.js.map +1 -0
- package/dist/planner/floors.js +18 -0
- package/dist/planner/floors.js.map +1 -0
- package/dist/planner/useDrawingTools.js +341 -0
- package/dist/planner/useDrawingTools.js.map +1 -0
- package/dist/planner/useMapDisplay.js +51 -0
- package/dist/planner/useMapDisplay.js.map +1 -0
- package/dist/planner/usePlannerKeyboard.js +138 -0
- package/dist/planner/usePlannerKeyboard.js.map +1 -0
- package/dist/planner/useReferenceAlignment.js +50 -0
- package/dist/planner/useReferenceAlignment.js.map +1 -0
- package/dist/styles.css +4931 -0
- package/dist/theme/index.js +34 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/types/SitePlanner.d.ts +5 -0
- package/dist/types/adapters/basemap.d.ts +2 -0
- package/dist/types/adapters/persistence.d.ts +29 -0
- package/dist/types/adapters/status.d.ts +4 -0
- package/dist/types/adapters/useProjectPersistence.d.ts +13 -0
- package/dist/types/components/AiImportPanel.d.ts +9 -0
- package/dist/types/components/AnalysisPreview.d.ts +4 -0
- package/dist/types/components/ElevatorPanel.d.ts +18 -0
- package/dist/types/components/Icons.d.ts +8 -0
- package/dist/types/components/ImportDialog.d.ts +42 -0
- package/dist/types/components/Inspector.d.ts +38 -0
- package/dist/types/components/NavigatePanel.d.ts +27 -0
- package/dist/types/components/NavigationGraph.d.ts +10 -0
- package/dist/types/components/StructureExplorer.d.ts +8 -0
- package/dist/types/components/StructureView.d.ts +22 -0
- package/dist/types/components/controls.d.ts +52 -0
- package/dist/types/components/graphLayout.d.ts +9 -0
- package/dist/types/editor/host.d.ts +9 -0
- package/dist/types/editor/index.d.ts +2 -0
- package/dist/types/i18n.d.ts +85 -0
- package/dist/types/import/analysisPreview.d.ts +27 -0
- package/dist/types/import/brief.d.ts +22 -0
- package/dist/types/import/checkpoint.d.ts +49 -0
- package/dist/types/import/detect.d.ts +34 -0
- package/dist/types/import/documentSvg.d.ts +2 -0
- package/dist/types/import/index.d.ts +10 -0
- package/dist/types/import/instructions.d.ts +7 -0
- package/dist/types/import/openings.d.ts +22 -0
- package/dist/types/import/planImport.d.ts +22 -0
- package/dist/types/import/register.d.ts +25 -0
- package/dist/types/import/runs.d.ts +31 -0
- package/dist/types/import/session.d.ts +33 -0
- package/dist/types/import/types.d.ts +56 -0
- package/dist/types/import/usage.d.ts +10 -0
- package/dist/types/import/walls.d.ts +37 -0
- package/dist/types/map/CabinMaterials.d.ts +18 -0
- package/dist/types/map/CabinMirror.d.ts +13 -0
- package/dist/types/map/Doors.d.ts +11 -0
- package/dist/types/map/ElevatorCabin.d.ts +20 -0
- package/dist/types/map/FixtureLights.d.ts +35 -0
- package/dist/types/map/MapCanvas.d.ts +87 -0
- package/dist/types/map/Passenger.d.ts +18 -0
- package/dist/types/map/SceneLayer.d.ts +306 -0
- package/dist/types/map/UndergroundContext.d.ts +18 -0
- package/dist/types/map/ambience.d.ts +29 -0
- package/dist/types/map/architecture.d.ts +8 -0
- package/dist/types/map/bathMusic.d.ts +14 -0
- package/dist/types/map/cameraAim.d.ts +20 -0
- package/dist/types/map/elevators.d.ts +16 -0
- package/dist/types/map/excavation.d.ts +9 -0
- package/dist/types/map/exteriors.d.ts +3 -0
- package/dist/types/map/features.d.ts +33 -0
- package/dist/types/map/fences.d.ts +4 -0
- package/dist/types/map/journey.d.ts +36 -0
- package/dist/types/map/levels.d.ts +4 -0
- package/dist/types/map/lighting.d.ts +103 -0
- package/dist/types/map/loadBasemap.d.ts +4 -0
- package/dist/types/map/materials.d.ts +38 -0
- package/dist/types/map/poolLighting.d.ts +11 -0
- package/dist/types/map/projection.d.ts +9 -0
- package/dist/types/map/rampGeometry.d.ts +8 -0
- package/dist/types/map/route.d.ts +59 -0
- package/dist/types/map/stairSurfaces.d.ts +29 -0
- package/dist/types/map/surfaces.d.ts +36 -0
- package/dist/types/map/textures.d.ts +8 -0
- package/dist/types/map/underground.d.ts +30 -0
- package/dist/types/map/walk.d.ts +232 -0
- package/dist/types/map/walkContext.d.ts +11 -0
- package/dist/types/map/walkDimensions.d.ts +5 -0
- package/dist/types/map/walkJourney.d.ts +33 -0
- package/dist/types/map/walkSurfaces.d.ts +27 -0
- package/dist/types/map/wallJoins.d.ts +6 -0
- package/dist/types/map/water.d.ts +12 -0
- package/dist/types/model/authoring.d.ts +38 -0
- package/dist/types/model/boundaries.d.ts +41 -0
- package/dist/types/model/coverage.d.ts +8 -0
- package/dist/types/model/document.d.ts +9 -0
- package/dist/types/model/doors.d.ts +19 -0
- package/dist/types/model/factory.d.ts +5 -0
- package/dist/types/model/geometry.d.ts +99 -0
- package/dist/types/model/history.d.ts +10 -0
- package/dist/types/model/host.d.ts +154 -0
- package/dist/types/model/imports.d.ts +7 -0
- package/dist/types/model/inference.d.ts +46 -0
- package/dist/types/model/live.d.ts +60 -0
- package/dist/types/model/materials.d.ts +28 -0
- package/dist/types/model/mutations.d.ts +178 -0
- package/dist/types/model/navigation.d.ts +70 -0
- package/dist/types/model/ontology.d.ts +43 -0
- package/dist/types/model/passages.d.ts +2 -0
- package/dist/types/model/portals.d.ts +9 -0
- package/dist/types/model/precision.d.ts +11 -0
- package/dist/types/model/project.d.ts +8 -0
- package/dist/types/model/ramps.d.ts +7 -0
- package/dist/types/model/roomNavigation.d.ts +15 -0
- package/dist/types/model/routeClearance.d.ts +11 -0
- package/dist/types/model/spaces.d.ts +46 -0
- package/dist/types/model/stairGeometry.d.ts +27 -0
- package/dist/types/model/stairTraversal.d.ts +8 -0
- package/dist/types/model/topology.d.ts +14 -0
- package/dist/types/model/types.d.ts +369 -0
- package/dist/types/model/validate.d.ts +38 -0
- package/dist/types/model/vertical.d.ts +145 -0
- package/dist/types/model/walls.d.ts +71 -0
- package/dist/types/planner/DrawingDock.d.ts +16 -0
- package/dist/types/planner/FloorControls.d.ts +17 -0
- package/dist/types/planner/MapSettings.d.ts +16 -0
- package/dist/types/planner/PlannerHelp.d.ts +3 -0
- package/dist/types/planner/ProjectSidebar.d.ts +32 -0
- package/dist/types/planner/floors.d.ts +3 -0
- package/dist/types/planner/types.d.ts +3 -0
- package/dist/types/planner/useDrawingTools.d.ts +52 -0
- package/dist/types/planner/useMapDisplay.d.ts +29 -0
- package/dist/types/planner/usePlannerKeyboard.d.ts +18 -0
- package/dist/types/planner/useReferenceAlignment.d.ts +30 -0
- package/dist/types/schema/index.d.ts +25 -0
- package/dist/types/theme/index.d.ts +55 -0
- package/package.json +58 -4
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
var H = Object.defineProperty;
|
|
2
|
+
var O = (i, c, s) => c in i ? H(i, c, { enumerable: !0, configurable: !0, writable: !0, value: s }) : i[c] = s;
|
|
3
|
+
var p = (i, c, s) => O(i, typeof c != "symbol" ? c + "" : c, s);
|
|
4
|
+
import * as e from "three";
|
|
5
|
+
class K extends e.Group {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
p(this, "rings", []);
|
|
9
|
+
p(this, "columns", []);
|
|
10
|
+
p(this, "center", [0, 0]);
|
|
11
|
+
p(this, "bottom", 0);
|
|
12
|
+
p(this, "top", 0);
|
|
13
|
+
p(this, "bearing", Number.NaN);
|
|
14
|
+
p(this, "ringLines");
|
|
15
|
+
p(this, "columnLines");
|
|
16
|
+
}
|
|
17
|
+
configure(s, a, l, f, y) {
|
|
18
|
+
this.dispose(), this.rings = s, this.columns = a, this.bottom = l, this.top = f;
|
|
19
|
+
let u = 0, h = 0, d = 0;
|
|
20
|
+
const t = new e.Box3();
|
|
21
|
+
for (const n of s)
|
|
22
|
+
for (const r of n)
|
|
23
|
+
u++, h += r.x, d += r.y, t.expandByPoint(r);
|
|
24
|
+
if (!u) return;
|
|
25
|
+
for (const [n, r] of a)
|
|
26
|
+
t.expandByPoint(new e.Vector3(n, r, l)), t.expandByPoint(new e.Vector3(n, r, f));
|
|
27
|
+
this.center = [h / u, d / u], this.bearing = Number.NaN;
|
|
28
|
+
const o = (n, r, g) => {
|
|
29
|
+
const m = new e.BufferGeometry();
|
|
30
|
+
m.boundingBox = t.clone(), m.setAttribute(
|
|
31
|
+
"position",
|
|
32
|
+
new e.BufferAttribute(new Float32Array(n * 6), 3).setUsage(e.DynamicDrawUsage)
|
|
33
|
+
), m.setDrawRange(0, 0);
|
|
34
|
+
const M = new e.LineSegments(
|
|
35
|
+
m,
|
|
36
|
+
new e.LineBasicMaterial({ color: r, transparent: !0, opacity: g, depthWrite: !1 })
|
|
37
|
+
);
|
|
38
|
+
return M.frustumCulled = !1, M.raycast = () => {
|
|
39
|
+
}, this.add(M), M;
|
|
40
|
+
};
|
|
41
|
+
this.ringLines = o(u, y ? "#99a0b4" : "#aeb4c0", 0.5), this.columnLines = o(a.length, y ? "#8b92a8" : "#a9afbd", 0.32);
|
|
42
|
+
}
|
|
43
|
+
setBearing(s) {
|
|
44
|
+
if (!this.ringLines || !this.columnLines) return;
|
|
45
|
+
const a = (s - this.bearing + 540) % 360 - 180;
|
|
46
|
+
if (Number.isFinite(a) && Math.abs(a) < 1) return;
|
|
47
|
+
this.bearing = s;
|
|
48
|
+
const l = Math.sin(s * Math.PI / 180), f = Math.cos(s * Math.PI / 180), y = (t, o) => (t - this.center[0]) * l + (o - this.center[1]) * f > 0, u = this.ringLines.geometry.getAttribute("position");
|
|
49
|
+
let h = 0;
|
|
50
|
+
for (const t of this.rings)
|
|
51
|
+
for (let o = 0; o < t.length; o++) {
|
|
52
|
+
const n = t[o], r = t[(o + 1) % t.length];
|
|
53
|
+
y((n.x + r.x) / 2, (n.y + r.y) / 2) && (u.setXYZ(h++, n.x, n.y, n.z), u.setXYZ(h++, r.x, r.y, r.z));
|
|
54
|
+
}
|
|
55
|
+
u.needsUpdate = !0, this.ringLines.geometry.setDrawRange(0, h);
|
|
56
|
+
const d = this.columnLines.geometry.getAttribute("position");
|
|
57
|
+
h = 0;
|
|
58
|
+
for (const [t, o] of this.columns)
|
|
59
|
+
y(t, o) && (d.setXYZ(h++, t, o, this.bottom), d.setXYZ(h++, t, o, this.top));
|
|
60
|
+
d.needsUpdate = !0, this.columnLines.geometry.setDrawRange(0, h);
|
|
61
|
+
}
|
|
62
|
+
dispose() {
|
|
63
|
+
for (const s of this.children)
|
|
64
|
+
s.geometry.dispose(), s.material.dispose();
|
|
65
|
+
this.clear(), this.ringLines = this.columnLines = void 0, this.rings = [], this.columns = [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const L = [
|
|
69
|
+
// Muted on purpose. These were the real colours of a Helsinki bore log — amber sand over Litorina
|
|
70
|
+
// clay over till — and side by side at full chroma they read as a geology poster rather than as
|
|
71
|
+
// ground: a band of teal and a band of yellow, competing with the building standing in them. Same
|
|
72
|
+
// sequence, same order, a fraction of the saturation, so depth still reads as layers and the eye
|
|
73
|
+
// stays on the plan.
|
|
74
|
+
{ until: -1.4, color: new e.Color("#6d6863") },
|
|
75
|
+
// made ground / pavement sub-base
|
|
76
|
+
{ until: -4.5, color: new e.Color("#968c7d") },
|
|
77
|
+
// sand & gravel
|
|
78
|
+
{ until: -11, color: new e.Color("#7d8891") },
|
|
79
|
+
// Litorina clay, the blue-grey one
|
|
80
|
+
{ until: -18, color: new e.Color("#877f75") },
|
|
81
|
+
// glacial till / moraine
|
|
82
|
+
{ until: Number.NEGATIVE_INFINITY, color: new e.Color("#79767b") }
|
|
83
|
+
// granite bedrock
|
|
84
|
+
], _ = 1.1, j = new e.Color("#b7b2a9"), Y = (i, c, s) => {
|
|
85
|
+
const a = Math.sin(i * 12.9898 + c * 78.233 + s * 37.719) * 43758.5453;
|
|
86
|
+
return a - Math.floor(a);
|
|
87
|
+
}, q = (i, c, s) => {
|
|
88
|
+
const a = Y(Math.round(i * 0.9), Math.round(c * 0.9), Math.round(s * 2.4)) - 0.5, l = Y(Math.round(i * 0.16), Math.round(c * 0.16), Math.round(s * 0.5)) - 0.5, f = Y(Math.round(i * 1.7), Math.round(c * 1.7), Math.round(s * 1.7)) > 0.965 ? -0.13 : 0;
|
|
89
|
+
return a * 0.13 + l * 0.16 + f;
|
|
90
|
+
};
|
|
91
|
+
function Q(i, c, s, a = []) {
|
|
92
|
+
const l = new e.Group();
|
|
93
|
+
l.name = "kerros-excavation";
|
|
94
|
+
const f = (t, o) => {
|
|
95
|
+
let n = L.findIndex((g) => t >= g.until);
|
|
96
|
+
n < 0 && (n = L.length - 1), o.copy(L[n].color);
|
|
97
|
+
const r = L[n].until;
|
|
98
|
+
return n + 1 < L.length && Number.isFinite(r) && t - r < _ && o.lerp(L[n + 1].color, (1 - (t - r) / _) * 0.5), o;
|
|
99
|
+
}, y = (t, o, n, r) => {
|
|
100
|
+
f(n, r);
|
|
101
|
+
const g = s < 0 ? Math.min(1, Math.max(0, n / s)) : 0;
|
|
102
|
+
r.multiplyScalar(1 + q(t, o, n) - g * 0.15);
|
|
103
|
+
for (const m of a) Math.abs(n - m) < 0.35 && r.lerp(j, 0.5);
|
|
104
|
+
return r;
|
|
105
|
+
}, u = (t, o, n, r, g = !1) => {
|
|
106
|
+
if (o <= t) return;
|
|
107
|
+
const m = [], M = [], B = new e.Color(), x = (w, b, N) => {
|
|
108
|
+
m.push(w, b, N), y(w, b, N, B), M.push(B.r, B.g, B.b), g && M.push(((N - t) / (o - t)) ** 2);
|
|
109
|
+
}, X = Math.min(110, Math.max(2, Math.ceil((o - t) / 0.55))), Z = (o - t) / X;
|
|
110
|
+
i.forEach(([w, b], N) => {
|
|
111
|
+
const [I, D] = i[(N + 1) % i.length], k = Math.hypot(I - w, D - b), E = Math.min(64, Math.max(1, Math.round(k / 3.5)));
|
|
112
|
+
for (let C = 0; C < E; C++) {
|
|
113
|
+
const v = C / E, W = (C + 1) / E, F = w + (I - w) * v, P = b + (D - b) * v, G = w + (I - w) * W, R = b + (D - b) * W;
|
|
114
|
+
for (let S = 0; S < X; S++) {
|
|
115
|
+
const U = t + Z * S, V = t + Z * (S + 1);
|
|
116
|
+
x(F, P, U), x(G, R, U), x(G, R, V), x(F, P, U), x(G, R, V), x(F, P, V);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
const A = new e.BufferGeometry();
|
|
121
|
+
A.setAttribute("position", new e.Float32BufferAttribute(m, 3)), A.setAttribute("color", new e.Float32BufferAttribute(M, g ? 4 : 3)), A.computeVertexNormals();
|
|
122
|
+
const T = new e.Mesh(
|
|
123
|
+
A,
|
|
124
|
+
new e.MeshStandardMaterial({
|
|
125
|
+
vertexColors: !0,
|
|
126
|
+
roughness: 1,
|
|
127
|
+
side: e.DoubleSide,
|
|
128
|
+
transparent: n < 1,
|
|
129
|
+
opacity: n,
|
|
130
|
+
depthWrite: n === 1
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
T.raycast = () => {
|
|
134
|
+
}, l.add(T);
|
|
135
|
+
};
|
|
136
|
+
u(s, c, 1), u(c, 0, 0.38, !0, !0);
|
|
137
|
+
const h = new e.Shape(i.map((t) => new e.Vector2(...t))), d = new e.Mesh(
|
|
138
|
+
new e.ShapeGeometry(h),
|
|
139
|
+
// The floor of the excavation is whatever the last layer is — bedrock, in a deep shaft.
|
|
140
|
+
new e.MeshStandardMaterial({
|
|
141
|
+
color: f(s, new e.Color()).multiplyScalar(0.62),
|
|
142
|
+
roughness: 1,
|
|
143
|
+
side: e.DoubleSide
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
return d.position.z = s, d.raycast = () => {
|
|
147
|
+
}, l.add(d), l;
|
|
148
|
+
}
|
|
149
|
+
export {
|
|
150
|
+
K as UndergroundCage,
|
|
151
|
+
Q as undergroundPit
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=UndergroundContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UndergroundContext.js","sources":["../../../../src/map/UndergroundContext.ts"],"sourcesContent":["import * as THREE from 'three';\nimport type { Point } from '../model/types';\n\n/** A camera-facing cutaway cage. Rotating updates two existing buffers, never GPU resources. */\nexport class UndergroundCage extends THREE.Group {\n private rings: THREE.Vector3[][] = [];\n private columns: Point[] = [];\n private center: Point = [0, 0];\n private bottom = 0;\n private top = 0;\n private bearing = Number.NaN;\n private ringLines?: THREE.LineSegments;\n private columnLines?: THREE.LineSegments;\n\n configure(rings: THREE.Vector3[][], columns: Point[], bottom: number, top: number, evening: boolean) {\n this.dispose();\n this.rings = rings;\n this.columns = columns;\n this.bottom = bottom;\n this.top = top;\n let count = 0,\n x = 0,\n y = 0;\n const bounds = new THREE.Box3();\n for (const ring of rings)\n for (const p of ring) {\n count++;\n x += p.x;\n y += p.y;\n bounds.expandByPoint(p);\n }\n if (!count) return;\n for (const [cx, cy] of columns) {\n bounds.expandByPoint(new THREE.Vector3(cx, cy, bottom));\n bounds.expandByPoint(new THREE.Vector3(cx, cy, top));\n }\n this.center = [x / count, y / count];\n this.bearing = Number.NaN;\n const lines = (capacity: number, color: string, opacity: number) => {\n const geometry = new THREE.BufferGeometry();\n // The vertex buffers contain only the current half-cage. Stable full-cage bounds let\n // the scene fit its clipping range once, without rescanning buffers on every rotation.\n geometry.boundingBox = bounds.clone();\n geometry.setAttribute(\n 'position',\n new THREE.BufferAttribute(new Float32Array(capacity * 6), 3).setUsage(THREE.DynamicDrawUsage),\n );\n geometry.setDrawRange(0, 0);\n const mesh = new THREE.LineSegments(\n geometry,\n new THREE.LineBasicMaterial({ color, transparent: true, opacity, depthWrite: false }),\n );\n mesh.frustumCulled = false;\n mesh.raycast = () => {};\n this.add(mesh);\n return mesh;\n };\n this.ringLines = lines(count, evening ? '#99a0b4' : '#aeb4c0', 0.5);\n this.columnLines = lines(columns.length, evening ? '#8b92a8' : '#a9afbd', 0.32);\n }\n\n setBearing(bearing: number) {\n if (!this.ringLines || !this.columnLines) return;\n const delta = ((bearing - this.bearing + 540) % 360) - 180;\n if (Number.isFinite(delta) && Math.abs(delta) < 1) return;\n this.bearing = bearing;\n const fx = Math.sin((bearing * Math.PI) / 180),\n fy = Math.cos((bearing * Math.PI) / 180);\n const far = (x: number, y: number) => (x - this.center[0]) * fx + (y - this.center[1]) * fy > 0;\n const rings = this.ringLines.geometry.getAttribute('position') as THREE.BufferAttribute;\n let n = 0;\n for (const ring of this.rings)\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i],\n b = ring[(i + 1) % ring.length];\n if (!far((a.x + b.x) / 2, (a.y + b.y) / 2)) continue;\n rings.setXYZ(n++, a.x, a.y, a.z);\n rings.setXYZ(n++, b.x, b.y, b.z);\n }\n rings.needsUpdate = true;\n this.ringLines.geometry.setDrawRange(0, n);\n const columns = this.columnLines.geometry.getAttribute('position') as THREE.BufferAttribute;\n n = 0;\n for (const [x, y] of this.columns)\n if (far(x, y)) {\n columns.setXYZ(n++, x, y, this.bottom);\n columns.setXYZ(n++, x, y, this.top);\n }\n columns.needsUpdate = true;\n this.columnLines.geometry.setDrawRange(0, n);\n }\n\n dispose() {\n for (const child of this.children as THREE.LineSegments[]) {\n child.geometry.dispose();\n (child.material as THREE.Material).dispose();\n }\n this.clear();\n this.ringLines = this.columnLines = undefined;\n this.rings = [];\n this.columns = [];\n }\n}\n\n// Excavated ground reads as depth only if the cut face is not one flat band. Dig anywhere in central\n// Helsinki and you pass through the same sequence: made ground over post-glacial sand, the blue-grey\n// Litorina clay the whole city is founded on, stony glacial till, then granite bedrock. Each layer\n// gets its own colour, blended over a short transition so the face reads geological rather than CAD.\n// Depths are metres below grade; the last entry runs to the bottom of the shaft.\nconst PROFILE: { until: number; color: THREE.Color }[] = [\n // Muted on purpose. These were the real colours of a Helsinki bore log — amber sand over Litorina\n // clay over till — and side by side at full chroma they read as a geology poster rather than as\n // ground: a band of teal and a band of yellow, competing with the building standing in them. Same\n // sequence, same order, a fraction of the saturation, so depth still reads as layers and the eye\n // stays on the plan.\n { until: -1.4, color: new THREE.Color('#6d6863') }, // made ground / pavement sub-base\n { until: -4.5, color: new THREE.Color('#968c7d') }, // sand & gravel\n { until: -11, color: new THREE.Color('#7d8891') }, // Litorina clay, the blue-grey one\n { until: -18, color: new THREE.Color('#877f75') }, // glacial till / moraine\n { until: Number.NEGATIVE_INFINITY, color: new THREE.Color('#79767b') }, // granite bedrock\n];\nconst BLEND = 1.1; // metres of gradation between layers\nconst SLAB_LINE = new THREE.Color('#b7b2a9');\n// Deterministic value noise — soil is mottled, and strata are horizontal, so it varies faster with\n// depth than across the face. No assets and no dependency; the same point always shades the same.\nconst hash = (x: number, y: number, z: number) => {\n const s = Math.sin(x * 12.9898 + y * 78.233 + z * 37.719) * 43758.5453;\n return s - Math.floor(s);\n};\nconst grain = (x: number, y: number, z: number) => {\n const fine = hash(Math.round(x * 0.9), Math.round(y * 0.9), Math.round(z * 2.4)) - 0.5;\n const broad = hash(Math.round(x * 0.16), Math.round(y * 0.16), Math.round(z * 0.5)) - 0.5;\n // Occasional darker stones sitting in the till.\n const stone = hash(Math.round(x * 1.7), Math.round(y * 1.7), Math.round(z * 1.7)) > 0.965 ? -0.13 : 0;\n return fine * 0.13 + broad * 0.16 + stone;\n};\n/** Only the shaft boundary needs vertical faces; no 1.8 km cap to triangulate or raycast. */\nexport function undergroundPit(ring: Point[], floor: number, bottom: number, strata: number[] = []): THREE.Group {\n const group = new THREE.Group();\n group.name = 'kerros-excavation';\n const layerAt = (z: number, target: THREE.Color) => {\n let index = PROFILE.findIndex(l => z >= l.until);\n if (index < 0) index = PROFILE.length - 1;\n target.copy(PROFILE[index].color);\n // Gradate into the layer below rather than cutting a hard line.\n const edge = PROFILE[index].until;\n if (index + 1 < PROFILE.length && Number.isFinite(edge) && z - edge < BLEND)\n target.lerp(PROFILE[index + 1].color, (1 - (z - edge) / BLEND) * 0.5);\n return target;\n };\n const shade = (x: number, y: number, z: number, target: THREE.Color) => {\n layerAt(z, target);\n // The exposed face is darker the deeper it sits — less bounced light reaches the bottom.\n const depth = bottom < 0 ? Math.min(1, Math.max(0, z / bottom)) : 0;\n target.multiplyScalar(1 + grain(x, y, z) - depth * 0.15);\n // A pale line of cut concrete where each deck slab meets the soil.\n for (const s of strata) if (Math.abs(z - s) < 0.35) target.lerp(SLAB_LINE, 0.5);\n return target;\n };\n // `fade` makes the face solid at `hi` and transparent at `lo`. The veil above the inspected level\n // uses it so the ground you are looking through thins out to nothing exactly where your floor is —\n // the geology stays readable near grade without anything standing over the floor being inspected.\n // It used to be the other way round, which put the densest band of soil across the near edge of\n // the plate you had come down to look at and left grade itself invisible.\n const sides = (lo: number, hi: number, opacity: number, detail: boolean, fade = false) => {\n if (hi <= lo) return;\n const positions: number[] = [];\n const colors: number[] = [];\n const c = new THREE.Color();\n const push = (x: number, y: number, z: number) => {\n positions.push(x, y, z);\n shade(x, y, z, c);\n colors.push(c.r, c.g, c.b);\n // Squared falloff keeps the soil near grade legible while clearing quickly toward the floor.\n if (fade) colors.push(((z - lo) / (hi - lo)) ** 2);\n };\n // Subdivide the face: vertex colours can only express strata and mottling if there are vertices\n // between the top and the bottom.\n const rows = detail ? Math.min(110, Math.max(2, Math.ceil((hi - lo) / 0.55))) : 2;\n const dz = (hi - lo) / rows;\n ring.forEach(([ax, ay], i) => {\n const [bx, by] = ring[(i + 1) % ring.length];\n const span = Math.hypot(bx - ax, by - ay);\n const cols = detail ? Math.min(64, Math.max(1, Math.round(span / 3.5))) : 1;\n for (let col = 0; col < cols; col++) {\n const t0 = col / cols,\n t1 = (col + 1) / cols;\n const x0 = ax + (bx - ax) * t0,\n y0 = ay + (by - ay) * t0;\n const x1 = ax + (bx - ax) * t1,\n y1 = ay + (by - ay) * t1;\n for (let r = 0; r < rows; r++) {\n const z0 = lo + dz * r,\n z1 = lo + dz * (r + 1);\n push(x0, y0, z0);\n push(x1, y1, z0);\n push(x1, y1, z1);\n push(x0, y0, z0);\n push(x1, y1, z1);\n push(x0, y0, z1);\n }\n }\n });\n const geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, fade ? 4 : 3));\n geometry.computeVertexNormals();\n const mesh = new THREE.Mesh(\n geometry,\n new THREE.MeshStandardMaterial({\n vertexColors: true,\n roughness: 1,\n side: THREE.DoubleSide,\n transparent: opacity < 1,\n opacity,\n depthWrite: opacity === 1,\n }),\n );\n mesh.raycast = () => {};\n group.add(mesh);\n };\n sides(bottom, floor, 1, true);\n sides(floor, 0, 0.38, true, true);\n const shape = new THREE.Shape(ring.map(p => new THREE.Vector2(...p)));\n const base = new THREE.Mesh(\n new THREE.ShapeGeometry(shape),\n // The floor of the excavation is whatever the last layer is — bedrock, in a deep shaft.\n new THREE.MeshStandardMaterial({\n color: layerAt(bottom, new THREE.Color()).multiplyScalar(0.62),\n roughness: 1,\n side: THREE.DoubleSide,\n }),\n );\n base.position.z = bottom;\n base.raycast = () => {};\n group.add(base);\n return group;\n}\n"],"names":["UndergroundCage","THREE","__publicField","rings","columns","bottom","top","evening","count","x","y","bounds","ring","p","cx","cy","lines","capacity","color","opacity","geometry","mesh","bearing","delta","fx","fy","far","n","i","a","b","child","PROFILE","BLEND","SLAB_LINE","hash","z","s","grain","fine","broad","stone","undergroundPit","floor","strata","group","layerAt","target","index","l","edge","shade","depth","sides","lo","hi","detail","fade","positions","colors","c","push","rows","dz","ax","ay","bx","by","span","cols","col","t0","t1","x0","y0","x1","y1","r","z0","z1","shape","base"],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
var B = Object.defineProperty;
|
|
2
|
+
var k = (t, e, n) => e in t ? B(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n;
|
|
3
|
+
var h = (t, e, n) => k(t, typeof e != "symbol" ? e + "" : e, n);
|
|
4
|
+
import { spaceAt as A } from "../model/spaces.js";
|
|
5
|
+
const S = [
|
|
6
|
+
{ id: "silent", label: "Silent", description: "Nothing but the walk" },
|
|
7
|
+
{ id: "office", label: "Office", description: "Ventilation and a faint ballast hum" },
|
|
8
|
+
{ id: "backrooms", label: "Backrooms", description: "Ballasts, breathing air handling, a compressor somewhere" },
|
|
9
|
+
{ id: "plant", label: "Plant room", description: "Machinery, close and loud" },
|
|
10
|
+
{ id: "elevator", label: "Elevator music", description: "Gentle electric keys and an original lounge melody" },
|
|
11
|
+
{ id: "baths", label: "Bath music", description: "Slow suspended chords, soft glass bells and a spacious echo" }
|
|
12
|
+
];
|
|
13
|
+
function M(t, e, n) {
|
|
14
|
+
const a = A(t, e, n), s = t.floors.find((o) => o.id === e), i = (a == null ? void 0 : a.ambience) ?? (s == null ? void 0 : s.ambience) ?? null;
|
|
15
|
+
return i && i.preset !== "silent" ? i : null;
|
|
16
|
+
}
|
|
17
|
+
const f = 1.6, y = /* @__PURE__ */ new WeakMap();
|
|
18
|
+
function w(t) {
|
|
19
|
+
const e = y.get(t);
|
|
20
|
+
if (e) return e;
|
|
21
|
+
const n = G(t);
|
|
22
|
+
return y.set(t, n), n;
|
|
23
|
+
}
|
|
24
|
+
function G(t) {
|
|
25
|
+
const n = t.createBuffer(1, t.sampleRate * 4, t.sampleRate), a = n.getChannelData(0), s = new Float32Array(8);
|
|
26
|
+
let i = 2654435769;
|
|
27
|
+
const o = () => (i = Math.imul(i ^ i >>> 15, 739982445) + 739982445 | 0, (i >>> 0) / 4294967295 * 2 - 1);
|
|
28
|
+
for (let c = 0; c < a.length; c++) {
|
|
29
|
+
let u = 0;
|
|
30
|
+
for (let r = 0; r < s.length; r++)
|
|
31
|
+
c % (1 << r) === 0 && (s[r] = o()), u += s[r];
|
|
32
|
+
a[c] = u / s.length;
|
|
33
|
+
}
|
|
34
|
+
return n;
|
|
35
|
+
}
|
|
36
|
+
function m(t, e, n, a, s) {
|
|
37
|
+
const i = [], o = [];
|
|
38
|
+
return s.forEach((c, u) => {
|
|
39
|
+
const r = t.createOscillator();
|
|
40
|
+
r.type = u === 0 ? "sine" : "triangle", r.frequency.value = n * (u + 1);
|
|
41
|
+
const l = t.createGain();
|
|
42
|
+
l.gain.value = a * c, r.connect(l).connect(e), r.start(), i.push(l), o.push(r);
|
|
43
|
+
}), { nodes: i, sources: o };
|
|
44
|
+
}
|
|
45
|
+
function b(t, e, n) {
|
|
46
|
+
const a = t.createGain();
|
|
47
|
+
a.gain.value = n;
|
|
48
|
+
const s = t.createBiquadFilter();
|
|
49
|
+
s.type = "bandpass", s.frequency.value = 650, s.Q.value = 0.45, s.connect(a).connect(e);
|
|
50
|
+
const i = m(t, s, 100, 0.7, [1, 0.7, 0.55, 0.5, 0.4, 0.32, 0.26, 0.2, 0.16, 0.13, 0.1, 0.08]), o = t.createOscillator();
|
|
51
|
+
o.type = "sine", o.frequency.value = 7900;
|
|
52
|
+
const c = t.createGain();
|
|
53
|
+
c.gain.value = n * 0.03, o.connect(c).connect(e), o.start();
|
|
54
|
+
const u = t.createOscillator();
|
|
55
|
+
u.frequency.value = 0.37;
|
|
56
|
+
const r = t.createGain();
|
|
57
|
+
return r.gain.value = n * 0.12, u.connect(r).connect(a.gain), u.start(), { nodes: [a, s, c, r, ...i.nodes], sources: [...i.sources, o, u] };
|
|
58
|
+
}
|
|
59
|
+
function g(t, e, n, a = 0.05) {
|
|
60
|
+
const s = t.createBufferSource();
|
|
61
|
+
s.buffer = w(t), s.loop = !0;
|
|
62
|
+
const i = t.createBiquadFilter();
|
|
63
|
+
i.type = "lowpass", i.frequency.value = 1100, i.Q.value = 0.6;
|
|
64
|
+
const o = t.createBiquadFilter();
|
|
65
|
+
o.type = "peaking", o.frequency.value = 170, o.Q.value = 2.5, o.gain.value = 6;
|
|
66
|
+
const c = t.createGain();
|
|
67
|
+
c.gain.value = n, s.connect(i).connect(o).connect(c).connect(e);
|
|
68
|
+
const u = t.createBiquadFilter();
|
|
69
|
+
u.type = "highpass", u.frequency.value = 2400;
|
|
70
|
+
const r = t.createGain();
|
|
71
|
+
r.gain.value = n * 0.22, s.connect(u).connect(r).connect(e), s.start();
|
|
72
|
+
const l = t.createOscillator();
|
|
73
|
+
l.frequency.value = a;
|
|
74
|
+
const d = t.createGain();
|
|
75
|
+
return d.gain.value = n * 0.3, l.connect(d).connect(c.gain), l.start(), { nodes: [i, o, c, d, u, r], sources: [s, l] };
|
|
76
|
+
}
|
|
77
|
+
function T(t, e, n) {
|
|
78
|
+
const a = t.createGain();
|
|
79
|
+
a.gain.value = 0, a.connect(e);
|
|
80
|
+
const s = m(t, a, 50, n, [0.6, 1, 0.7, 0.5, 0.35, 0.25]), i = t.createBufferSource();
|
|
81
|
+
i.buffer = w(t), i.loop = !0;
|
|
82
|
+
const o = t.createBiquadFilter();
|
|
83
|
+
o.type = "lowpass", o.frequency.value = 260;
|
|
84
|
+
const c = t.createGain();
|
|
85
|
+
c.gain.value = n * 0.35, i.connect(o).connect(c).connect(a), i.start();
|
|
86
|
+
const u = 34, r = 18, l = 0.4;
|
|
87
|
+
let d = t.currentTime + 3, p;
|
|
88
|
+
const v = () => {
|
|
89
|
+
a.gain.setTargetAtTime(1, d, l), a.gain.setTargetAtTime(0, d + u, l * 0.6), d += u + r, p = setTimeout(v, (d - t.currentTime - 5) * 1e3);
|
|
90
|
+
};
|
|
91
|
+
return v(), {
|
|
92
|
+
nodes: [a, o, c, ...s.nodes],
|
|
93
|
+
sources: [...s.sources, i, { stop: () => clearTimeout(p) }]
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function q(t, e, n) {
|
|
97
|
+
let a = !1;
|
|
98
|
+
const s = {
|
|
99
|
+
nodes: [],
|
|
100
|
+
sources: [
|
|
101
|
+
{
|
|
102
|
+
stop: () => {
|
|
103
|
+
a = !0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
return import("./bathMusic.js").then((i) => {
|
|
109
|
+
if (a || t.state === "closed") return;
|
|
110
|
+
const o = i[n](t, e);
|
|
111
|
+
s.nodes.push(...o.nodes), s.sources.push(...o.sources);
|
|
112
|
+
}).catch((i) => console.warn("Room music could not load.", i)), s;
|
|
113
|
+
}
|
|
114
|
+
const O = {
|
|
115
|
+
baths: (t, e) => [q(t, e, "bathMusic")],
|
|
116
|
+
elevator: (t, e) => [q(t, e, "elevatorMusic")],
|
|
117
|
+
office: (t, e) => [g(t, e, 0.24, 0.04), b(t, e, 0.07)],
|
|
118
|
+
backrooms: (t, e) => [g(t, e, 0.34, 0.06), b(t, e, 0.2), T(t, e, 0.22)],
|
|
119
|
+
plant: (t, e) => [
|
|
120
|
+
g(t, e, 0.6, 0.1),
|
|
121
|
+
m(t, e, 50, 0.3, [0.6, 1, 0.7, 0.5, 0.3]),
|
|
122
|
+
T(t, e, 0.35)
|
|
123
|
+
]
|
|
124
|
+
};
|
|
125
|
+
class C {
|
|
126
|
+
constructor() {
|
|
127
|
+
h(this, "ctx");
|
|
128
|
+
h(this, "master");
|
|
129
|
+
h(this, "playing");
|
|
130
|
+
h(this, "fading", []);
|
|
131
|
+
h(this, "muted", !1);
|
|
132
|
+
}
|
|
133
|
+
get isMuted() {
|
|
134
|
+
return this.muted;
|
|
135
|
+
}
|
|
136
|
+
/** Let the context run. Safe to call on every gesture; a running context ignores it. */
|
|
137
|
+
resume() {
|
|
138
|
+
var e;
|
|
139
|
+
((e = this.ctx) == null ? void 0 : e.state) === "suspended" && this.ctx.resume();
|
|
140
|
+
}
|
|
141
|
+
setMuted(e) {
|
|
142
|
+
this.muted = e;
|
|
143
|
+
const n = this.master;
|
|
144
|
+
n && this.ctx && n.gain.setTargetAtTime(e ? 0 : 1, this.ctx.currentTime, 0.15);
|
|
145
|
+
}
|
|
146
|
+
/** Play this — or nothing, for null — fading out whatever was playing. Same thing again is a no-op. */
|
|
147
|
+
set(e) {
|
|
148
|
+
var o;
|
|
149
|
+
const n = e ? `${e.preset}@${e.level ?? 1}` : "";
|
|
150
|
+
if ((((o = this.playing) == null ? void 0 : o.key) ?? "") === n) return;
|
|
151
|
+
const a = this.context();
|
|
152
|
+
if (!a || !this.master || (this.playing && this.fadeOut(this.playing), this.playing = void 0, !e)) return;
|
|
153
|
+
const s = a.createGain();
|
|
154
|
+
s.gain.value = 0, s.connect(this.master);
|
|
155
|
+
const i = O[e.preset](a, s);
|
|
156
|
+
s.gain.setTargetAtTime(e.level ?? 1, a.currentTime, f / 3), this.playing = { key: n, gain: s, layers: i };
|
|
157
|
+
}
|
|
158
|
+
dispose() {
|
|
159
|
+
this.playing && this.fadeOut(this.playing), this.playing = void 0;
|
|
160
|
+
const e = this.ctx;
|
|
161
|
+
this.ctx = void 0, this.master = void 0, setTimeout(() => void (e == null ? void 0 : e.close().catch(() => {
|
|
162
|
+
})), f * 1e3 + 200);
|
|
163
|
+
}
|
|
164
|
+
context() {
|
|
165
|
+
if (this.ctx) return this.ctx;
|
|
166
|
+
const e = globalThis.AudioContext;
|
|
167
|
+
if (!e) return;
|
|
168
|
+
try {
|
|
169
|
+
this.ctx = new e();
|
|
170
|
+
} catch {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this.master = this.ctx.createGain(), this.master.gain.value = this.muted ? 0 : 1;
|
|
174
|
+
const n = this.ctx.createDynamicsCompressor();
|
|
175
|
+
return n.threshold.value = -12, n.knee.value = 12, n.ratio.value = 8, n.attack.value = 5e-3, n.release.value = 0.2, this.master.connect(n).connect(this.ctx.destination), this.ctx;
|
|
176
|
+
}
|
|
177
|
+
fadeOut(e) {
|
|
178
|
+
const n = this.ctx;
|
|
179
|
+
n && (e.gain.gain.setTargetAtTime(0, n.currentTime, f / 3), this.fading.push(e), setTimeout(() => {
|
|
180
|
+
this.fading = this.fading.filter((a) => a !== e);
|
|
181
|
+
for (const a of e.layers) {
|
|
182
|
+
for (const s of a.sources) s.stop();
|
|
183
|
+
for (const s of a.nodes) s.disconnect();
|
|
184
|
+
}
|
|
185
|
+
e.gain.disconnect();
|
|
186
|
+
}, f * 1e3));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export {
|
|
190
|
+
S as AMBIENCES,
|
|
191
|
+
C as AmbienceEngine,
|
|
192
|
+
M as ambienceAt
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=ambience.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ambience.js","sources":["../../../../src/map/ambience.ts"],"sourcesContent":["// The sound of a building, heard from inside it. No audio recordings are fetched: every preset is a\n// small Web Audio graph — oscillators for the ballasts and the compressor, filtered noise for the air\n// handling — because a hum is a hum and a file of one would be a hundred kilobytes of the same second.\n//\n// Two halves. ambienceAt() is the document's opinion of what a point on a floor sounds like, pure and\n// testable; AmbienceEngine plays it, cross-fading as the walker crosses from one space into the next.\nimport type { Ambience, AmbiencePreset, Point, ProjectDocument } from '../model/types';\nimport { spaceAt } from '../model/spaces';\n\nexport const AMBIENCES: { id: AmbiencePreset; label: string; description: string }[] = [\n { id: 'silent', label: 'Silent', description: 'Nothing but the walk' },\n { id: 'office', label: 'Office', description: 'Ventilation and a faint ballast hum' },\n { id: 'backrooms', label: 'Backrooms', description: 'Ballasts, breathing air handling, a compressor somewhere' },\n { id: 'plant', label: 'Plant room', description: 'Machinery, close and loud' },\n { id: 'elevator', label: 'Elevator music', description: 'Gentle electric keys and an original lounge melody' },\n { id: 'baths', label: 'Bath music', description: 'Slow suspended chords, soft glass bells and a spacious echo' },\n];\n\n/** What a point on a floor sounds like: the space's own ambience, else the floor's, else nothing.\n * `silent` resolves to null too, so a room can be the quiet one on a humming floor. */\nexport function ambienceAt(project: ProjectDocument, floorId: string | null, at: Point): Ambience | null {\n const space = spaceAt(project, floorId, at);\n const floor = project.floors.find(f => f.id === floorId);\n const chosen = space?.ambience ?? floor?.ambience ?? null;\n return chosen && chosen.preset !== 'silent' ? chosen : null;\n}\n\n/** How long a room takes to fade into the next. A door is not a switch. */\nconst CROSSFADE = 1.6;\n\n/* ------------------------------------------------------------------ the sounds */\n\n/** Looping pink-ish noise, four seconds of it: a Voss–McCartney sum of white noise at octave rates,\n * which is what air moving through ducting sounds like before the filters shape it. Made once per\n * context: it is a few hundred thousand samples, and a preset is built inside the walk's own frame,\n * on the step that crosses a threshold. */\nconst noiseBuffers = new WeakMap<AudioContext, AudioBuffer>();\nfunction noiseBuffer(ctx: AudioContext): AudioBuffer {\n const cached = noiseBuffers.get(ctx);\n if (cached) return cached;\n const buffer = makeNoise(ctx);\n noiseBuffers.set(ctx, buffer);\n return buffer;\n}\nfunction makeNoise(ctx: AudioContext): AudioBuffer {\n const seconds = 4,\n buffer = ctx.createBuffer(1, ctx.sampleRate * seconds, ctx.sampleRate),\n data = buffer.getChannelData(0);\n const rows = new Float32Array(8);\n let seed = 0x9e3779b9;\n const random = () => {\n seed = (Math.imul(seed ^ (seed >>> 15), 0x2c1b3c6d) + 0x2c1b3c6d) | 0;\n return ((seed >>> 0) / 0xffffffff) * 2 - 1;\n };\n for (let i = 0; i < data.length; i++) {\n let sum = 0;\n for (let r = 0; r < rows.length; r++) {\n if (i % (1 << r) === 0) rows[r] = random();\n sum += rows[r];\n }\n data[i] = sum / rows.length;\n }\n return buffer;\n}\n\ninterface Layer {\n nodes: AudioNode[];\n sources: (AudioScheduledSourceNode | { stop(): void })[];\n}\n\nfunction hum(ctx: AudioContext, out: AudioNode, hz: number, gain: number, harmonics: number[]): Layer {\n const nodes: AudioNode[] = [],\n sources: AudioScheduledSourceNode[] = [];\n harmonics.forEach((weight, i) => {\n const osc = ctx.createOscillator();\n osc.type = i === 0 ? 'sine' : 'triangle';\n osc.frequency.value = hz * (i + 1);\n const g = ctx.createGain();\n g.gain.value = gain * weight;\n osc.connect(g).connect(out);\n osc.start();\n nodes.push(g);\n sources.push(osc);\n });\n return { nodes, sources };\n}\n\n/** A fluorescent ballast: mains at twice the line frequency with a comb of harmonics, and a thin\n * whine up where the ballast itself sings. Slightly unsteady — a real one is. */\nfunction ballast(ctx: AudioContext, out: AudioNode, level: number): Layer {\n // Voiced for the speakers people actually have. A ballast's fundamental is 100 Hz, which a laptop\n // cannot reproduce at all; what you hear of one is its harmonics up through the midrange, so the\n // comb runs well past a kilohertz and the band that shapes it sits there too.\n const g = ctx.createGain();\n g.gain.value = level;\n const band = ctx.createBiquadFilter();\n band.type = 'bandpass';\n band.frequency.value = 650;\n band.Q.value = 0.45;\n band.connect(g).connect(out);\n const tone = hum(ctx, band, 100, 0.7, [1, 0.7, 0.55, 0.5, 0.4, 0.32, 0.26, 0.2, 0.16, 0.13, 0.1, 0.08]);\n const whine = ctx.createOscillator();\n whine.type = 'sine';\n whine.frequency.value = 7900;\n const wg = ctx.createGain();\n wg.gain.value = level * 0.03;\n whine.connect(wg).connect(out);\n whine.start();\n // Flutter: a slow wobble on the level so it never settles into a pure tone.\n const lfo = ctx.createOscillator();\n lfo.frequency.value = 0.37;\n const depth = ctx.createGain();\n depth.gain.value = level * 0.12;\n lfo.connect(depth).connect(g.gain);\n lfo.start();\n return { nodes: [g, band, wg, depth, ...tone.nodes], sources: [...tone.sources, whine, lfo] };\n}\n\n/** Air handling: pink noise through a low shelf, with a resonance where the duct sings and a slow\n * breath on the level as the plant modulates. */\nfunction airHandling(ctx: AudioContext, out: AudioNode, level: number, breath = 0.05): Layer {\n const src = ctx.createBufferSource();\n src.buffer = noiseBuffer(ctx);\n src.loop = true;\n const low = ctx.createBiquadFilter();\n low.type = 'lowpass';\n low.frequency.value = 1100;\n low.Q.value = 0.6;\n const duct = ctx.createBiquadFilter();\n duct.type = 'peaking';\n duct.frequency.value = 170;\n duct.Q.value = 2.5;\n duct.gain.value = 6;\n const g = ctx.createGain();\n g.gain.value = level;\n src.connect(low).connect(duct).connect(g).connect(out);\n // The diffusers: the same noise, only its top, quiet. This is the part a laptop can play.\n const rush = ctx.createBiquadFilter();\n rush.type = 'highpass';\n rush.frequency.value = 2400;\n const rg = ctx.createGain();\n rg.gain.value = level * 0.22;\n src.connect(rush).connect(rg).connect(out);\n src.start();\n const lfo = ctx.createOscillator();\n lfo.frequency.value = breath;\n const depth = ctx.createGain();\n depth.gain.value = level * 0.3;\n lfo.connect(depth).connect(g.gain);\n lfo.start();\n return { nodes: [low, duct, g, depth, rush, rg], sources: [src, lfo] };\n}\n\n/** A compressor that cycles: mains hum and a low rattle for half a minute, then off for a while,\n * with the thump of the relay at each end. Scheduled ahead on the audio clock, so it keeps time\n * whatever the main thread is doing. */\nfunction compressor(ctx: AudioContext, out: AudioNode, level: number): Layer {\n const g = ctx.createGain();\n g.gain.value = 0;\n g.connect(out);\n // Harmonics up to 300 Hz: the fundamental is felt, the harmonics are what is heard.\n const tone = hum(ctx, g, 50, level, [0.6, 1, 0.7, 0.5, 0.35, 0.25]);\n const rattle = ctx.createBufferSource();\n rattle.buffer = noiseBuffer(ctx);\n rattle.loop = true;\n const low = ctx.createBiquadFilter();\n low.type = 'lowpass';\n low.frequency.value = 260;\n const rg = ctx.createGain();\n rg.gain.value = level * 0.35;\n rattle.connect(low).connect(rg).connect(g);\n rattle.start();\n // The duty cycle, scheduled a cycle at a time.\n const ON = 34,\n OFF = 18,\n RISE = 0.4;\n let at = ctx.currentTime + 3;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n g.gain.setTargetAtTime(1, at, RISE);\n g.gain.setTargetAtTime(0, at + ON, RISE * 0.6);\n at += ON + OFF;\n timer = setTimeout(schedule, (at - ctx.currentTime - 5) * 1000);\n };\n schedule();\n return {\n nodes: [g, low, rg, ...tone.nodes],\n sources: [...tone.sources, rattle, { stop: () => clearTimeout(timer) }],\n };\n}\n\n/** Load the score only on entering a musical space. A plan-only viewer never needs its synthesis\n * code. The stop flag also covers leaving Walk before the import has completed. */\nfunction music(ctx: AudioContext, out: AudioNode, preset: 'bathMusic' | 'elevatorMusic'): Layer {\n let stopped = false;\n const layer: Layer = {\n nodes: [],\n sources: [\n {\n stop: () => {\n stopped = true;\n },\n },\n ],\n };\n void import('./bathMusic')\n .then(score => {\n if (stopped || ctx.state === 'closed') return;\n const playing = score[preset](ctx, out);\n layer.nodes.push(...playing.nodes);\n layer.sources.push(...playing.sources);\n })\n .catch(error => console.warn('Room music could not load.', error));\n return layer;\n}\n\nconst RECIPES: Record<Exclude<AmbiencePreset, 'silent'>, (ctx: AudioContext, out: AudioNode) => Layer[]> = {\n baths: (ctx, out) => [music(ctx, out, 'bathMusic')],\n elevator: (ctx, out) => [music(ctx, out, 'elevatorMusic')],\n office: (ctx, out) => [airHandling(ctx, out, 0.24, 0.04), ballast(ctx, out, 0.07)],\n backrooms: (ctx, out) => [airHandling(ctx, out, 0.34, 0.06), ballast(ctx, out, 0.2), compressor(ctx, out, 0.22)],\n plant: (ctx, out) => [\n airHandling(ctx, out, 0.6, 0.1),\n hum(ctx, out, 50, 0.3, [0.6, 1, 0.7, 0.5, 0.3]),\n compressor(ctx, out, 0.35),\n ],\n};\n\n/* ------------------------------------------------------------------ the player */\n\ninterface Playing {\n key: string;\n gain: GainNode;\n layers: Layer[];\n}\n\n/** Plays one ambience at a time and cross-fades between them. Owns its AudioContext, which the\n * browser will only let run after the person has clicked or pressed something — resume() is for\n * the host to call from such a gesture, and everything else copes with a context that is not yet\n * running by starting silently and coming up when it is. */\nexport class AmbienceEngine {\n private ctx?: AudioContext;\n private master?: GainNode;\n private playing?: Playing;\n private fading: Playing[] = [];\n private muted = false;\n\n get isMuted() {\n return this.muted;\n }\n\n /** Let the context run. Safe to call on every gesture; a running context ignores it. */\n resume() {\n if (this.ctx?.state === 'suspended') void this.ctx.resume();\n }\n\n setMuted(muted: boolean) {\n this.muted = muted;\n const master = this.master;\n if (master && this.ctx) master.gain.setTargetAtTime(muted ? 0 : 1, this.ctx.currentTime, 0.15);\n }\n\n /** Play this — or nothing, for null — fading out whatever was playing. Same thing again is a no-op. */\n set(ambience: Ambience | null) {\n const key = ambience ? `${ambience.preset}@${ambience.level ?? 1}` : '';\n if ((this.playing?.key ?? '') === key) return;\n const ctx = this.context();\n if (!ctx || !this.master) return;\n if (this.playing) this.fadeOut(this.playing);\n this.playing = undefined;\n if (!ambience) return;\n const gain = ctx.createGain();\n gain.gain.value = 0;\n gain.connect(this.master);\n const layers = RECIPES[ambience.preset as Exclude<AmbiencePreset, 'silent'>](ctx, gain);\n gain.gain.setTargetAtTime(ambience.level ?? 1, ctx.currentTime, CROSSFADE / 3);\n this.playing = { key, gain, layers };\n }\n\n dispose() {\n if (this.playing) this.fadeOut(this.playing);\n this.playing = undefined;\n const ctx = this.ctx;\n this.ctx = undefined;\n this.master = undefined;\n // Let the fade be heard, then close. Closing releases the hardware; a page that leaves a\n // context open per visit runs out of them.\n setTimeout(() => void ctx?.close().catch(() => undefined), CROSSFADE * 1000 + 200);\n }\n\n private context(): AudioContext | undefined {\n if (this.ctx) return this.ctx;\n const Ctor = (globalThis as { AudioContext?: typeof AudioContext }).AudioContext;\n if (!Ctor) return undefined;\n try {\n this.ctx = new Ctor();\n } catch {\n return undefined;\n }\n this.master = this.ctx.createGain();\n this.master.gain.value = this.muted ? 0 : 1;\n // A limiter on the way out. The layers are levelled to sit well under full scale together, but\n // a compressor coming on over a ballast on a loud floor is exactly the sum nobody has listened\n // to on every device; this turns \"might clip\" into \"will not\".\n const limiter = this.ctx.createDynamicsCompressor();\n limiter.threshold.value = -12;\n limiter.knee.value = 12;\n limiter.ratio.value = 8;\n limiter.attack.value = 0.005;\n limiter.release.value = 0.2;\n this.master.connect(limiter).connect(this.ctx.destination);\n return this.ctx;\n }\n\n private fadeOut(playing: Playing) {\n const ctx = this.ctx;\n if (!ctx) return;\n playing.gain.gain.setTargetAtTime(0, ctx.currentTime, CROSSFADE / 3);\n this.fading.push(playing);\n setTimeout(() => {\n this.fading = this.fading.filter(p => p !== playing);\n for (const layer of playing.layers) {\n for (const s of layer.sources) s.stop();\n for (const n of layer.nodes) n.disconnect();\n }\n playing.gain.disconnect();\n }, CROSSFADE * 1000);\n }\n}\n"],"names":["AMBIENCES","ambienceAt","project","floorId","at","space","spaceAt","floor","f","chosen","CROSSFADE","noiseBuffers","noiseBuffer","ctx","cached","buffer","makeNoise","data","rows","seed","random","i","sum","hum","out","hz","gain","harmonics","nodes","sources","weight","osc","g","ballast","level","band","tone","whine","wg","lfo","depth","airHandling","breath","src","low","duct","rush","rg","compressor","rattle","ON","OFF","RISE","timer","schedule","music","preset","stopped","layer","score","playing","error","RECIPES","AmbienceEngine","__publicField","_a","muted","master","ambience","key","layers","Ctor","limiter","p","n"],"mappings":"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"}
|