@pascal-app/core 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/events/bus.d.ts +45 -6
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/events/bus.js +1 -1
  4. package/dist/hooks/scene-registry/scene-registry.d.ts +2 -0
  5. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  6. package/dist/hooks/scene-registry/scene-registry.js +2 -0
  7. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  8. package/dist/hooks/spatial-grid/spatial-grid-manager.js +164 -6
  9. package/dist/index.d.ts +8 -15
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +7 -14
  12. package/dist/lib/door-operation.d.ts +7 -0
  13. package/dist/lib/door-operation.d.ts.map +1 -0
  14. package/dist/lib/door-operation.js +25 -0
  15. package/dist/lib/polygon-geometry.d.ts.map +1 -1
  16. package/dist/lib/slab-polygon.d.ts +3 -0
  17. package/dist/lib/slab-polygon.d.ts.map +1 -0
  18. package/dist/lib/slab-polygon.js +58 -0
  19. package/dist/lib/space-detection.d.ts.map +1 -1
  20. package/dist/lib/space-detection.js +10 -8
  21. package/dist/material-library.d.ts +5 -3
  22. package/dist/material-library.d.ts.map +1 -1
  23. package/dist/material-library.js +28 -32
  24. package/dist/schema/asset-url.d.ts +34 -0
  25. package/dist/schema/asset-url.d.ts.map +1 -0
  26. package/dist/schema/asset-url.js +79 -0
  27. package/dist/schema/asset-url.test.d.ts +2 -0
  28. package/dist/schema/asset-url.test.d.ts.map +1 -0
  29. package/dist/schema/asset-url.test.js +134 -0
  30. package/dist/schema/index.d.ts +7 -5
  31. package/dist/schema/index.d.ts.map +1 -1
  32. package/dist/schema/index.js +5 -3
  33. package/dist/schema/material.d.ts +1 -0
  34. package/dist/schema/material.d.ts.map +1 -1
  35. package/dist/schema/material.js +13 -11
  36. package/dist/schema/nodes/column.d.ts +520 -0
  37. package/dist/schema/nodes/column.d.ts.map +1 -0
  38. package/dist/schema/nodes/column.js +385 -0
  39. package/dist/schema/nodes/door.d.ts +72 -0
  40. package/dist/schema/nodes/door.d.ts.map +1 -1
  41. package/dist/schema/nodes/door.js +39 -2
  42. package/dist/schema/nodes/fence.d.ts +1 -1
  43. package/dist/schema/nodes/fence.js +2 -2
  44. package/dist/schema/nodes/guide.d.ts +17 -0
  45. package/dist/schema/nodes/guide.d.ts.map +1 -1
  46. package/dist/schema/nodes/guide.js +11 -1
  47. package/dist/schema/nodes/item.d.ts +20 -0
  48. package/dist/schema/nodes/item.d.ts.map +1 -1
  49. package/dist/schema/nodes/item.js +30 -1
  50. package/dist/schema/nodes/level.d.ts +1 -1
  51. package/dist/schema/nodes/level.d.ts.map +1 -1
  52. package/dist/schema/nodes/level.js +6 -0
  53. package/dist/schema/nodes/roof-segment.d.ts +2 -2
  54. package/dist/schema/nodes/roof.d.ts +2 -2
  55. package/dist/schema/nodes/roof.d.ts.map +1 -1
  56. package/dist/schema/nodes/roof.js +5 -5
  57. package/dist/schema/nodes/scan.d.ts.map +1 -1
  58. package/dist/schema/nodes/scan.js +2 -1
  59. package/dist/schema/nodes/site.d.ts +7 -0
  60. package/dist/schema/nodes/site.d.ts.map +1 -1
  61. package/dist/schema/nodes/spawn.d.ts +24 -0
  62. package/dist/schema/nodes/spawn.d.ts.map +1 -0
  63. package/dist/schema/nodes/spawn.js +8 -0
  64. package/dist/schema/nodes/stair.d.ts +6 -6
  65. package/dist/schema/nodes/stair.d.ts.map +1 -1
  66. package/dist/schema/nodes/stair.js +9 -7
  67. package/dist/schema/nodes/window.d.ts +55 -0
  68. package/dist/schema/nodes/window.d.ts.map +1 -1
  69. package/dist/schema/nodes/window.js +29 -0
  70. package/dist/schema/types.d.ts +320 -5
  71. package/dist/schema/types.d.ts.map +1 -1
  72. package/dist/schema/types.js +4 -0
  73. package/dist/store/actions/node-actions.d.ts.map +1 -1
  74. package/dist/store/actions/node-actions.js +13 -10
  75. package/dist/store/use-interactive.d.ts +43 -0
  76. package/dist/store/use-interactive.d.ts.map +1 -1
  77. package/dist/store/use-interactive.js +66 -0
  78. package/dist/store/use-scene.d.ts.map +1 -1
  79. package/dist/store/use-scene.js +69 -5
  80. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  81. package/dist/systems/stair/stair-opening-sync.js +41 -7
  82. package/dist/systems/stair/stair-opening-sync.test.d.ts +2 -0
  83. package/dist/systems/stair/stair-opening-sync.test.d.ts.map +1 -0
  84. package/dist/systems/stair/stair-opening-sync.test.js +63 -0
  85. package/dist/systems/wall/wall-curve.d.ts +1 -1
  86. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  87. package/dist/systems/wall/wall-curve.js +1 -1
  88. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  89. package/dist/systems/wall/wall-mitering.js +2 -6
  90. package/package.json +34 -5
  91. package/dist/materials.d.ts +0 -10
  92. package/dist/materials.d.ts.map +0 -1
  93. package/dist/materials.js +0 -22
  94. package/dist/systems/ceiling/ceiling-system.d.ts +0 -8
  95. package/dist/systems/ceiling/ceiling-system.d.ts.map +0 -1
  96. package/dist/systems/ceiling/ceiling-system.js +0 -92
  97. package/dist/systems/door/door-system.d.ts +0 -2
  98. package/dist/systems/door/door-system.d.ts.map +0 -1
  99. package/dist/systems/door/door-system.js +0 -195
  100. package/dist/systems/fence/fence-system.d.ts +0 -2
  101. package/dist/systems/fence/fence-system.d.ts.map +0 -1
  102. package/dist/systems/fence/fence-system.js +0 -187
  103. package/dist/systems/item/item-system.d.ts +0 -2
  104. package/dist/systems/item/item-system.d.ts.map +0 -1
  105. package/dist/systems/item/item-system.js +0 -48
  106. package/dist/systems/roof/roof-system.d.ts +0 -16
  107. package/dist/systems/roof/roof-system.d.ts.map +0 -1
  108. package/dist/systems/roof/roof-system.js +0 -797
  109. package/dist/systems/slab/slab-system.d.ts +0 -8
  110. package/dist/systems/slab/slab-system.d.ts.map +0 -1
  111. package/dist/systems/slab/slab-system.js +0 -214
  112. package/dist/systems/stair/stair-system.d.ts +0 -2
  113. package/dist/systems/stair/stair-system.d.ts.map +0 -1
  114. package/dist/systems/stair/stair-system.js +0 -776
  115. package/dist/systems/wall/wall-system.d.ts +0 -12
  116. package/dist/systems/wall/wall-system.d.ts.map +0 -1
  117. package/dist/systems/wall/wall-system.js +0 -455
  118. package/dist/systems/window/window-system.d.ts +0 -2
  119. package/dist/systems/window/window-system.d.ts.map +0 -1
  120. package/dist/systems/window/window-system.js +0 -131
