@treasuryspatial/viewer-kit 0.2.44 → 0.2.50

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 (69) hide show
  1. package/dist/autoGenerate.d.ts +1 -0
  2. package/dist/autoGenerate.d.ts.map +1 -1
  3. package/dist/autoGenerate.js +10 -2
  4. package/dist/camera.d.ts +1 -0
  5. package/dist/camera.d.ts.map +1 -1
  6. package/dist/camera.js +8 -1
  7. package/dist/engine/ViewerEngine.d.ts +20 -0
  8. package/dist/engine/ViewerEngine.d.ts.map +1 -1
  9. package/dist/engine/ViewerEngine.js +254 -63
  10. package/dist/engine/types.d.ts +69 -3
  11. package/dist/engine/types.d.ts.map +1 -1
  12. package/dist/exports/download.d.ts +6 -0
  13. package/dist/exports/download.d.ts.map +1 -1
  14. package/dist/exports/download.js +142 -0
  15. package/dist/exports/three-export.d.ts +4 -1
  16. package/dist/exports/three-export.d.ts.map +1 -1
  17. package/dist/exports/three-export.js +138 -4
  18. package/dist/index.d.ts +13 -9
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +5 -4
  21. package/dist/materials/architectural.d.ts +3 -3
  22. package/dist/materials/architectural.d.ts.map +1 -1
  23. package/dist/materials/architectural.js +295 -37
  24. package/dist/materials/catalogue-data.d.ts +15 -0
  25. package/dist/materials/catalogue-data.d.ts.map +1 -1
  26. package/dist/materials/catalogue-data.js +16 -0
  27. package/dist/materials/presets.d.ts +15 -8
  28. package/dist/materials/presets.d.ts.map +1 -1
  29. package/dist/materials/presets.js +140 -39
  30. package/dist/materials/resolve.d.ts +42 -0
  31. package/dist/materials/resolve.d.ts.map +1 -1
  32. package/dist/materials/resolve.js +228 -13
  33. package/dist/materials/types.d.ts +32 -3
  34. package/dist/materials/types.d.ts.map +1 -1
  35. package/dist/presets/defaults.d.ts.map +1 -1
  36. package/dist/presets/defaults.js +17 -1
  37. package/dist/presets/sciencePresets.d.ts.map +1 -1
  38. package/dist/presets/sciencePresets.js +167 -50
  39. package/dist/scene.d.ts +28 -4
  40. package/dist/scene.d.ts.map +1 -1
  41. package/dist/scene.js +196 -31
  42. package/dist/sceneSemanticRegistry.d.ts +64 -0
  43. package/dist/sceneSemanticRegistry.d.ts.map +1 -0
  44. package/dist/sceneSemanticRegistry.js +199 -0
  45. package/dist/sky/scienceSky.d.ts.map +1 -1
  46. package/dist/sky/scienceSky.js +16 -0
  47. package/dist/systems/debugSystem.d.ts +24 -1
  48. package/dist/systems/debugSystem.d.ts.map +1 -1
  49. package/dist/systems/debugSystem.js +324 -77
  50. package/dist/systems/environmentSystem.d.ts +5 -4
  51. package/dist/systems/environmentSystem.d.ts.map +1 -1
  52. package/dist/systems/environmentSystem.js +138 -62
  53. package/dist/systems/lightingSystem.d.ts +10 -1
  54. package/dist/systems/lightingSystem.d.ts.map +1 -1
  55. package/dist/systems/lightingSystem.js +118 -17
  56. package/dist/systems/postfxSystem.d.ts +5 -1
  57. package/dist/systems/postfxSystem.d.ts.map +1 -1
  58. package/dist/systems/postfxSystem.js +84 -1
  59. package/dist/systems/rendererSystem.d.ts.map +1 -1
  60. package/dist/systems/rendererSystem.js +1 -0
  61. package/dist/tsconfig.tsbuildinfo +1 -1
  62. package/dist/uploads/geometry3dm.d.ts.map +1 -1
  63. package/dist/uploads/geometry3dm.js +1 -0
  64. package/dist/uploads/grasshopper.d.ts.map +1 -1
  65. package/dist/uploads/grasshopper.js +63 -5
  66. package/dist/uploads/mesh.js +5 -5
  67. package/dist/uploads/types.d.ts +4 -0
  68. package/dist/uploads/types.d.ts.map +1 -1
  69. package/package.json +3 -3
@@ -1,38 +1,107 @@
1
1
  import { findMaterial } from "./catalogue";
2
- export const BASELINE_MATERIAL_PRESET_ID = "calenv-baseline";
3
- const materialSlot = (catalogId, overrides) => ({
2
+ export const ARCHITECTURAL_WHITE_MATERIAL_PRESET_ID = "architectural-white";
3
+ export const MONOCHROME_CLAY_MATERIAL_PRESET_ID = "monochrome-clay";
4
+ export const UPLOAD_VISIBLE_MATERIAL_PRESET_ID = "upload-visible";
5
+ const materialBinding = (catalogId, overrides) => ({
4
6
  catalogId,
5
7
  overrides,
6
8
  });
7
9
  export const MATERIAL_PRESET_DATA = {
8
- [BASELINE_MATERIAL_PRESET_ID]: {
9
- id: BASELINE_MATERIAL_PRESET_ID,
10
- label: "calenv baseline surfaces",
10
+ [ARCHITECTURAL_WHITE_MATERIAL_PRESET_ID]: {
11
+ id: ARCHITECTURAL_WHITE_MATERIAL_PRESET_ID,
12
+ label: "architectural white surfaces",
11
13
  materials: {
12
- walls: materialSlot("white_wall", { reflectance: 0.7, roughness: 0.3 }),
13
- floor: materialSlot("stone_light", {
14
- color: { r: 232, g: 234, b: 240 },
15
- reflectance: 0.52,
16
- roughness: 0.4,
14
+ walls: materialBinding("white_wall", {
15
+ color: { r: 244, g: 244, b: 240 },
16
+ reflectance: 0.66,
17
+ roughness: 0.52,
18
+ }),
19
+ floor: materialBinding("stone_light", {
20
+ color: { r: 226, g: 225, b: 219 },
21
+ reflectance: 0.46,
22
+ roughness: 0.64,
23
+ }),
24
+ ceiling: materialBinding("acoustic_ceiling_white", {
25
+ color: { r: 248, g: 248, b: 244 },
26
+ reflectance: 0.72,
27
+ roughness: 0.56,
28
+ }),
29
+ },
30
+ },
31
+ [MONOCHROME_CLAY_MATERIAL_PRESET_ID]: {
32
+ id: MONOCHROME_CLAY_MATERIAL_PRESET_ID,
33
+ label: "monochrome clay surfaces",
34
+ materials: {
35
+ walls: materialBinding("white_wall", {
36
+ color: { r: 238, g: 238, b: 234 },
37
+ reflectance: 0.68,
38
+ roughness: 0.7,
39
+ }),
40
+ floor: materialBinding("white_wall", {
41
+ color: { r: 232, g: 232, b: 228 },
42
+ reflectance: 0.62,
43
+ roughness: 0.76,
44
+ }),
45
+ ceiling: materialBinding("white_wall", {
46
+ color: { r: 245, g: 245, b: 241 },
47
+ reflectance: 0.72,
48
+ roughness: 0.68,
49
+ }),
50
+ surfaces: {
51
+ roof: materialBinding("white_wall", {
52
+ color: { r: 238, g: 238, b: 234 },
53
+ reflectance: 0.66,
54
+ roughness: 0.72,
55
+ }),
56
+ door: materialBinding("white_wall", {
57
+ color: { r: 230, g: 230, b: 226 },
58
+ reflectance: 0.58,
59
+ roughness: 0.74,
60
+ }),
61
+ glazing: materialBinding("white_wall", {
62
+ color: { r: 224, g: 228, b: 230 },
63
+ reflectance: 0.54,
64
+ roughness: 0.62,
65
+ }),
66
+ },
67
+ },
68
+ },
69
+ [UPLOAD_VISIBLE_MATERIAL_PRESET_ID]: {
70
+ id: UPLOAD_VISIBLE_MATERIAL_PRESET_ID,
71
+ label: "upload visible surfaces",
72
+ materials: {
73
+ walls: materialBinding("white_wall", {
74
+ color: { r: 245, g: 245, b: 244 },
75
+ reflectance: 0.72,
76
+ roughness: 0.34,
77
+ }),
78
+ floor: materialBinding("stone_light", {
79
+ color: { r: 225, g: 226, b: 230 },
80
+ reflectance: 0.48,
81
+ roughness: 0.44,
82
+ }),
83
+ ceiling: materialBinding("acoustic_ceiling_white", {
84
+ color: { r: 248, g: 248, b: 246 },
85
+ reflectance: 0.76,
86
+ roughness: 0.28,
17
87
  }),
18
- ceiling: materialSlot("acoustic_ceiling_white", { reflectance: 0.7, roughness: 0.3 }),
19
88
  },
20
89
  },
21
90
  studio: {
22
91
  id: "studio",
23
92
  label: "studio high-contrast surfaces",
24
93
  materials: {
25
- walls: materialSlot("concrete_charcoal", {
94
+ walls: materialBinding("concrete_charcoal", {
26
95
  color: { r: 48, g: 52, b: 58 },
27
96
  reflectance: 0.22,
28
97
  roughness: 0.45,
29
98
  }),
30
- floor: materialSlot("stone_dark", {
99
+ floor: materialBinding("stone_dark", {
31
100
  color: { r: 28, g: 30, b: 34 },
32
101
  reflectance: 0.18,
33
102
  roughness: 0.4,
34
103
  }),
35
- ceiling: materialSlot("white_wall", {
104
+ ceiling: materialBinding("white_wall", {
36
105
  color: { r: 220, g: 222, b: 228 },
37
106
  reflectance: 0.58,
38
107
  roughness: 0.25,
@@ -43,17 +112,17 @@ export const MATERIAL_PRESET_DATA = {
43
112
  id: "daylight",
44
113
  label: "daylight pavilion surfaces",
45
114
  materials: {
46
- walls: materialSlot("white_wall", {
115
+ walls: materialBinding("white_wall", {
47
116
  color: { r: 240, g: 242, b: 248 },
48
117
  reflectance: 0.68,
49
118
  roughness: 0.35,
50
119
  }),
51
- floor: materialSlot("stone_light", {
120
+ floor: materialBinding("stone_light", {
52
121
  color: { r: 214, g: 206, b: 190 },
53
122
  reflectance: 0.45,
54
123
  roughness: 0.5,
55
124
  }),
56
- ceiling: materialSlot("acoustic_ceiling_white", {
125
+ ceiling: materialBinding("acoustic_ceiling_white", {
57
126
  color: { r: 252, g: 252, b: 248 },
58
127
  reflectance: 0.78,
59
128
  roughness: 0.22,
@@ -64,19 +133,19 @@ export const MATERIAL_PRESET_DATA = {
64
133
  id: "gallery-spot",
65
134
  label: "immersive gallery surfaces",
66
135
  materials: {
67
- walls: materialSlot("white_wall", {
136
+ walls: materialBinding("white_wall", {
68
137
  color: { r: 246, g: 237, b: 225 },
69
138
  reflectance: 0.6,
70
139
  roughness: 0.25,
71
140
  }),
72
- floor: materialSlot("stone_dark", {
141
+ floor: materialBinding("stone_dark", {
73
142
  color: { r: 90, g: 88, b: 83 },
74
143
  reflectance: 0.32,
75
144
  roughness: 0.6,
76
145
  pattern: "grid",
77
146
  patternScale: 0.4,
78
147
  }),
79
- ceiling: materialSlot("acoustic_ceiling_white", {
148
+ ceiling: materialBinding("acoustic_ceiling_white", {
80
149
  color: { r: 255, g: 250, b: 245 },
81
150
  reflectance: 0.75,
82
151
  roughness: 0.2,
@@ -87,17 +156,17 @@ export const MATERIAL_PRESET_DATA = {
87
156
  id: "lab-neutral",
88
157
  label: "neutral lab surfaces",
89
158
  materials: {
90
- walls: materialSlot("white_wall", {
159
+ walls: materialBinding("white_wall", {
91
160
  color: { r: 240, g: 240, b: 246 },
92
161
  reflectance: 0.82,
93
162
  roughness: 0.3,
94
163
  }),
95
- floor: materialSlot("timber_floor_warm", {
164
+ floor: materialBinding("timber_floor_warm", {
96
165
  color: { r: 172, g: 168, b: 160 },
97
166
  reflectance: 0.35,
98
167
  roughness: 0.55,
99
168
  }),
100
- ceiling: materialSlot("acoustic_ceiling_white", {
169
+ ceiling: materialBinding("acoustic_ceiling_white", {
101
170
  color: { r: 233, g: 235, b: 239 },
102
171
  reflectance: 0.88,
103
172
  roughness: 0.25,
@@ -108,19 +177,19 @@ export const MATERIAL_PRESET_DATA = {
108
177
  id: "atrium-suntrack",
109
178
  label: "atrium daylight surfaces",
110
179
  materials: {
111
- walls: materialSlot("stone_light", {
180
+ walls: materialBinding("stone_light", {
112
181
  color: { r: 210, g: 210, b: 205 },
113
182
  reflectance: 0.55,
114
183
  roughness: 0.4,
115
184
  }),
116
- floor: materialSlot("stone_light", {
185
+ floor: materialBinding("stone_light", {
117
186
  color: { r: 190, g: 190, b: 183 },
118
187
  reflectance: 0.4,
119
188
  roughness: 0.6,
120
189
  pattern: "grid",
121
190
  patternScale: 0.5,
122
191
  }),
123
- ceiling: materialSlot("glass_structural_clear", {
192
+ ceiling: materialBinding("glass_structural_clear", {
124
193
  color: { r: 230, g: 238, b: 245 },
125
194
  reflectance: 0.65,
126
195
  roughness: 0.15,
@@ -131,19 +200,19 @@ export const MATERIAL_PRESET_DATA = {
131
200
  id: "flow-horizon",
132
201
  label: "flow horizon surfaces",
133
202
  materials: {
134
- walls: materialSlot("glass_structural_clear", {
203
+ walls: materialBinding("glass_structural_clear", {
135
204
  color: { r: 210, g: 225, b: 235 },
136
205
  reflectance: 0.4,
137
206
  roughness: 0.2,
138
207
  }),
139
- floor: materialSlot("timber_floor_warm", {
208
+ floor: materialBinding("timber_floor_warm", {
140
209
  color: { r: 140, g: 110, b: 85 },
141
210
  reflectance: 0.28,
142
211
  roughness: 0.6,
143
212
  pattern: "herringbone",
144
213
  patternScale: 0.4,
145
214
  }),
146
- ceiling: materialSlot("timber_floor_warm", {
215
+ ceiling: materialBinding("timber_floor_warm", {
147
216
  color: { r: 210, g: 200, b: 185 },
148
217
  reflectance: 0.5,
149
218
  roughness: 0.35,
@@ -154,17 +223,17 @@ export const MATERIAL_PRESET_DATA = {
154
223
  id: "biophilic-soft",
155
224
  label: "biophilic loft surfaces",
156
225
  materials: {
157
- walls: materialSlot("white_wall", {
226
+ walls: materialBinding("white_wall", {
158
227
  color: { r: 214, g: 224, b: 214 },
159
228
  reflectance: 0.58,
160
229
  roughness: 0.35,
161
230
  }),
162
- floor: materialSlot("timber_floor_warm", {
231
+ floor: materialBinding("timber_floor_warm", {
163
232
  color: { r: 170, g: 142, b: 110 },
164
233
  reflectance: 0.32,
165
234
  roughness: 0.55,
166
235
  }),
167
- ceiling: materialSlot("acoustic_ceiling_white", {
236
+ ceiling: materialBinding("acoustic_ceiling_white", {
168
237
  color: { r: 250, g: 248, b: 240 },
169
238
  reflectance: 0.78,
170
239
  roughness: 0.25,
@@ -182,6 +251,14 @@ const hexToRgb = (hex) => {
182
251
  b: value & 0xff,
183
252
  };
184
253
  };
254
+ const findMaterialDefinition = (materialId, materialDefinitions) => {
255
+ if (materialDefinitions && "get" in materialDefinitions) {
256
+ return materialDefinitions.get(materialId) ?? findMaterial(materialId);
257
+ }
258
+ const toolMaterial = materialDefinitions?.find((material) => material.materialId === materialId);
259
+ return toolMaterial ?? findMaterial(materialId);
260
+ };
261
+ export const hasMaterialDefinition = (materialId, materialDefinitions) => Boolean(findMaterialDefinition(materialId, materialDefinitions));
185
262
  const resolveMaterialConfig = (definition, catalogId, overrides) => {
186
263
  const baselineColor = definition?.baseline?.color ?? "#ffffff";
187
264
  const baseColor = overrides?.color ?? hexToRgb(baselineColor);
@@ -194,15 +271,39 @@ const resolveMaterialConfig = (definition, catalogId, overrides) => {
194
271
  patternScale: overrides?.patternScale ?? 0.5,
195
272
  };
196
273
  };
197
- export function resolveMaterialSlot(slot) {
198
- const definition = findMaterial(slot.catalogId);
199
- return resolveMaterialConfig(definition, slot.catalogId, slot.overrides);
274
+ export function resolveMaterialBinding(binding, materialDefinitions) {
275
+ const definition = findMaterialDefinition(binding.catalogId, materialDefinitions);
276
+ return resolveMaterialConfig(definition, binding.catalogId, binding.overrides);
200
277
  }
201
- export function resolveMaterialPresetMaterials(preset) {
278
+ export function resolveMaterialSurfaceMap(surfaces, materialDefinitions) {
279
+ if (!surfaces)
280
+ return undefined;
281
+ const entries = Object.entries(surfaces)
282
+ .filter(([surfaceId]) => Boolean(surfaceId))
283
+ .map(([surfaceId, binding]) => [surfaceId, resolveMaterialBinding(binding, materialDefinitions)]);
284
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
285
+ }
286
+ export function resolveMaterialPresetMaterials(preset, materialDefinitions) {
287
+ const walls = resolveMaterialBinding(preset.materials.walls, materialDefinitions);
288
+ const floor = resolveMaterialBinding(preset.materials.floor, materialDefinitions);
289
+ const ceiling = resolveMaterialBinding(preset.materials.ceiling, materialDefinitions);
290
+ const defaultSharedSurfaces = {
291
+ roof: { ...walls },
292
+ door: { ...walls },
293
+ glazing: resolveMaterialBinding(materialBinding("glass_structural_clear", {
294
+ color: { r: 224, g: 232, b: 240 },
295
+ reflectance: 0.62,
296
+ roughness: 0.16,
297
+ }), materialDefinitions),
298
+ };
299
+ const authoredSurfaces = resolveMaterialSurfaceMap(preset.materials.surfaces, materialDefinitions);
202
300
  return {
203
- walls: resolveMaterialSlot(preset.materials.walls),
204
- floor: resolveMaterialSlot(preset.materials.floor),
205
- ceiling: resolveMaterialSlot(preset.materials.ceiling),
301
+ walls,
302
+ floor,
303
+ ceiling,
304
+ surfaces: Object.keys(authoredSurfaces ?? {}).length > 0
305
+ ? { ...defaultSharedSurfaces, ...(authoredSurfaces ?? {}) }
306
+ : defaultSharedSurfaces,
206
307
  };
207
308
  }
208
309
  export function listMaterialPresets() {
@@ -1,13 +1,55 @@
1
1
  import type { MaterialsConfig, SurfaceMaterialConfig } from "./types";
2
+ import { type MaterialDefinitionLookup } from "./presets";
2
3
  export type MaterialOverrides = {
3
4
  walls?: Partial<SurfaceMaterialConfig>;
4
5
  floor?: Partial<SurfaceMaterialConfig>;
5
6
  ceiling?: Partial<SurfaceMaterialConfig>;
7
+ surfaces?: Record<string, Partial<SurfaceMaterialConfig>>;
8
+ };
9
+ export type CoreMaterialSurface = "walls" | "floor" | "ceiling";
10
+ export type MaterialOverrideTargetKind = "core" | "surface";
11
+ export type SurfaceOverride = Partial<Pick<SurfaceMaterialConfig, "roughness" | "reflectance" | "patternScale" | "pattern" | "type" | "color">>;
12
+ export type MaterialOverrideNumberKey = "roughness" | "reflectance" | "patternScale";
13
+ export type MaterialOverrideAction = {
14
+ type: "reset";
15
+ } | {
16
+ type: "set-core-number";
17
+ surface: CoreMaterialSurface;
18
+ key: MaterialOverrideNumberKey;
19
+ value: number | null;
20
+ } | {
21
+ type: "set-surface-number";
22
+ surfaceId: string;
23
+ key: MaterialOverrideNumberKey;
24
+ value: number | null;
25
+ } | {
26
+ type: "set-core-type";
27
+ surface: CoreMaterialSurface;
28
+ value: string | null;
29
+ } | {
30
+ type: "set-surface-type";
31
+ surfaceId: string;
32
+ value: string | null;
33
+ } | {
34
+ type: "set-core-color";
35
+ surface: CoreMaterialSurface;
36
+ color: SurfaceMaterialConfig["color"] | null;
37
+ } | {
38
+ type: "set-surface-color";
39
+ surfaceId: string;
40
+ color: SurfaceMaterialConfig["color"] | null;
6
41
  };
7
42
  export type MaterialResolveOptions = {
8
43
  payload?: Record<string, unknown> | null;
9
44
  presetId?: string | null;
10
45
  overrides?: MaterialOverrides | null;
11
46
  };
47
+ export declare const CORE_MATERIAL_SURFACES: CoreMaterialSurface[];
48
+ export declare const isCoreMaterialSurface: (value: string) => value is CoreMaterialSurface;
49
+ export declare const normalizeMaterialSurfaceId: (value: string | null | undefined) => string;
50
+ export declare const normalizeMaterialSurfaceConfigMap: (surfaces: MaterialsConfig["surfaces"] | null | undefined) => MaterialsConfig["surfaces"] | undefined;
51
+ export declare const normalizeMaterialOverrides: (overrides: MaterialOverrides | null | undefined) => MaterialOverrides;
52
+ export declare const reduceMaterialOverrides: (previous: MaterialOverrides | null | undefined, action: MaterialOverrideAction) => MaterialOverrides;
53
+ export declare const mergeMaterialsConfigWithOverrides: (base: MaterialsConfig | null, overrides: MaterialOverrides | null | undefined, materialDefinitions?: MaterialDefinitionLookup) => MaterialsConfig | null;
12
54
  export declare function resolveMaterialConfig(options: MaterialResolveOptions): MaterialsConfig | null;
13
55
  //# sourceMappingURL=resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/materials/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGtE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACtC,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,GAAG,IAAI,CAyB7F"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/materials/resolve.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,223 @@
1
- import { getMaterialPreset, resolveMaterialPresetMaterials } from "./presets";
1
+ import { getMaterialPreset, resolveMaterialBinding, resolveMaterialPresetMaterials, } from "./presets";
2
+ export const CORE_MATERIAL_SURFACES = ["walls", "floor", "ceiling"];
3
+ export const isCoreMaterialSurface = (value) => CORE_MATERIAL_SURFACES.includes(value);
4
+ export const normalizeMaterialSurfaceId = (value) => value?.trim().toLowerCase() ?? "";
5
+ export const normalizeMaterialSurfaceConfigMap = (surfaces) => {
6
+ const entries = Object.entries(surfaces ?? {})
7
+ .map(([surfaceId, config]) => [normalizeMaterialSurfaceId(surfaceId), config])
8
+ .filter((entry) => Boolean(entry[0] && entry[1]));
9
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
10
+ };
11
+ const normalizeSurfaceOverrideMap = (surfaces) => {
12
+ const entries = Object.entries(surfaces ?? {})
13
+ .map(([surfaceId, config]) => [normalizeMaterialSurfaceId(surfaceId), config])
14
+ .filter((entry) => Boolean(entry[0] && entry[1]));
15
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
16
+ };
17
+ export const normalizeMaterialOverrides = (overrides) => {
18
+ if (!overrides)
19
+ return {};
20
+ const next = {};
21
+ if (overrides.walls && Object.keys(overrides.walls).length > 0)
22
+ next.walls = { ...overrides.walls };
23
+ if (overrides.floor && Object.keys(overrides.floor).length > 0)
24
+ next.floor = { ...overrides.floor };
25
+ if (overrides.ceiling && Object.keys(overrides.ceiling).length > 0)
26
+ next.ceiling = { ...overrides.ceiling };
27
+ const surfaces = normalizeSurfaceOverrideMap(overrides.surfaces);
28
+ if (surfaces)
29
+ next.surfaces = surfaces;
30
+ return next;
31
+ };
32
+ const compactOverride = (override) => {
33
+ if (!override)
34
+ return undefined;
35
+ const next = Object.fromEntries(Object.entries(override).filter(([, value]) => value !== null && value !== undefined && value !== ""));
36
+ return Object.keys(next).length > 0 ? next : undefined;
37
+ };
38
+ const setCoreOverride = (previous, surface, patch) => {
39
+ const next = { ...previous };
40
+ const merged = compactOverride({ ...previous[surface], ...patch });
41
+ if (merged) {
42
+ next[surface] = merged;
43
+ }
44
+ else {
45
+ delete next[surface];
46
+ }
47
+ return normalizeMaterialOverrides(next);
48
+ };
49
+ const setSurfaceOverride = (previous, surfaceId, patch) => {
50
+ const normalizedSurfaceId = normalizeMaterialSurfaceId(surfaceId);
51
+ if (!normalizedSurfaceId)
52
+ return normalizeMaterialOverrides(previous);
53
+ const surfaces = { ...(previous.surfaces ?? {}) };
54
+ const merged = compactOverride({ ...surfaces[normalizedSurfaceId], ...patch });
55
+ if (merged) {
56
+ surfaces[normalizedSurfaceId] = merged;
57
+ }
58
+ else {
59
+ delete surfaces[normalizedSurfaceId];
60
+ }
61
+ return normalizeMaterialOverrides({
62
+ ...previous,
63
+ surfaces: Object.keys(surfaces).length > 0 ? surfaces : undefined,
64
+ });
65
+ };
66
+ export const reduceMaterialOverrides = (previous, action) => {
67
+ const current = normalizeMaterialOverrides(previous);
68
+ switch (action.type) {
69
+ case "reset":
70
+ return {};
71
+ case "set-core-number":
72
+ return setCoreOverride(current, action.surface, { [action.key]: action.value ?? undefined });
73
+ case "set-surface-number":
74
+ return setSurfaceOverride(current, action.surfaceId, { [action.key]: action.value ?? undefined });
75
+ case "set-core-type": {
76
+ const value = action.value?.trim() || undefined;
77
+ return setCoreOverride(current, action.surface, { type: value });
78
+ }
79
+ case "set-surface-type": {
80
+ const value = action.value?.trim() || undefined;
81
+ return setSurfaceOverride(current, action.surfaceId, { type: value });
82
+ }
83
+ case "set-core-color":
84
+ return setCoreOverride(current, action.surface, { color: action.color ?? undefined });
85
+ case "set-surface-color":
86
+ return setSurfaceOverride(current, action.surfaceId, { color: action.color ?? undefined });
87
+ default:
88
+ return current;
89
+ }
90
+ };
91
+ const isCompleteSurfaceMaterialConfig = (value) => Boolean(value &&
92
+ value.type &&
93
+ value.color &&
94
+ typeof value.reflectance === "number" &&
95
+ typeof value.roughness === "number");
96
+ const mergeMaterialMap = (base, overrides) => {
97
+ if (!base && !overrides)
98
+ return undefined;
99
+ const surfaceIds = new Set([...Object.keys(base ?? {}), ...Object.keys(overrides ?? {})]);
100
+ const nextEntries = [...surfaceIds]
101
+ .map((surfaceId) => {
102
+ const baseConfig = base?.[surfaceId];
103
+ const overrideConfig = overrides?.[surfaceId];
104
+ if (!baseConfig && !isCompleteSurfaceMaterialConfig(overrideConfig))
105
+ return null;
106
+ return [
107
+ surfaceId,
108
+ {
109
+ ...(baseConfig ?? overrideConfig),
110
+ ...(overrideConfig ?? {}),
111
+ },
112
+ ];
113
+ })
114
+ .filter((entry) => Boolean(entry));
115
+ return nextEntries.length > 0 ? Object.fromEntries(nextEntries) : undefined;
116
+ };
117
+ const defaultSurfaceConfig = () => ({
118
+ type: "custom",
119
+ color: { r: 255, g: 255, b: 255 },
120
+ reflectance: 0.5,
121
+ roughness: 0.6,
122
+ });
123
+ const cleanBindingOverrides = (override) => {
124
+ if (!override)
125
+ return undefined;
126
+ const next = {};
127
+ if (override.color)
128
+ next.color = override.color;
129
+ if (typeof override.reflectance === "number")
130
+ next.reflectance = override.reflectance;
131
+ if (typeof override.roughness === "number")
132
+ next.roughness = override.roughness;
133
+ if (override.pattern)
134
+ next.pattern = override.pattern;
135
+ if (typeof override.patternScale === "number")
136
+ next.patternScale = override.patternScale;
137
+ return Object.keys(next).length > 0 ? next : undefined;
138
+ };
139
+ const normalizeMaterialDefinitionLookup = (materialDefinitions) => {
140
+ if (!Array.isArray(materialDefinitions))
141
+ return materialDefinitions;
142
+ const seen = new Set();
143
+ return materialDefinitions.filter((definition) => {
144
+ if (!definition?.materialId || seen.has(definition.materialId))
145
+ return false;
146
+ seen.add(definition.materialId);
147
+ return true;
148
+ });
149
+ };
150
+ const resolveOverrideConfig = (baseConfig, overrideConfig, materialDefinitions) => {
151
+ if (!overrideConfig)
152
+ return baseConfig ?? null;
153
+ const overrideType = typeof overrideConfig.type === "string" && overrideConfig.type.trim()
154
+ ? overrideConfig.type.trim()
155
+ : null;
156
+ if (overrideType && overrideType !== baseConfig?.type && overrideType !== "custom") {
157
+ return resolveMaterialBinding({
158
+ catalogId: overrideType,
159
+ overrides: cleanBindingOverrides(overrideConfig),
160
+ }, normalizeMaterialDefinitionLookup(materialDefinitions));
161
+ }
162
+ const seed = baseConfig ?? defaultSurfaceConfig();
163
+ return {
164
+ ...seed,
165
+ ...(overrideConfig ?? {}),
166
+ type: overrideType ?? seed.type,
167
+ color: overrideConfig.color ?? seed.color,
168
+ reflectance: typeof overrideConfig.reflectance === "number" ? overrideConfig.reflectance : seed.reflectance,
169
+ roughness: typeof overrideConfig.roughness === "number" ? overrideConfig.roughness : seed.roughness,
170
+ };
171
+ };
172
+ export const mergeMaterialsConfigWithOverrides = (base, overrides, materialDefinitions) => {
173
+ if (!base)
174
+ return null;
175
+ const baseSurfaces = normalizeMaterialSurfaceConfigMap(base.surfaces);
176
+ const overrideSurfaces = normalizeSurfaceOverrideMap(overrides?.surfaces);
177
+ const surfaceIds = new Set([
178
+ ...Object.keys(baseSurfaces ?? {}),
179
+ ...Object.keys(overrideSurfaces ?? {}),
180
+ ]);
181
+ const surfaces = [...surfaceIds]
182
+ .map((surfaceId) => {
183
+ const baseConfig = baseSurfaces?.[surfaceId];
184
+ const overrideConfig = overrideSurfaces?.[surfaceId];
185
+ const config = resolveOverrideConfig(baseConfig, overrideConfig, materialDefinitions);
186
+ if (!config)
187
+ return null;
188
+ return [surfaceId, config];
189
+ })
190
+ .filter((entry) => Boolean(entry));
191
+ const next = {
192
+ surfaces: surfaces.length > 0 ? Object.fromEntries(surfaces) : baseSurfaces,
193
+ };
194
+ const walls = resolveOverrideConfig(base.walls, overrides?.walls, materialDefinitions);
195
+ const floor = resolveOverrideConfig(base.floor, overrides?.floor, materialDefinitions);
196
+ const ceiling = resolveOverrideConfig(base.ceiling, overrides?.ceiling, materialDefinitions);
197
+ if (walls)
198
+ next.walls = walls;
199
+ if (floor)
200
+ next.floor = floor;
201
+ if (ceiling)
202
+ next.ceiling = ceiling;
203
+ return next;
204
+ };
2
205
  export function resolveMaterialConfig(options) {
3
206
  const { payload, presetId, overrides } = options;
4
207
  if (presetId) {
5
208
  try {
6
209
  const preset = getMaterialPreset(presetId);
7
210
  const base = resolveMaterialPresetMaterials(preset);
8
- return {
9
- walls: { ...base.walls, ...(overrides?.walls ?? {}) },
10
- floor: { ...base.floor, ...(overrides?.floor ?? {}) },
11
- ceiling: { ...base.ceiling, ...(overrides?.ceiling ?? {}) },
211
+ const next = {
212
+ surfaces: mergeMaterialMap(base.surfaces, overrides?.surfaces),
12
213
  };
214
+ if (base.walls)
215
+ next.walls = { ...base.walls, ...(overrides?.walls ?? {}) };
216
+ if (base.floor)
217
+ next.floor = { ...base.floor, ...(overrides?.floor ?? {}) };
218
+ if (base.ceiling)
219
+ next.ceiling = { ...base.ceiling, ...(overrides?.ceiling ?? {}) };
220
+ return next.walls || next.floor || next.ceiling || next.surfaces ? next : null;
13
221
  }
14
222
  catch {
15
223
  return null;
@@ -17,12 +225,19 @@ export function resolveMaterialConfig(options) {
17
225
  }
18
226
  const record = payload;
19
227
  const directMaterials = record?.materials ?? record?.room?.materials;
20
- if (directMaterials?.walls && directMaterials?.floor && directMaterials?.ceiling) {
21
- return {
22
- walls: { ...directMaterials.walls, ...(overrides?.walls ?? {}) },
23
- floor: { ...directMaterials.floor, ...(overrides?.floor ?? {}) },
24
- ceiling: { ...directMaterials.ceiling, ...(overrides?.ceiling ?? {}) },
25
- };
26
- }
27
- return null;
228
+ if (!directMaterials)
229
+ return null;
230
+ const next = {
231
+ surfaces: mergeMaterialMap(directMaterials?.surfaces, overrides?.surfaces),
232
+ };
233
+ if (directMaterials?.walls) {
234
+ next.walls = { ...directMaterials.walls, ...(overrides?.walls ?? {}) };
235
+ }
236
+ if (directMaterials?.floor) {
237
+ next.floor = { ...directMaterials.floor, ...(overrides?.floor ?? {}) };
238
+ }
239
+ if (directMaterials?.ceiling) {
240
+ next.ceiling = { ...directMaterials.ceiling, ...(overrides?.ceiling ?? {}) };
241
+ }
242
+ return next.walls || next.floor || next.ceiling || next.surfaces ? next : null;
28
243
  }
@@ -42,9 +42,38 @@ export type SurfaceMaterialConfig = {
42
42
  pattern?: string;
43
43
  patternScale?: number;
44
44
  };
45
+ export type MaterialSurfaceRole = "walls" | "floor" | "ceiling";
46
+ export type MaterialSurfaceConfigMap = Record<string, SurfaceMaterialConfig>;
45
47
  export type MaterialsConfig = {
46
- walls: SurfaceMaterialConfig;
47
- floor: SurfaceMaterialConfig;
48
- ceiling: SurfaceMaterialConfig;
48
+ walls?: SurfaceMaterialConfig;
49
+ floor?: SurfaceMaterialConfig;
50
+ ceiling?: SurfaceMaterialConfig;
51
+ surfaces?: MaterialSurfaceConfigMap;
52
+ };
53
+ export type SurfaceDefinition = {
54
+ id: string;
55
+ label?: string;
56
+ summary?: string;
57
+ parentId?: string;
58
+ };
59
+ export type SurfaceMappingRule = {
60
+ surfaceId: string;
61
+ surfaceIds?: string[];
62
+ classes?: string[];
63
+ subclasses?: string[];
64
+ roles?: string[];
65
+ layers?: string[];
66
+ materials?: string[];
67
+ };
68
+ export type MaterialApplicationPolicy = {
69
+ honorObjectColor?: boolean;
70
+ surfaceDefinitions?: SurfaceDefinition[];
71
+ surfaceMappings?: SurfaceMappingRule[];
72
+ runtimeSurfaceOverrides?: string[];
73
+ requiredSurfaceBindingIds?: string[];
74
+ defaultSurfaceMaterial?: SurfaceMaterialConfig;
75
+ includeCoreSurfaceRoles?: boolean;
76
+ honorCoreSurfaceMaterials?: boolean;
77
+ honorSurfaceParentMaterials?: boolean;
49
78
  };
50
79
  //# sourceMappingURL=types.d.ts.map