@@ -1,6 +1,6 @@
1
- import { getClampedWallCurveOffset, getWallCurveFrameAt, isCurvedWall, } from '../systems/wall/wall-curve';
2
- import { CeilingNode, SlabNode } from '../schema';
1
+ import { CeilingNode, SlabNode, } from '../schema';
3
2
  import { getSceneHistoryPauseDepth, pauseSceneHistory, resumeSceneHistory, } from '../store/history-control';
3
+ import { getClampedWallCurveOffset, getWallCurveFrameAt, isCurvedWall, } from '../systems/wall/wall-curve';
4
4
  import { simplifyClosedPolygon } from './polygon-geometry';
5
5
  const DEFAULT_AUTO_SLAB_ELEVATION = 0.05;
6
6
  const DEFAULT_AUTO_CEILING_HEIGHT = 2.5;
@@ -97,10 +97,10 @@ function polygonCentroid(points) {
97
97
  };
98
98
  }
99
99
  function bboxOf(points) {
100
- let minX = Infinity;
101
- let minY = Infinity;
102
- let maxX = -Infinity;
103
- let maxY = -Infinity;
100
+ let minX = Number.POSITIVE_INFINITY;
101
+ let minY = Number.POSITIVE_INFINITY;
102
+ let maxX = Number.NEGATIVE_INFINITY;
103
+ let maxY = Number.NEGATIVE_INFINITY;
104
104
  for (const point of points) {
105
105
  minX = Math.min(minX, point.x);
106
106
  minY = Math.min(minY, point.y);
@@ -266,7 +266,7 @@ function extractRoomPolygons(walls) {
266
266
  const signedArea = polygonArea(polygon);
267
267
  if (signedArea <= 0)
268
268
  continue;
269
- if (signedArea < 0.5 || signedArea > 10000)
269
+ if (signedArea < 0.5 || signedArea > 10_000)
270
270
  continue;
271
271
  const signature = polygonSignature(polygon);
272
272
  if (faces.some((face) => polygonSignature(face) === signature))
@@ -552,7 +552,9 @@ function syncAutoCeilingsForLevel(levelId, roomPolygons, existingCeilings, scene
552
552
  const polygon = updatesById.get(ceiling.id);
553
553
  if (!polygon)
554
554
  return [];
555
- return sameTuplePolygon(ceiling.polygon, polygon) ? [] : [{ id: ceiling.id, data: { polygon } }];
555
+ return sameTuplePolygon(ceiling.polygon, polygon)
556
+ ? []
557
+ : [{ id: ceiling.id, data: { polygon } }];
556
558
  });
557
559
  const plannedCeilingsForNaming = [...existingCeilings];
558
560
  const ceilingsToCreate = [];
@@ -1,15 +1,17 @@
1
- import { type MaterialPresetPayload, type MaterialTarget } from './schema/material';
1
+ import { type MaterialPresetPayload } from './schema/material';
2
2
  export type MaterialCatalogItem = {
3
3
  id: string;
4
4
  label: string;
5
+ category: MaterialCategory;
5
6
  description?: string;
6
- targets: MaterialTarget[];
7
7
  previewThumbnailUrl?: string;
8
8
  previewColor?: string;
9
9
  preset: MaterialPresetPayload;
10
10
  };
11
+ export declare const MATERIAL_CATEGORIES: readonly ["wood", "wallpaper", "parquet", "granite", "marble", "other"];
12
+ export type MaterialCategory = (typeof MATERIAL_CATEGORIES)[number];
11
13
  export declare const MATERIAL_CATALOG: MaterialCatalogItem[];
12
- export declare function getMaterialsForTarget(target: MaterialTarget): MaterialCatalogItem[];
14
+ export declare function getMaterialsForCategory(category: MaterialCategory): MaterialCatalogItem[];
13
15
  export declare function getCatalogMaterialById(id?: string): MaterialCatalogItem | undefined;
14
16
  export declare const LIBRARY_MATERIAL_REF_PREFIX = "library:";
15
17
  export declare function toLibraryMaterialRef(id: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"material-library.d.ts","sourceRoot":"","sources":["../src/material-library.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EAEpB,MAAM,mBAAmB,CAAA;AAE1B,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,qBAAqB,CAAA;CAC9B,CAAA;AAkCD,eAAO,MAAM,gBAAgB,EAAE,mBAAmB,EAuiBjD,CAAA;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,mBAAmB,EAAE,CAEnF;AAED,wBAAgB,sBAAsB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAGnF;AAED,eAAO,MAAM,2BAA2B,aAAa,CAAA;AAErD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,UAE9C;AAED,wBAAgB,2BAA2B,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,iBAItE;AAED,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,GAAG,IAAI,CAIhG"}
1
+ {"version":3,"file":"material-library.d.ts","sourceRoot":"","sources":["../src/material-library.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,mBAAmB,CAAA;AAE1B,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,qBAAqB,CAAA;CAC9B,CAAA;AA4BD,eAAO,MAAM,mBAAmB,yEAOtB,CAAA;AACV,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEnE,eAAO,MAAM,gBAAgB,EAAE,mBAAmB,EAiiBjD,CAAA;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,mBAAmB,EAAE,CAEzF;AAED,wBAAgB,sBAAsB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAGnF;AAED,eAAO,MAAM,2BAA2B,aAAa,CAAA;AAErD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,UAE9C;AAED,wBAAgB,2BAA2B,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,iBAItE;AAED,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,GAAG,IAAI,CAIhG"}
@@ -1,10 +1,6 @@
1
1
  import { MaterialTarget as MaterialTargetSchema, } from './schema/material';
2
- const WALL_TARGETS = [
3
- MaterialTargetSchema.enum.wall,
4
- ];
5
- const SLAB_TARGETS = [
6
- MaterialTargetSchema.enum.slab,
7
- ];
2
+ const WALL_TARGETS = [MaterialTargetSchema.enum.wall];
3
+ const SLAB_TARGETS = [MaterialTargetSchema.enum.slab];
8
4
  const WALL_AND_SLAB_TARGETS = [
9
5
  MaterialTargetSchema.enum.wall,
10
6
  MaterialTargetSchema.enum.slab,
@@ -21,15 +17,21 @@ const ROOF_TARGETS = [
21
17
  MaterialTargetSchema.enum.roof,
22
18
  MaterialTargetSchema.enum['roof-segment'],
23
19
  ];
24
- const CEILING_TARGETS = [
25
- MaterialTargetSchema.enum.ceiling,
20
+ const CEILING_TARGETS = [MaterialTargetSchema.enum.ceiling];
21
+ export const MATERIAL_CATEGORIES = [
22
+ 'wood',
23
+ 'wallpaper',
24
+ 'parquet',
25
+ 'granite',
26
+ 'marble',
27
+ 'other',
26
28
  ];
27
29
  export const MATERIAL_CATALOG = [
28
30
  {
29
31
  id: 'wall-wood1',
30
32
  label: 'Wood',
33
+ category: 'wood',
31
34
  description: 'Warm wood finish',
32
- targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS, ...ROOF_TARGETS],
33
35
  previewThumbnailUrl: '/material/wood1/wood1_thumbnail.webp',
34
36
  preset: {
35
37
  maps: {
@@ -63,8 +65,8 @@ export const MATERIAL_CATALOG = [
63
65
  {
64
66
  id: 'wall-wood2',
65
67
  label: 'Wood',
68
+ category: 'wood',
66
69
  description: 'Textured wood finish',
67
- targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS, ...ROOF_TARGETS],
68
70
  previewThumbnailUrl: '/material/wood2/wood2_thumbnail.webp',
69
71
  preset: {
70
72
  maps: {
@@ -99,8 +101,8 @@ export const MATERIAL_CATALOG = [
99
101
  {
100
102
  id: 'wall-wood3',
101
103
  label: 'Wood',
104
+ category: 'wood',
102
105
  description: 'Knotted timber finish',
103
- targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS, ...ROOF_TARGETS],
104
106
  previewThumbnailUrl: '/material/wood3/wood3_thumbnail.webp',
105
107
  preset: {
106
108
  maps: {
@@ -133,8 +135,8 @@ export const MATERIAL_CATALOG = [
133
135
  {
134
136
  id: 'wall-wood4',
135
137
  label: 'Wood',
138
+ category: 'wood',
136
139
  description: 'Oak stretcher finish',
137
- targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
138
140
  previewThumbnailUrl: '/material/wood4/wood4_thumbnail.webp',
139
141
  preset: {
140
142
  maps: {
@@ -167,8 +169,8 @@ export const MATERIAL_CATALOG = [
167
169
  {
168
170
  id: 'wall-wood5',
169
171
  label: 'Wood',
172
+ category: 'wood',
170
173
  description: 'Rich grain wood finish',
171
- targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
172
174
  previewThumbnailUrl: '/material/wood5/wood5_thumnail.webp',
173
175
  preset: {
174
176
  maps: {
@@ -203,8 +205,8 @@ export const MATERIAL_CATALOG = [
203
205
  {
204
206
  id: 'wall-granite1',
205
207
  label: 'Granite',
208
+ category: 'granite',
206
209
  description: 'Polished granite finish',
207
- targets: SLAB_TARGETS,
208
210
  previewThumbnailUrl: '/material/granite1/granite_thumbnail.webp',
209
211
  preset: {
210
212
  maps: {
@@ -237,8 +239,8 @@ export const MATERIAL_CATALOG = [
237
239
  {
238
240
  id: 'wall-marble1',
239
241
  label: 'Marble',
242
+ category: 'marble',
240
243
  description: 'Smooth marble finish',
241
- targets: [...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
242
244
  previewThumbnailUrl: '/material/marble1/marble1_thumbnail.webp',
243
245
  preset: {
244
246
  maps: {
@@ -271,8 +273,8 @@ export const MATERIAL_CATALOG = [
271
273
  {
272
274
  id: 'wall-marble2',
273
275
  label: 'Marble',
276
+ category: 'marble',
274
277
  description: 'Soft marble finish',
275
- targets: [...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
276
278
  previewThumbnailUrl: '/material/marble2/marble2_thumbnail.webp',
277
279
  preset: {
278
280
  maps: {
@@ -305,8 +307,8 @@ export const MATERIAL_CATALOG = [
305
307
  {
306
308
  id: 'wall-parquet1',
307
309
  label: 'Parquet',
310
+ category: 'parquet',
308
311
  description: 'Parquet wood finish',
309
- targets: SLAB_TARGETS,
310
312
  previewThumbnailUrl: '/material/parquet1/parquet_thumnail.webp',
311
313
  preset: {
312
314
  maps: {
@@ -339,8 +341,8 @@ export const MATERIAL_CATALOG = [
339
341
  {
340
342
  id: 'wall-parquet2',
341
343
  label: 'Parquet',
344
+ category: 'parquet',
342
345
  description: 'Soft parquet finish',
343
- targets: SLAB_TARGETS,
344
346
  previewThumbnailUrl: '/material/parquet2/parquet2_thumbnail.webp',
345
347
  preset: {
346
348
  maps: {
@@ -373,8 +375,8 @@ export const MATERIAL_CATALOG = [
373
375
  {
374
376
  id: 'wall-wallpaper1',
375
377
  label: 'Wallpaper',
378
+ category: 'wallpaper',
376
379
  description: 'Soft wallpaper finish',
377
- targets: WALL_TARGETS,
378
380
  previewThumbnailUrl: '/material/wallpaper1/wallpaper1_thumbnail.webp',
379
381
  preset: {
380
382
  maps: {
@@ -408,8 +410,8 @@ export const MATERIAL_CATALOG = [
408
410
  {
409
411
  id: 'wall-wallpaper2',
410
412
  label: 'Wallpaper',
413
+ category: 'wallpaper',
411
414
  description: 'Decorative wallpaper finish',
412
- targets: WALL_TARGETS,
413
415
  previewThumbnailUrl: '/material/wallpaper2/wallpaper2_thumnail.webp',
414
416
  preset: {
415
417
  maps: {
@@ -442,8 +444,8 @@ export const MATERIAL_CATALOG = [
442
444
  {
443
445
  id: 'wall-wallpaper3',
444
446
  label: 'Wallpaper',
447
+ category: 'wallpaper',
445
448
  description: 'Patterned wallpaper finish',
446
- targets: WALL_TARGETS,
447
449
  previewThumbnailUrl: '/material/wallpaper3/wallpaper3_thumbnail.webp',
448
450
  preset: {
449
451
  maps: {
@@ -476,14 +478,8 @@ export const MATERIAL_CATALOG = [
476
478
  {
477
479
  id: 'preset-white',
478
480
  label: 'White',
481
+ category: 'other',
479
482
  description: 'Clean painted finish',
480
- targets: [
481
- ...WALL_TARGETS,
482
- ...SLAB_TARGETS,
483
- ...ROOF_TARGETS,
484
- ...STAIR_AND_FENCE_TARGETS,
485
- ...CEILING_TARGETS,
486
- ],
487
483
  previewColor: '#ffffff',
488
484
  preset: {
489
485
  maps: {},
@@ -514,8 +510,8 @@ export const MATERIAL_CATALOG = [
514
510
  {
515
511
  id: 'preset-metal',
516
512
  label: 'Metal',
513
+ category: 'other',
517
514
  description: 'Brushed metal finish',
518
- targets: [...WALL_TARGETS, ...SLAB_TARGETS],
519
515
  previewColor: '#c0c0c0',
520
516
  preset: {
521
517
  maps: {},
@@ -546,8 +542,8 @@ export const MATERIAL_CATALOG = [
546
542
  {
547
543
  id: 'preset-glass',
548
544
  label: 'Glass',
545
+ category: 'other',
549
546
  description: 'Light glass finish',
550
- targets: [...WALL_TARGETS, ...SLAB_TARGETS],
551
547
  previewColor: '#87ceeb',
552
548
  preset: {
553
549
  maps: {},
@@ -576,8 +572,8 @@ export const MATERIAL_CATALOG = [
576
572
  },
577
573
  },
578
574
  ];
579
- export function getMaterialsForTarget(target) {
580
- return MATERIAL_CATALOG.filter((item) => item.targets.includes(target));
575
+ export function getMaterialsForCategory(category) {
576
+ return MATERIAL_CATALOG.filter((item) => item.category === category);
581
577
  }
582
578
  export function getCatalogMaterialById(id) {
583
579
  if (!id)
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Scheme allowlist for asset-like URLs embedded in scene graphs.
4
+ *
5
+ * Phase 3 security audit: `scan.url`, `guide.url`, `material.texture.url`, and
6
+ * `item.asset.src` were previously bare `z.string()`. That meant an
7
+ * attacker-crafted scene loaded in the editor could beacon to arbitrary URLs
8
+ * (e.g. `javascript:`, `file:///etc/passwd`, `http://169.254.169.254/...`).
9
+ *
10
+ * This validator rejects URLs that don't match the scheme allowlist below.
11
+ */
12
+ declare const ALLOWED_SCHEMES: readonly ["asset:", "blob:", "https:", "data:image/"];
13
+ /**
14
+ * Optional environment variable that narrows which `https:` origins are
15
+ * accepted. Set to a comma-separated list (e.g. `https://cdn.pascal.app`).
16
+ * When unset, any `https:` origin is permitted.
17
+ */
18
+ export declare const ALLOWED_ORIGINS_ENV = "PASCAL_ALLOWED_ASSET_ORIGINS";
19
+ /**
20
+ * Zod validator for asset-style URL fields. Accepts:
21
+ * - `asset://…` internal handles
22
+ * - `blob:…` in-memory references
23
+ * - `data:image/…` inline images (not `data:text/html` or other types)
24
+ * - `/…` app-relative paths
25
+ * - `https://…` public URLs (optionally narrowed to an env allowlist)
26
+ * - `http://localhost[:port]/…` or `http://127.0.0.1/…` for local dev
27
+ *
28
+ * Rejects every other scheme, including `javascript:`, `file:`, `ftp:`,
29
+ * and `data:text/html`, as well as empty strings and non-URL garbage.
30
+ */
31
+ export declare const AssetUrl: z.ZodString;
32
+ export type AssetUrl = z.infer<typeof AssetUrl>;
33
+ export { ALLOWED_SCHEMES };
34
+ //# sourceMappingURL=asset-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-url.d.ts","sourceRoot":"","sources":["../../src/schema/asset-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;GASG;AACH,QAAA,MAAM,eAAe,uDAAwD,CAAA;AAE7E;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,iCAAiC,CAAA;AAuCjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,aAGnB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAA;AAG/C,OAAO,EAAE,eAAe,EAAE,CAAA"}
@@ -0,0 +1,79 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Scheme allowlist for asset-like URLs embedded in scene graphs.
4
+ *
5
+ * Phase 3 security audit: `scan.url`, `guide.url`, `material.texture.url`, and
6
+ * `item.asset.src` were previously bare `z.string()`. That meant an
7
+ * attacker-crafted scene loaded in the editor could beacon to arbitrary URLs
8
+ * (e.g. `javascript:`, `file:///etc/passwd`, `http://169.254.169.254/...`).
9
+ *
10
+ * This validator rejects URLs that don't match the scheme allowlist below.
11
+ */
12
+ const ALLOWED_SCHEMES = ['asset:', 'blob:', 'https:', 'data:image/'];
13
+ /**
14
+ * Optional environment variable that narrows which `https:` origins are
15
+ * accepted. Set to a comma-separated list (e.g. `https://cdn.pascal.app`).
16
+ * When unset, any `https:` origin is permitted.
17
+ */
18
+ export const ALLOWED_ORIGINS_ENV = 'PASCAL_ALLOWED_ASSET_ORIGINS';
19
+ // Narrow access to the environment variable without requiring @types/node in
20
+ // this package. The core package ships to both browser and Node contexts.
21
+ function readAllowedOrigins() {
22
+ const g = globalThis;
23
+ const value = g.process?.env?.[ALLOWED_ORIGINS_ENV];
24
+ if (!value)
25
+ return undefined;
26
+ const list = value
27
+ .split(',')
28
+ .map((s) => s.trim())
29
+ .filter((s) => s.length > 0);
30
+ return list.length > 0 ? list : undefined;
31
+ }
32
+ function isAllowedAssetUrl(url) {
33
+ if (typeof url !== 'string' || url.length === 0)
34
+ return false;
35
+ if (url.startsWith('asset://'))
36
+ return true; // internal handle
37
+ if (url.startsWith('blob:'))
38
+ return true; // in-memory reference
39
+ if (url.startsWith('data:image/'))
40
+ return true; // inline image only (never data:text/html)
41
+ if (url.startsWith('/'))
42
+ return true; // app-relative path
43
+ try {
44
+ const parsed = new URL(url);
45
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')
46
+ return false;
47
+ // http is only permitted for localhost development
48
+ if (parsed.protocol === 'http:' && !['localhost', '127.0.0.1'].includes(parsed.hostname)) {
49
+ return false;
50
+ }
51
+ // optional env-driven origin allowlist (only enforced for https URLs)
52
+ if (parsed.protocol === 'https:') {
53
+ const allowlist = readAllowedOrigins();
54
+ if (allowlist)
55
+ return allowlist.includes(parsed.origin);
56
+ }
57
+ return true;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }
63
+ /**
64
+ * Zod validator for asset-style URL fields. Accepts:
65
+ * - `asset://…` internal handles
66
+ * - `blob:…` in-memory references
67
+ * - `data:image/…` inline images (not `data:text/html` or other types)
68
+ * - `/…` app-relative paths
69
+ * - `https://…` public URLs (optionally narrowed to an env allowlist)
70
+ * - `http://localhost[:port]/…` or `http://127.0.0.1/…` for local dev
71
+ *
72
+ * Rejects every other scheme, including `javascript:`, `file:`, `ftp:`,
73
+ * and `data:text/html`, as well as empty strings and non-URL garbage.
74
+ */
75
+ export const AssetUrl = z.string().refine(isAllowedAssetUrl, {
76
+ message: 'URL must be asset://, blob:, data:image/, /path, or https://. http://localhost allowed for dev.',
77
+ });
78
+ // re-export the scheme allowlist for documentation / downstream validators
79
+ export { ALLOWED_SCHEMES };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=asset-url.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-url.test.d.ts","sourceRoot":"","sources":["../../src/schema/asset-url.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,134 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
2
+ import { ALLOWED_ORIGINS_ENV, AssetUrl } from './asset-url';
3
+ function isValid(url) {
4
+ return AssetUrl.safeParse(url).success;
5
+ }
6
+ describe('AssetUrl', () => {
7
+ describe('allowed URLs', () => {
8
+ const cases = [
9
+ ['asset://abc', 'internal asset handle'],
10
+ ['asset://catalog/items/chair-1', 'nested asset handle'],
11
+ ['blob:http://example.com/uuid-1234', 'blob URL with http inner'],
12
+ ['blob:https://example.com/uuid-5678', 'blob URL with https inner'],
13
+ ['https://cdn.example.com/a.glb', 'https CDN URL'],
14
+ ['https://cdn.example.com/models/chair.glb?v=2', 'https URL with query string'],
15
+ ['http://localhost:3000/x', 'http localhost with port'],
16
+ ['http://localhost/x', 'http localhost without port'],
17
+ ['http://127.0.0.1:8080/texture.png', 'http 127.0.0.1 loopback'],
18
+ ['/public/a.glb', 'app-relative path'],
19
+ ['/material/wood1/albedoMap_basecolor.jpg', 'relative path deep'],
20
+ ['data:image/png;base64,AAA', 'inline PNG data URL'],
21
+ ['data:image/jpeg;base64,/9j/', 'inline JPEG data URL'],
22
+ ['data:image/webp;base64,UklGR', 'inline WebP data URL'],
23
+ ['data:image/svg+xml,%3Csvg%3E', 'inline SVG data URL'],
24
+ ];
25
+ for (const [url, label] of cases) {
26
+ test(`accepts ${label}: ${url}`, () => {
27
+ expect(isValid(url)).toBe(true);
28
+ });
29
+ }
30
+ });
31
+ describe('rejected URLs', () => {
32
+ const cases = [
33
+ ['javascript:alert(1)', 'javascript scheme'],
34
+ ['JAVASCRIPT:alert(1)', 'javascript scheme uppercase'],
35
+ ['file:///etc/passwd', 'file scheme'],
36
+ ['file://C:/Windows/System32/config', 'file scheme Windows'],
37
+ ['http://evil.com/', 'non-loopback http'],
38
+ ['http://example.com:3000/x', 'http on non-loopback host'],
39
+ ['http://169.254.169.254/latest/meta-data/', 'http on link-local (cloud metadata)'],
40
+ ['data:text/html,<script>alert(1)</script>', 'data text/html'],
41
+ ['data:application/javascript,alert(1)', 'data application/javascript'],
42
+ ['data:text/plain,hi', 'data text/plain'],
43
+ ['ftp://a.b.com', 'ftp scheme'],
44
+ ['ws://example.com/', 'websocket scheme'],
45
+ ['vbscript:msgbox', 'vbscript scheme'],
46
+ ['', 'empty string'],
47
+ ['not a url at all', 'non-url string'],
48
+ ['://missing-scheme', 'malformed'],
49
+ ];
50
+ for (const [url, label] of cases) {
51
+ test(`rejects ${label}: ${url}`, () => {
52
+ expect(isValid(url)).toBe(false);
53
+ });
54
+ }
55
+ });
56
+ describe(`env allowlist via ${ALLOWED_ORIGINS_ENV}`, () => {
57
+ const g = globalThis;
58
+ const original = g.process?.env?.[ALLOWED_ORIGINS_ENV];
59
+ beforeEach(() => {
60
+ if (g.process?.env)
61
+ delete g.process.env[ALLOWED_ORIGINS_ENV];
62
+ });
63
+ afterEach(() => {
64
+ if (!g.process?.env)
65
+ return;
66
+ if (original === undefined) {
67
+ delete g.process.env[ALLOWED_ORIGINS_ENV];
68
+ }
69
+ else {
70
+ g.process.env[ALLOWED_ORIGINS_ENV] = original;
71
+ }
72
+ });
73
+ test('single origin allowlist accepts matching https URL', () => {
74
+ if (!g.process?.env)
75
+ return; // browser-only runtime
76
+ g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
77
+ expect(isValid('https://cdn.pascal.app/a.glb')).toBe(true);
78
+ expect(isValid('https://cdn.pascal.app/deep/path?q=1')).toBe(true);
79
+ });
80
+ test('single origin allowlist rejects non-matching https URL', () => {
81
+ if (!g.process?.env)
82
+ return;
83
+ g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
84
+ expect(isValid('https://cdn.other.com/a.glb')).toBe(false);
85
+ expect(isValid('https://attacker.example.com/x')).toBe(false);
86
+ });
87
+ test('multi-origin allowlist accepts any listed origin', () => {
88
+ if (!g.process?.env)
89
+ return;
90
+ g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app, https://assets.pascal.app';
91
+ expect(isValid('https://cdn.pascal.app/a.glb')).toBe(true);
92
+ expect(isValid('https://assets.pascal.app/tex.webp')).toBe(true);
93
+ expect(isValid('https://third.example.com/x')).toBe(false);
94
+ });
95
+ test('allowlist ignores trailing / in URL path (origin match only)', () => {
96
+ if (!g.process?.env)
97
+ return;
98
+ g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
99
+ expect(isValid('https://cdn.pascal.app/')).toBe(true);
100
+ expect(isValid('https://cdn.pascal.app')).toBe(true);
101
+ });
102
+ test('empty allowlist behaves like unset', () => {
103
+ if (!g.process?.env)
104
+ return;
105
+ g.process.env[ALLOWED_ORIGINS_ENV] = '';
106
+ expect(isValid('https://cdn.other.com/a.glb')).toBe(true);
107
+ });
108
+ test('allowlist does not restrict non-https schemes', () => {
109
+ if (!g.process?.env)
110
+ return;
111
+ g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
112
+ // these should still pass because they match earlier scheme-based branches
113
+ expect(isValid('asset://x')).toBe(true);
114
+ expect(isValid('blob:https://example.com/abc')).toBe(true);
115
+ expect(isValid('data:image/png;base64,AAA')).toBe(true);
116
+ expect(isValid('/public/a.glb')).toBe(true);
117
+ expect(isValid('http://localhost:3000/x')).toBe(true);
118
+ });
119
+ test('allowlist rejects subdomain spoofing', () => {
120
+ if (!g.process?.env)
121
+ return;
122
+ g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
123
+ expect(isValid('https://cdn.pascal.app.evil.com/x')).toBe(false);
124
+ expect(isValid('https://evil.com/cdn.pascal.app')).toBe(false);
125
+ });
126
+ test('allowlist respects ports', () => {
127
+ if (!g.process?.env)
128
+ return;
129
+ g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app:8443';
130
+ expect(isValid('https://cdn.pascal.app:8443/x')).toBe(true);
131
+ expect(isValid('https://cdn.pascal.app/x')).toBe(false);
132
+ });
133
+ });
134
+ });
@@ -5,25 +5,27 @@ export type { MaterialMapProperties, MaterialMaps, MaterialPresetPayload, Materi
5
5
  export { DEFAULT_MATERIALS, MaterialMapPropertiesSchema, MaterialMapsSchema, MaterialPreset, MaterialPresetPayloadSchema, MaterialProperties, MaterialSchema, MaterialTarget, resolveMaterial, TextureWrapMode, } from './material';
6
6
  export { BuildingNode } from './nodes/building';
7
7
  export { CeilingNode } from './nodes/ceiling';
8
+ export { COLUMN_PRESETS, ColumnBaseStyle, ColumnCapitalStyle, ColumnCarvingPlacement, ColumnCrossSection, ColumnNode, ColumnPanelShape, type ColumnPresetId, ColumnRingPlacement, ColumnShaftDetail, ColumnShaftProfile, ColumnStyle, } from './nodes/column';
8
9
  export { DoorNode, DoorSegment } from './nodes/door';
9
10
  export { FenceBaseStyle, FenceNode, FenceStyle } from './nodes/fence';
10
- export { GuideNode } from './nodes/guide';
11
+ export { GuideNode, GuideScaleReference } from './nodes/guide';
11
12
  export type { AnimationEffect, Asset, AssetInput, Control, Effect, Interactive, LightEffect, SliderControl, TemperatureControl, ToggleControl, } from './nodes/item';
12
- export { getScaledDimensions, ItemNode } from './nodes/item';
13
+ export { getScaledDimensions, ItemNode, isLowProfileItemSurface, LOW_PROFILE_ITEM_SURFACE_MAX_HEIGHT, } from './nodes/item';
13
14
  export { LevelNode } from './nodes/level';
14
- export { getEffectiveRoofSurfaceMaterial, RoofNode } from './nodes/roof';
15
15
  export type { RoofSurfaceMaterialRole, RoofSurfaceMaterialSpec } from './nodes/roof';
16
+ export { getEffectiveRoofSurfaceMaterial, RoofNode } from './nodes/roof';
16
17
  export { RoofSegmentNode, RoofType } from './nodes/roof-segment';
17
18
  export { ScanNode } from './nodes/scan';
18
19
  export { SiteNode } from './nodes/site';
19
20
  export { SlabNode } from './nodes/slab';
20
- export { getEffectiveStairSurfaceMaterial, StairNode, StairRailingMode, StairSlabOpeningMode, StairTopLandingMode, StairType, } from './nodes/stair';
21
+ export { SpawnNode } from './nodes/spawn';
21
22
  export type { StairSurfaceMaterialRole, StairSurfaceMaterialSpec } from './nodes/stair';
23
+ export { getEffectiveStairSurfaceMaterial, StairNode, StairRailingMode, StairSlabOpeningMode, StairTopLandingMode, StairType, } from './nodes/stair';
22
24
  export { AttachmentSide, StairSegmentNode, StairSegmentType } from './nodes/stair-segment';
23
25
  export { SurfaceHoleMetadata } from './nodes/surface-hole-metadata';
24
26
  export type { WallSurfaceMaterialSpec, WallSurfaceSide } from './nodes/wall';
25
27
  export { getEffectiveWallSurfaceMaterial, getWallSurfaceMaterialSignature, WallNode, } from './nodes/wall';
26
- export { WindowNode } from './nodes/window';
28
+ export { WindowNode, WindowType } from './nodes/window';
27
29
  export { ZoneNode } from './nodes/zone';
28
30
  export type { AnyNodeId, AnyNodeType } from './types';
29
31
  export { AnyNode } from './types';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACxF,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,qBAAqB,EACrB,cAAc,IAAI,mBAAmB,EACrC,eAAe,IAAI,oBAAoB,GACxC,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,kBAAkB,EAClB,cAAc,EACd,2BAA2B,EAC3B,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,YAAY,EACV,eAAe,EACf,KAAK,EACL,UAAU,EACV,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,aAAa,GACd,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,+BAA+B,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACxE,YAAY,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACpF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EACL,gCAAgC,EAChC,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,SAAS,GACV,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AACvF,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC1F,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AACnE,YAAY,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,EAC/B,QAAQ,GACT,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"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"}
@@ -8,10 +8,11 @@ export { generateCollectionId } from './collections';
8
8
  export { DEFAULT_MATERIALS, MaterialMapPropertiesSchema, MaterialMapsSchema, MaterialPreset, MaterialPresetPayloadSchema, MaterialProperties, MaterialSchema, MaterialTarget, resolveMaterial, TextureWrapMode, } from './material';
9
9
  export { BuildingNode } from './nodes/building';
10
10
  export { CeilingNode } from './nodes/ceiling';
11
+ export { COLUMN_PRESETS, ColumnBaseStyle, ColumnCapitalStyle, ColumnCarvingPlacement, ColumnCrossSection, ColumnNode, ColumnPanelShape, ColumnRingPlacement, ColumnShaftDetail, ColumnShaftProfile, ColumnStyle, } from './nodes/column';
11
12
  export { DoorNode, DoorSegment } from './nodes/door';
12
13
  export { FenceBaseStyle, FenceNode, FenceStyle } from './nodes/fence';
13
- export { GuideNode } from './nodes/guide';
14
- export { getScaledDimensions, ItemNode } from './nodes/item';
14
+ export { GuideNode, GuideScaleReference } from './nodes/guide';
15
+ export { getScaledDimensions, ItemNode, isLowProfileItemSurface, LOW_PROFILE_ITEM_SURFACE_MAX_HEIGHT, } from './nodes/item';
15
16
  export { LevelNode } from './nodes/level';
16
17
  export { getEffectiveRoofSurfaceMaterial, RoofNode } from './nodes/roof';
17
18
  export { RoofSegmentNode, RoofType } from './nodes/roof-segment';
@@ -19,11 +20,12 @@ export { ScanNode } from './nodes/scan';
19
20
  // Nodes
20
21
  export { SiteNode } from './nodes/site';
21
22
  export { SlabNode } from './nodes/slab';
23
+ export { SpawnNode } from './nodes/spawn';
22
24
  export { getEffectiveStairSurfaceMaterial, StairNode, StairRailingMode, StairSlabOpeningMode, StairTopLandingMode, StairType, } from './nodes/stair';
23
25
  export { AttachmentSide, StairSegmentNode, StairSegmentType } from './nodes/stair-segment';
24
26
  export { SurfaceHoleMetadata } from './nodes/surface-hole-metadata';
25
27
  export { getEffectiveWallSurfaceMaterial, getWallSurfaceMaterialSignature, WallNode, } from './nodes/wall';
26
- export { WindowNode } from './nodes/window';
28
+ export { WindowNode, WindowType } from './nodes/window';
27
29
  export { ZoneNode } from './nodes/zone';
28
30
  // Union types
29
31
  export { AnyNode } from './types';
@@ -65,6 +65,7 @@ export declare const MaterialTarget: z.ZodEnum<{
65
65
  stair: "stair";
66
66
  "stair-segment": "stair-segment";
67
67
  fence: "fence";
68
+ column: "column";
68
69
  slab: "slab";
69
70
  ceiling: "ceiling";
70
71
  door: "door";
@@ -1 +1 @@
1
- {"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../../src/schema/material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,cAAc;;;;;;;;;;;EAWzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAO7B,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAEnE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAWzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,cAAc;;;;;;;;;;;EAWzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,eAAe;;;;EAAsD,CAAA;AAClF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAE7D,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAW7B,CAAA;AACF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE7D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqBtC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE/E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGtC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE/E,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAiFxE,CAAA;AAED,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,kBAAkB,CAiB7E"}
1
+ {"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../../src/schema/material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,cAAc;;;;;;;;;;;EAWzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAO7B,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAEnE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAWzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,cAAc;;;;;;;;;;;;EAYzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,eAAe;;;;EAAsD,CAAA;AAClF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAE7D,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAW7B,CAAA;AACF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE7D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqBtC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE/E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGtC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE/E,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAiFxE,CAAA;AAED,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,kBAAkB,CAiB7E"}