@ifc-lite/viewer 1.17.4 → 1.18.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 (196) hide show
  1. package/.turbo/turbo-build.log +20 -17
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/CHANGELOG.md +630 -0
  4. package/DESKTOP_CONTRACT_VERSION +1 -1
  5. package/dist/assets/{basketViewActivator-BmnNtVfZ.js → basketViewActivator-Cm1QEk_R.js} +1 -1
  6. package/dist/assets/drawing-2d-DoxKMqbO.js +257 -0
  7. package/dist/assets/{exporters-ChAtBmlj.js → exporters-B_OBqIyD.js} +3479 -2845
  8. package/dist/assets/{geometry.worker-BQ0rzNo-.js → geometry.worker-xHHy-9DV.js} +1 -1
  9. package/dist/assets/ids-DQ5jY0E8.js +1 -0
  10. package/dist/assets/ifc-lite_bg-ADjKXSms.wasm +0 -0
  11. package/dist/assets/{index-Co8E2-FE.js → index-BKq-M3Mk.js} +55873 -40593
  12. package/dist/assets/index-COnQRuqY.css +1 -0
  13. package/dist/assets/{native-bridge-BRvbckFQ.js → native-bridge-SHXiQwFW.js} +104 -104
  14. package/dist/assets/sandbox-jez21HtV.js +9627 -0
  15. package/dist/assets/{server-client-BV8zHZ7Y.js → server-client-ncOQVNso.js} +1 -1
  16. package/dist/assets/{wasm-bridge-g01g7T9b.js → wasm-bridge-DyfBSB8z.js} +1 -1
  17. package/dist/index.html +8 -7
  18. package/index.html +1 -0
  19. package/package.json +13 -13
  20. package/src/App.tsx +16 -2
  21. package/src/apache-arrow.d.ts +30 -0
  22. package/src/components/viewer/AddElementPanel.tsx +758 -0
  23. package/src/components/viewer/BulkPropertyEditor.tsx +7 -0
  24. package/src/components/viewer/CesiumOverlay.tsx +62 -19
  25. package/src/components/viewer/ChatPanel.tsx +259 -93
  26. package/src/components/viewer/CommandPalette.tsx +56 -7
  27. package/src/components/viewer/EntityContextMenu.tsx +168 -4
  28. package/src/components/viewer/ExportChangesButton.tsx +25 -5
  29. package/src/components/viewer/ExportDialog.tsx +19 -1
  30. package/src/components/viewer/MainToolbar.tsx +73 -13
  31. package/src/components/viewer/PropertiesPanel.tsx +237 -23
  32. package/src/components/viewer/SearchInline.tsx +669 -0
  33. package/src/components/viewer/SearchModal.filter.builder.tsx +766 -0
  34. package/src/components/viewer/SearchModal.filter.tsx +514 -0
  35. package/src/components/viewer/SearchModal.text.tsx +388 -0
  36. package/src/components/viewer/SearchModal.tsx +235 -0
  37. package/src/components/viewer/SettingsPage.tsx +252 -101
  38. package/src/components/viewer/ThemeSwitch.tsx +63 -7
  39. package/src/components/viewer/ToolOverlays.tsx +5 -0
  40. package/src/components/viewer/ViewerLayout.tsx +25 -4
  41. package/src/components/viewer/Viewport.tsx +25 -3
  42. package/src/components/viewer/ViewportContainer.tsx +51 -64
  43. package/src/components/viewer/ViewportOverlays.tsx +5 -2
  44. package/src/components/viewer/annotations/AnnotationDropInput.tsx +203 -0
  45. package/src/components/viewer/annotations/AnnotationLayer.tsx +287 -0
  46. package/src/components/viewer/annotations/AnnotationPin.tsx +90 -0
  47. package/src/components/viewer/annotations/AnnotationPopover.tsx +296 -0
  48. package/src/components/viewer/bcf/BCFTopicDetail.tsx +4 -4
  49. package/src/components/viewer/chat/ModelSelector.tsx +90 -54
  50. package/src/components/viewer/lists/ListPanel.tsx +14 -21
  51. package/src/components/viewer/properties/GeoreferencingPanel.tsx +113 -51
  52. package/src/components/viewer/properties/LocationMap.tsx +9 -7
  53. package/src/components/viewer/properties/ModelMetadataPanel.tsx +1 -1
  54. package/src/components/viewer/properties/RawStepCard.tsx +332 -0
  55. package/src/components/viewer/properties/RawStepRow.tsx +261 -0
  56. package/src/components/viewer/properties/ScheduleCard.tsx +224 -0
  57. package/src/components/viewer/properties/TaskEditCard.tsx +510 -0
  58. package/src/components/viewer/properties/raw-step-format.ts +193 -0
  59. package/src/components/viewer/schedule/AnimationSettingsPopover.tsx +542 -0
  60. package/src/components/viewer/schedule/GanttDependencyArrows.tsx +89 -0
  61. package/src/components/viewer/schedule/GanttDragTooltip.tsx +48 -0
  62. package/src/components/viewer/schedule/GanttEmptyState.tsx +97 -0
  63. package/src/components/viewer/schedule/GanttPanel.tsx +295 -0
  64. package/src/components/viewer/schedule/GanttTaskBar.tsx +199 -0
  65. package/src/components/viewer/schedule/GanttTaskTree.tsx +250 -0
  66. package/src/components/viewer/schedule/GanttTimeline.tsx +305 -0
  67. package/src/components/viewer/schedule/GanttToolbar.tsx +406 -0
  68. package/src/components/viewer/schedule/GenerateAdvancedPanel.tsx +147 -0
  69. package/src/components/viewer/schedule/GenerateScheduleDialog.tsx +392 -0
  70. package/src/components/viewer/schedule/HeightStrategyPanel.tsx +120 -0
  71. package/src/components/viewer/schedule/generate-schedule.test.ts +439 -0
  72. package/src/components/viewer/schedule/generate-schedule.ts +648 -0
  73. package/src/components/viewer/schedule/schedule-animator.test.ts +452 -0
  74. package/src/components/viewer/schedule/schedule-animator.ts +488 -0
  75. package/src/components/viewer/schedule/schedule-selection.test.ts +148 -0
  76. package/src/components/viewer/schedule/schedule-selection.ts +163 -0
  77. package/src/components/viewer/schedule/schedule-utils.ts +223 -0
  78. package/src/components/viewer/schedule/useConstructionSequence.ts +156 -0
  79. package/src/components/viewer/schedule/useGanttBarDrag.test.ts +90 -0
  80. package/src/components/viewer/schedule/useGanttBarDrag.ts +305 -0
  81. package/src/components/viewer/schedule/useGanttSelection3DHighlight.ts +152 -0
  82. package/src/components/viewer/schedule/useOverlayCompositor.ts +108 -0
  83. package/src/components/viewer/selectionHandlers.ts +446 -0
  84. package/src/components/viewer/tools/AddElementOverlay.tsx +540 -0
  85. package/src/components/viewer/tools/SectionCapControls.tsx +237 -0
  86. package/src/components/viewer/tools/SectionPanel.tsx +39 -18
  87. package/src/components/viewer/useAnimationLoop.ts +9 -1
  88. package/src/components/viewer/useDuplicateShortcut.ts +77 -0
  89. package/src/components/viewer/useMouseControls.ts +9 -1
  90. package/src/components/viewer/useRenderUpdates.ts +1 -1
  91. package/src/hooks/ids/idsDataAccessor.ts +60 -24
  92. package/src/hooks/ingest/viewerModelIngest.ts +7 -2
  93. package/src/hooks/useIfcFederation.ts +326 -71
  94. package/src/hooks/useIfcLoader.ts +23 -10
  95. package/src/hooks/useKeyboardShortcuts.ts +25 -0
  96. package/src/hooks/useSandbox.ts +1 -1
  97. package/src/hooks/useSearchIndex.ts +125 -0
  98. package/src/hooks/useViewControls.ts +13 -5
  99. package/src/index.css +550 -10
  100. package/src/lib/desktop-entitlement.ts +2 -4
  101. package/src/lib/geo/cesium-bridge.ts +15 -7
  102. package/src/lib/geo/effective-georef.test.ts +73 -0
  103. package/src/lib/geo/effective-georef.ts +111 -0
  104. package/src/lib/geo/reproject.ts +105 -19
  105. package/src/lib/llm/byok-guard.test.ts +77 -0
  106. package/src/lib/llm/byok-guard.ts +39 -0
  107. package/src/lib/llm/free-models.test.ts +0 -6
  108. package/src/lib/llm/models.ts +104 -42
  109. package/src/lib/llm/stream-client.ts +74 -110
  110. package/src/lib/llm/stream-direct.test.ts +130 -0
  111. package/src/lib/llm/stream-direct.ts +316 -0
  112. package/src/lib/llm/system-prompt.test.ts +14 -0
  113. package/src/lib/llm/system-prompt.ts +102 -1
  114. package/src/lib/llm/types.ts +20 -2
  115. package/src/lib/recent-files.ts +38 -4
  116. package/src/lib/scripts/templates/bim-globals.d.ts +136 -114
  117. package/src/lib/scripts/templates/construction-schedule.ts +223 -0
  118. package/src/lib/scripts/templates.ts +7 -0
  119. package/src/lib/search/common-ifc-types.ts +36 -0
  120. package/src/lib/search/filter-evaluate.test.ts +537 -0
  121. package/src/lib/search/filter-evaluate.ts +610 -0
  122. package/src/lib/search/filter-rules.test.ts +119 -0
  123. package/src/lib/search/filter-rules.ts +198 -0
  124. package/src/lib/search/filter-schema.test.ts +233 -0
  125. package/src/lib/search/filter-schema.ts +146 -0
  126. package/src/lib/search/recent-searches.test.ts +116 -0
  127. package/src/lib/search/recent-searches.ts +93 -0
  128. package/src/lib/search/result-export.test.ts +101 -0
  129. package/src/lib/search/result-export.ts +104 -0
  130. package/src/lib/search/saved-filters.test.ts +118 -0
  131. package/src/lib/search/saved-filters.ts +154 -0
  132. package/src/lib/search/tier0-scan.test.ts +196 -0
  133. package/src/lib/search/tier0-scan.ts +237 -0
  134. package/src/lib/search/tier1-index.test.ts +242 -0
  135. package/src/lib/search/tier1-index.ts +448 -0
  136. package/src/main.tsx +1 -10
  137. package/src/sdk/adapters/export-adapter.test.ts +434 -1
  138. package/src/sdk/adapters/export-adapter.ts +404 -1
  139. package/src/sdk/adapters/export-schedule-splice.test.ts +127 -0
  140. package/src/sdk/adapters/export-schedule-splice.ts +87 -0
  141. package/src/sdk/adapters/model-compat.ts +8 -2
  142. package/src/sdk/adapters/schedule-adapter.ts +73 -0
  143. package/src/sdk/adapters/store-adapter.ts +201 -0
  144. package/src/sdk/adapters/visibility-adapter.ts +3 -0
  145. package/src/sdk/local-backend.ts +16 -8
  146. package/src/services/api-keys.ts +73 -0
  147. package/src/services/desktop-export.ts +3 -1
  148. package/src/services/desktop-native-metadata.ts +41 -18
  149. package/src/services/file-dialog.ts +4 -1
  150. package/src/services/tauri-modules.d.ts +25 -0
  151. package/src/store/basketVisibleSet.ts +3 -0
  152. package/src/store/constants.ts +20 -2
  153. package/src/store/globalId.ts +4 -1
  154. package/src/store/index.ts +82 -6
  155. package/src/store/slices/addElementMeshes.ts +365 -0
  156. package/src/store/slices/addElementSlice.ts +275 -0
  157. package/src/store/slices/annotationsSlice.test.ts +133 -0
  158. package/src/store/slices/annotationsSlice.ts +251 -0
  159. package/src/store/slices/cesiumSlice.ts +5 -0
  160. package/src/store/slices/chatSlice.test.ts +6 -76
  161. package/src/store/slices/chatSlice.ts +17 -58
  162. package/src/store/slices/dataSlice.test.ts +23 -4
  163. package/src/store/slices/dataSlice.ts +1 -1
  164. package/src/store/slices/modelSlice.test.ts +67 -9
  165. package/src/store/slices/modelSlice.ts +39 -7
  166. package/src/store/slices/mutationSlice.ts +964 -3
  167. package/src/store/slices/overlayCompositor.test.ts +164 -0
  168. package/src/store/slices/overlaySlice.test.ts +93 -0
  169. package/src/store/slices/overlaySlice.ts +151 -0
  170. package/src/store/slices/pinboardSlice.test.ts +6 -1
  171. package/src/store/slices/playbackSlice.ts +128 -0
  172. package/src/store/slices/schedule-edit-helpers.test.ts +97 -0
  173. package/src/store/slices/schedule-edit-helpers.ts +179 -0
  174. package/src/store/slices/scheduleSlice.test.ts +694 -0
  175. package/src/store/slices/scheduleSlice.ts +1330 -0
  176. package/src/store/slices/searchSlice.test.ts +342 -0
  177. package/src/store/slices/searchSlice.ts +341 -0
  178. package/src/store/slices/sectionSlice.test.ts +87 -7
  179. package/src/store/slices/sectionSlice.ts +151 -5
  180. package/src/store/slices/selectionSlice.test.ts +46 -0
  181. package/src/store/slices/selectionSlice.ts +20 -0
  182. package/src/store/slices/uiSlice.ts +28 -5
  183. package/src/store/types.ts +26 -0
  184. package/src/store.ts +14 -0
  185. package/src/utils/nativeSpatialDataStore.ts +4 -1
  186. package/src/utils/viewportUtils.ts +7 -2
  187. package/src/vite-env.d.ts +0 -4
  188. package/dist/assets/drawing-2d-gWfpdfYe.js +0 -257
  189. package/dist/assets/ids-B4jTqB1O.js +0 -1
  190. package/dist/assets/ifc-lite_bg-BX4E7TX8.wasm +0 -0
  191. package/dist/assets/index-DckuDqlv.css +0 -1
  192. package/dist/assets/sandbox-DZiNLNMk.js +0 -5933
  193. package/src/components/viewer/UpgradePage.tsx +0 -71
  194. package/src/lib/desktop/ClerkDesktopEntitlementSync.tsx +0 -175
  195. package/src/lib/llm/ClerkChatSync.tsx +0 -74
  196. package/src/lib/llm/clerk-auth.ts +0 -62
@@ -23,18 +23,12 @@ interface BimEntity {
23
23
 
24
24
  interface BimPropertySet {
25
25
  name: string;
26
- Name?: string;
27
- globalId?: string;
28
- GlobalId?: string;
29
26
  properties: Array<{ name: string; value: string | number | boolean | null }>;
30
- Properties?: Array<{ name: string; value: string | number | boolean | null }>;
31
27
  }
32
28
 
33
29
  interface BimQuantitySet {
34
30
  name: string;
35
31
  quantities: Array<{ name: string; value: number | null }>;
36
- Name?: string;
37
- Quantities?: Array<{ name: string; value: number | null }>;
38
32
  }
39
33
 
40
34
  interface BimAttribute {
@@ -123,40 +117,6 @@ interface BimFileAttachment {
123
117
  hasTextContent: boolean;
124
118
  }
125
119
 
126
- type BimPoint3D = [number, number, number];
127
- type BimPoint2D = [number, number];
128
-
129
- interface BimPlacement3D {
130
- Location: BimPoint3D;
131
- Axis?: BimPoint3D;
132
- RefDirection?: BimPoint3D;
133
- }
134
-
135
- type BimProfileDef =
136
- | { ProfileType: 'AREA'; XDim: number; YDim: number }
137
- | { ProfileType: 'AREA'; Radius: number; WallThickness?: number }
138
- | { ProfileType: 'AREA'; OuterCurve: BimPoint2D[] }
139
- | { ProfileType: 'AREA'; Shape: 'IfcTShapeProfileDef'; FlangeWidth: number; Depth: number; WebThickness: number; FlangeThickness: number; FilletRadius?: number }
140
- | { ProfileType: 'AREA'; Shape: 'IfcUShapeProfileDef'; Depth: number; FlangeWidth: number; WebThickness: number; FlangeThickness: number; FilletRadius?: number }
141
- | { ProfileType: 'AREA'; OverallWidth: number; OverallDepth: number; WebThickness: number; FlangeThickness: number; FilletRadius?: number }
142
- | { ProfileType: 'AREA'; Depth: number; Width: number; Thickness: number; FilletRadius?: number }
143
- | { ProfileType: 'AREA'; Depth: number; Width: number; WallThickness: number; Girth: number }
144
- | { ProfileType: 'AREA'; XDim: number; YDim: number; WallThickness: number; InnerFilletRadius?: number; OuterFilletRadius?: number };
145
-
146
- type BimElementAttrs = {
147
- Name?: string;
148
- Description?: string;
149
- ObjectType?: string;
150
- Tag?: string;
151
- };
152
-
153
- type BimWallHostedOpening = BimElementAttrs & {
154
- Position: BimPoint3D;
155
- Width: number;
156
- Height: number;
157
- Thickness?: number;
158
- };
159
-
160
120
  // ── Namespace declarations ──────────────────────────────────────────────
161
121
 
162
122
  declare const bim: {
@@ -169,7 +129,7 @@ declare const bim: {
169
129
  /** Get active model ID */
170
130
  activeId(): string | null;
171
131
  /** Load IFC content into the 3D viewer for preview */
172
- loadIfc(content: string, filename?: string): void;
132
+ loadIfc(content: string, filename: string): void;
173
133
  };
174
134
  /** Query entities */
175
135
  query: {
@@ -241,7 +201,7 @@ declare const bim: {
241
201
  };
242
202
  /** Property editing */
243
203
  mutate: {
244
- /** Set an IfcPropertySet or quantity value */
204
+ /** Set an IfcPropertySet or quantity value (not a root IFC attribute) */
245
205
  setProperty(entity: unknown, psetName: string, propName: string, value: unknown): void;
246
206
  /** Set a root IFC attribute such as Name, Description, ObjectType, or Tag */
247
207
  setAttribute(entity: unknown, attrName: string, value: string): void;
@@ -252,6 +212,35 @@ declare const bim: {
252
212
  /** Redo undone mutation */
253
213
  redo(modelId: string): void;
254
214
  };
215
+ /** Document-level edits — add, remove, and edit positional STEP arguments on entities of a parsed model */
216
+ store: {
217
+ /** Inject a new entity into the active model. Returns an EntityRef for the freshly-allocated expressId. */
218
+ addEntity(modelId: string, def: { type: string; attributes: unknown[] }): { modelId: string; expressId: number };
219
+ /** Remove an entity. Tombstones existing entities; forgets overlay-only ones. Returns false if the id is unknown. */
220
+ removeEntity(entity: { modelId: string; expressId: number }): boolean;
221
+ /** Edit a non-IfcRoot attribute by zero-based STEP argument index (e.g. IfcRectangleProfileDef.XDim is index 3). */
222
+ setPositionalAttribute(entity: { modelId: string; expressId: number }, index: number, value: unknown): void;
223
+ /** Add an IfcColumn to a parsed model anchored to an existing IfcBuildingStorey. Returns the new column entity ref. */
224
+ addColumn(modelId: string, storeyExpressId: number, params: { Position: [number, number, number]; Width: number; Depth: number; Height: number; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
225
+ /** Add an IfcWall from Start to End anchored to an IfcBuildingStorey. Returns the new wall entity ref. */
226
+ addWall(modelId: string, storeyExpressId: number, params: { Start: [number, number, number]; End: [number, number, number]; Thickness: number; Height: number; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
227
+ /** Add an IfcSlab anchored to an IfcBuildingStorey. Two modes: rectangle (Position + Width + Depth) or polygon (OuterCurve = Array<[x, y]> with ≥3 points). */
228
+ addSlab(modelId: string, storeyExpressId: number, params: { Position: [number, number, number]; Width: number; Depth: number; Thickness: number; Profile?: "rectangle"; Name?: string; Description?: string; ObjectType?: string; Tag?: string } | { Profile: "polygon"; OuterCurve: Array<[number, number]>; Position?: [number, number, number]; Thickness: number; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
229
+ /** Add an IfcBeam from Start to End with a centred rectangular cross-section. */
230
+ addBeam(modelId: string, storeyExpressId: number, params: { Start: [number, number, number]; End: [number, number, number]; Width: number; Height: number; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
231
+ /** Add a free-standing IfcDoor anchored to an IfcBuildingStorey. */
232
+ addDoor(modelId: string, storeyExpressId: number, params: { Position: [number, number, number]; Width: number; Height: number; FrameThickness?: number; PredefinedType?: string; OperationType?: string; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
233
+ /** Add a free-standing IfcWindow anchored to an IfcBuildingStorey. */
234
+ addWindow(modelId: string, storeyExpressId: number, params: { Position: [number, number, number]; Width: number; Height: number; FrameThickness?: number; PredefinedType?: string; PartitioningType?: string; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
235
+ /** Add an IfcSpace (room) — rectangle or polygon footprint extruded by Height. */
236
+ addSpace(modelId: string, storeyExpressId: number, params: { Position: [number, number, number]; Width: number; Depth: number; Height: number; Profile?: "rectangle"; Name?: string; LongName?: string; Description?: string; ObjectType?: string } | { Profile: "polygon"; OuterCurve: Array<[number, number]>; Position?: [number, number, number]; Height: number; Name?: string; LongName?: string; Description?: string; ObjectType?: string }): { modelId: string; expressId: number };
237
+ /** Add an IfcRoof (flat-roof slab variant). Two modes: rectangle or polygon. */
238
+ addRoof(modelId: string, storeyExpressId: number, params: { Position: [number, number, number]; Width: number; Depth: number; Thickness: number; Profile?: "rectangle"; Name?: string; Description?: string; ObjectType?: string; Tag?: string } | { Profile: "polygon"; OuterCurve: Array<[number, number]>; Position?: [number, number, number]; Thickness: number; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
239
+ /** Add an IfcPlate (thin flat element). Two modes: rectangle or polygon. */
240
+ addPlate(modelId: string, storeyExpressId: number, params: { Position: [number, number, number]; Width: number; Depth: number; Thickness: number; Profile?: "rectangle"; PredefinedType?: string; Name?: string; Description?: string; ObjectType?: string; Tag?: string } | { Profile: "polygon"; OuterCurve: Array<[number, number]>; Position?: [number, number, number]; Thickness: number; PredefinedType?: string; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
241
+ /** Add an IfcMember (generic structural member — brace, post, strut) from Start to End. */
242
+ addMember(modelId: string, storeyExpressId: number, params: { Start: [number, number, number]; End: [number, number, number]; Width: number; Height: number; PredefinedType?: string; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): { modelId: string; expressId: number };
243
+ };
255
244
  /** Lens visualization */
256
245
  lens: {
257
246
  /** Get built-in lens presets */
@@ -260,83 +249,105 @@ declare const bim: {
260
249
  /** IFC creation from scratch */
261
250
  create: {
262
251
  /** Create a new IFC project. Returns a creator handle (number). */
263
- project(params?: { Name?: string; Description?: string; Schema?: string; LengthUnit?: string; Author?: string; Organization?: string }): number;
252
+ project(params: { Name?: string; Description?: string; Schema?: string; LengthUnit?: string; Author?: string; Organization?: string }): number;
253
+ /** Generate the IFC STEP file content. Returns { content, entities, stats }. */
254
+ toIfc(handle: number): { content: string; entities: Array<{ expressId: number; type: string; Name?: string }>; stats: { entityCount: number; fileSize: number } };
255
+ /** Assign a named colour to an element. Call before toIfc(). */
256
+ setColor(handle: number, elementId: number, name: string, rgb: unknown): void;
257
+ /** Create an IfcWorkSchedule. Returns schedule expressId. */
258
+ addIfcWorkSchedule(handle: number, params: { Name: string; StartTime: string; FinishTime?: string; CreationDate?: string; Description?: string; Identification?: string; Purpose?: string; Duration?: string; TotalFloat?: string; PredefinedType?: 'ACTUAL' | 'BASELINE' | 'PLANNED' | 'USERDEFINED' | 'NOTDEFINED' }): number;
259
+ /** Create an IfcWorkPlan (groups multiple schedules). Returns plan expressId. */
260
+ addIfcWorkPlan(handle: number, params: { Name: string; StartTime: string; FinishTime?: string; CreationDate?: string; Description?: string; Identification?: string; Purpose?: string; Duration?: string; PredefinedType?: 'ACTUAL' | 'BASELINE' | 'PLANNED' | 'USERDEFINED' | 'NOTDEFINED' }): number;
261
+ /** Create an IfcTask. Provide ScheduleStart + ScheduleFinish (or ScheduleDuration) for time fields. Returns task expressId. */
262
+ addIfcTask(handle: number, params: { Name: string; Description?: string; Identification?: string; LongDescription?: string; Status?: string; WorkMethod?: string; IsMilestone?: boolean; Priority?: number; ObjectType?: string; ScheduleStart?: string; ScheduleFinish?: string; ScheduleDuration?: string; ActualStart?: string; ActualFinish?: string; ActualDuration?: string; EarlyStart?: string; EarlyFinish?: string; LateStart?: string; LateFinish?: string; FreeFloat?: string; TotalFloat?: string; IsCritical?: boolean; DurationType?: 'WORKTIME' | 'ELAPSEDTIME' | 'NOTDEFINED'; Completion?: number; PredefinedType?: 'ATTENDANCE' | 'CONSTRUCTION' | 'DEMOLITION' | 'DISMANTLE' | 'DISPOSAL' | 'INSTALLATION' | 'LOGISTIC' | 'MAINTENANCE' | 'MOVE' | 'OPERATION' | 'REMOVAL' | 'RENOVATION' | 'USERDEFINED' | 'NOTDEFINED' | 'ADJUSTMENT' | 'CALIBRATION' | 'EMERGENCY' | 'INSPECTION' | 'SAFETY' | 'SHUTDOWN' | 'STARTUP' | 'TESTING' | 'TROUBLESHOOTING' }): number;
263
+ /** Link predecessor → successor tasks via IfcRelSequence. Returns relationship expressId. */
264
+ addIfcRelSequence(handle: number, predecessorTaskId: number, successorTaskId: number, params: { SequenceType?: 'START_START' | 'START_FINISH' | 'FINISH_START' | 'FINISH_FINISH' | 'USERDEFINED' | 'NOTDEFINED'; TimeLag?: string; LagDurationType?: 'WORKTIME' | 'ELAPSEDTIME' | 'NOTDEFINED'; UserDefinedSequenceType?: string }): number;
265
+ /** Canonical IfcRelAssignsToControl — bind IfcObjectDefinitions (tasks or sub-schedules) to an IfcControl (IfcWorkSchedule/IfcWorkPlan). Returns relationship expressId. */
266
+ addIfcRelAssignsToControl(handle: number, relatingControlId: number, relatedObjectIds: number[]): number;
267
+ /** Canonical IfcRelAssignsToProcess — bind products to an IfcProcess (task). Drives the 4D Gantt animation. Returns relationship expressId. */
268
+ addIfcRelAssignsToProcess(handle: number, relatingProcessId: number, relatedObjectIds: number[]): number;
269
+ /** Canonical IfcRelNests — nest child objects under a parent (task WBS hierarchy). Returns relationship expressId. */
270
+ addIfcRelNests(handle: number, relatingObjectId: number, relatedObjectIds: number[]): number;
271
+ /** Ergonomic alias for addIfcRelAssignsToControl — assign tasks to a work schedule. Returns relationship expressId. */
272
+ assignTasksToWorkSchedule(handle: number, scheduleId: number, taskIds: number[]): number;
273
+ /** Ergonomic alias for addIfcRelAssignsToControl — attach work schedules to a parent IfcWorkPlan. Returns relationship expressId. */
274
+ assignSchedulesToWorkPlan(handle: number, planId: number, scheduleIds: number[]): number;
275
+ /** Ergonomic alias for addIfcRelAssignsToProcess — bind products to a task. Returns relationship expressId. */
276
+ assignProductsToTask(handle: number, taskId: number, productIds: number[]): number;
277
+ /** Ergonomic alias for addIfcRelNests — nest child tasks under a summary parent. Returns relationship expressId. */
278
+ nestTasks(handle: number, parentTaskId: number, childTaskIds: number[]): number;
279
+ /** Create ANY IFC type extruded along a Start→End axis. Returns expressId. */
280
+ addAxisElement(handle: number, storeyId: number, params: unknown): number;
281
+ /** Create ANY IFC type with a profile at a placement. Returns expressId. */
282
+ addElement(handle: number, storeyId: number, params: unknown): number;
283
+ /** Add IfcBeam. Returns expressId. */
284
+ addIfcBeam(handle: number, storeyId: number, params: unknown): number;
285
+ /** Add IfcBuildingElementProxy. Returns expressId. */
286
+ addIfcBuildingElementProxy(handle: number, storeyId: number, params: unknown): number;
264
287
  /** Add a building storey. Returns storey expressId. */
265
- addIfcBuildingStorey(handle: number, params: { Name?: string; Description?: string; Elevation: number }): number;
266
- /** Add a wall to a storey. Returns wall expressId. */
267
- addIfcWall(handle: number, storeyId: number, params: BimElementAttrs & { Start: [number,number,number]; End: [number,number,number]; Thickness: number; Height: number; Openings?: Array<{ Width: number; Height: number; Position: [number,number,number]; Name?: string }> }): number;
268
- /** Add a slab to a storey. Returns slab expressId. */
269
- addIfcSlab(handle: number, storeyId: number, params: BimElementAttrs & { Position: [number,number,number]; Thickness: number; Width?: number; Depth?: number; Profile?: [number,number][]; Openings?: Array<{ Width: number; Height: number; Position: [number,number,number]; Name?: string }> }): number;
270
- /** Add a column to a storey. Returns column expressId. */
271
- addIfcColumn(handle: number, storeyId: number, params: BimElementAttrs & { Position: [number,number,number]; Width: number; Depth: number; Height: number }): number;
272
- /** Add a beam to a storey. Returns beam expressId. */
273
- addIfcBeam(handle: number, storeyId: number, params: BimElementAttrs & { Start: [number,number,number]; End: [number,number,number]; Width: number; Height: number }): number;
274
- /** Add a stair to a storey. Returns stair expressId. */
275
- addIfcStair(handle: number, storeyId: number, params: BimElementAttrs & { Position: [number,number,number]; NumberOfRisers: number; RiserHeight: number; TreadLength: number; Width: number; Direction?: number }): number;
276
- /** Add a roof to a storey. Returns roof expressId. */
277
- addIfcRoof(handle: number, storeyId: number, params: BimElementAttrs & { Position: [number,number,number]; Width: number; Depth: number; Thickness: number; Slope?: number }): number;
288
+ addIfcBuildingStorey(handle: number, params: unknown): number;
289
+ /** Add IfcCircularColumn. Returns expressId. */
290
+ addIfcCircularColumn(handle: number, storeyId: number, params: unknown): number;
291
+ /** Add IfcColumn. Returns expressId. */
292
+ addIfcColumn(handle: number, storeyId: number, params: unknown): number;
293
+ /** Add IfcCurtainWall. Returns expressId. */
294
+ addIfcCurtainWall(handle: number, storeyId: number, params: unknown): number;
295
+ /** Add IfcDoor. Returns expressId. */
296
+ addIfcDoor(handle: number, storeyId: number, params: unknown): number;
297
+ /** Add IfcElementQuantity. Returns expressId. */
298
+ addIfcElementQuantity(handle: number, elementId: number, params: unknown): number;
299
+ /** Add IfcFooting. Returns expressId. */
300
+ addIfcFooting(handle: number, storeyId: number, params: unknown): number;
301
+ /** Add IfcFurnishingElement. Returns expressId. */
302
+ addIfcFurnishingElement(handle: number, storeyId: number, params: unknown): number;
278
303
  /** Add a dual-pitch gable roof. `Slope` is in radians. Returns roof expressId. */
279
- addIfcGableRoof(handle: number, storeyId: number, params: BimElementAttrs & { Position: [number,number,number]; Width: number; Depth: number; Thickness: number; Slope: number; Overhang?: number }): number;
304
+ addIfcGableRoof(handle: number, storeyId: number, params: unknown): number;
305
+ /** Add IfcHollowCircularColumn. Returns expressId. */
306
+ addIfcHollowCircularColumn(handle: number, storeyId: number, params: unknown): number;
307
+ /** Add IfcIShapeBeam. Returns expressId. */
308
+ addIfcIShapeBeam(handle: number, storeyId: number, params: unknown): number;
309
+ /** Add IfcLShapeMember. Returns expressId. */
310
+ addIfcLShapeMember(handle: number, storeyId: number, params: unknown): number;
311
+ /** Associate a material with an element via IfcRelAssociatesMaterial (deferred to toIfc). Returns nothing. */
312
+ addIfcMaterial(handle: number, elementId: number, params: unknown): void;
313
+ /** Add IfcMember. Returns expressId. */
314
+ addIfcMember(handle: number, storeyId: number, params: unknown): number;
315
+ /** Add IfcPile. Returns expressId. */
316
+ addIfcPile(handle: number, storeyId: number, params: unknown): number;
317
+ /** Add IfcPlate. Returns expressId. */
318
+ addIfcPlate(handle: number, storeyId: number, params: unknown): number;
319
+ /** Add IfcPropertySet. Returns expressId. */
320
+ addIfcPropertySet(handle: number, elementId: number, params: unknown): number;
321
+ /** Add IfcRailing. Returns expressId. */
322
+ addIfcRailing(handle: number, storeyId: number, params: unknown): number;
323
+ /** Add IfcRamp. Returns expressId. */
324
+ addIfcRamp(handle: number, storeyId: number, params: unknown): number;
325
+ /** Add IfcRectangleHollowBeam. Returns expressId. */
326
+ addIfcRectangleHollowBeam(handle: number, storeyId: number, params: unknown): number;
327
+ /** Add IfcRoof. Returns expressId. */
328
+ addIfcRoof(handle: number, storeyId: number, params: unknown): number;
329
+ /** Add IfcSlab. Returns expressId. */
330
+ addIfcSlab(handle: number, storeyId: number, params: unknown): number;
331
+ /** Add IfcSpace. Returns expressId. */
332
+ addIfcSpace(handle: number, storeyId: number, params: unknown): number;
333
+ /** Add IfcStair. Returns expressId. */
334
+ addIfcStair(handle: number, storeyId: number, params: unknown): number;
335
+ /** Add IfcTShapeMember. Returns expressId. */
336
+ addIfcTShapeMember(handle: number, storeyId: number, params: unknown): number;
337
+ /** Add IfcUShapeMember. Returns expressId. */
338
+ addIfcUShapeMember(handle: number, storeyId: number, params: unknown): number;
339
+ /** Add IfcWall. Returns expressId. */
340
+ addIfcWall(handle: number, storeyId: number, params: unknown): number;
280
341
  /** Add a door hosted in a wall opening. Position is wall-local [alongWall, 0, baseHeight]. Returns door expressId. */
281
- addIfcWallDoor(handle: number, wallId: number, params: BimWallHostedOpening & { PredefinedType?: string; OperationType?: string }): number;
342
+ addIfcWallDoor(handle: number, wallId: number, params: unknown): number;
282
343
  /** Add a window hosted in a wall opening. Position is wall-local [alongWall, 0, sillHeight]. Returns window expressId. */
283
- addIfcWallWindow(handle: number, wallId: number, params: BimWallHostedOpening & { PartitioningType?: string }): number;
284
- /** Add a door to a storey. Returns door expressId. */
285
- addIfcDoor(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Height: number; Thickness?: number; PredefinedType?: string; OperationType?: string }): number;
286
- /** Add a window to a storey. Returns window expressId. */
287
- addIfcWindow(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Height: number; Thickness?: number; PartitioningType?: string }): number;
288
- /** Add a ramp to a storey. Returns ramp expressId. */
289
- addIfcRamp(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Length: number; Thickness: number; Rise?: number }): number;
290
- /** Add a railing to a storey. Returns railing expressId. */
291
- addIfcRailing(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; Height: number; Width?: number }): number;
292
- /** Add a plate to a storey. Returns plate expressId. */
293
- addIfcPlate(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Depth: number; Thickness: number; Profile?: BimPoint2D[] }): number;
294
- /** Add a member to a storey. Returns member expressId. */
295
- addIfcMember(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; Width: number; Height: number }): number;
296
- /** Add a footing to a storey. Returns footing expressId. */
297
- addIfcFooting(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Depth: number; Height: number; PredefinedType?: string }): number;
298
- /** Add a pile to a storey. Returns pile expressId. */
299
- addIfcPile(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Length: number; Diameter: number; IsRectangular?: boolean; RectangularDepth?: number }): number;
300
- /** Add a space to a storey. Returns space expressId. */
301
- addIfcSpace(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Depth: number; Height: number; LongName?: string; Profile?: BimPoint2D[] }): number;
302
- /** Add a curtain wall to a storey. Returns curtain wall expressId. */
303
- addIfcCurtainWall(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; Height: number; Thickness?: number }): number;
304
- /** Add a furnishing element to a storey. Returns expressId. */
305
- addIfcFurnishingElement(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Depth: number; Height: number; Direction?: number }): number;
306
- /** Add a generic building element proxy to a storey. Returns expressId. */
307
- addIfcBuildingElementProxy(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Width: number; Depth: number; Height: number; Profile?: BimPoint2D[]; ProxyType?: string }): number;
308
- /** Add a circular column to a storey. Returns expressId. */
309
- addIfcCircularColumn(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Radius: number; Height: number }): number;
310
- /** Add an I-shape beam to a storey. Returns expressId. */
311
- addIfcIShapeBeam(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; OverallWidth: number; OverallDepth: number; WebThickness: number; FlangeThickness: number; FilletRadius?: number }): number;
312
- /** Add an L-shape member to a storey. Returns expressId. */
313
- addIfcLShapeMember(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; Width: number; Depth: number; Thickness: number; FilletRadius?: number }): number;
314
- /** Add a T-shape member to a storey. Returns expressId. */
315
- addIfcTShapeMember(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; FlangeWidth: number; Depth: number; WebThickness: number; FlangeThickness: number; FilletRadius?: number }): number;
316
- /** Add a U-shape member to a storey. Returns expressId. */
317
- addIfcUShapeMember(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; Depth: number; FlangeWidth: number; WebThickness: number; FlangeThickness: number; FilletRadius?: number }): number;
318
- /** Add a hollow circular column to a storey. Returns expressId. */
319
- addIfcHollowCircularColumn(handle: number, storeyId: number, params: BimElementAttrs & { Position: BimPoint3D; Radius: number; WallThickness: number; Height: number }): number;
320
- /** Add a rectangular hollow beam to a storey. Returns expressId. */
321
- addIfcRectangleHollowBeam(handle: number, storeyId: number, params: BimElementAttrs & { Start: BimPoint3D; End: BimPoint3D; XDim: number; YDim: number; WallThickness: number; InnerFilletRadius?: number; OuterFilletRadius?: number }): number;
322
- /** Create any IFC type with a profile at a placement. Returns expressId. */
323
- addElement(handle: number, storeyId: number, params: { IfcType: string; Placement: BimPlacement3D; Profile: BimProfileDef; Depth: number; ExtrusionDirection?: BimPoint3D; PredefinedType?: string; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): number;
324
- /** Create any IFC type extruded along a Start→End axis. Returns expressId. */
325
- addAxisElement(handle: number, storeyId: number, params: { IfcType: string; Start: BimPoint3D; End: BimPoint3D; Profile: BimProfileDef; PredefinedType?: string; Name?: string; Description?: string; ObjectType?: string; Tag?: string }): number;
344
+ addIfcWallWindow(handle: number, wallId: number, params: unknown): number;
345
+ /** Add IfcWindow. Returns expressId. */
346
+ addIfcWindow(handle: number, storeyId: number, params: unknown): number;
326
347
  /** Create a profile from a ProfileDef union. Returns profile ID. */
327
- createProfile(handle: number, profile: BimProfileDef): number;
348
+ createProfile(handle: number, profile: unknown): number;
328
349
  /** Get the world placement ID for use with addLocalPlacement. */
329
350
  getWorldPlacementId(handle: number): number;
330
- /** Assign a named colour to an element. Call before toIfc(). */
331
- setColor(handle: number, elementId: number, name: string, rgb: [number, number, number]): void;
332
- /** Assign an IFC material (simple or layered) to an element. */
333
- addIfcMaterial(handle: number, elementId: number, material: { Name: string; Category?: string; Layers?: Array<{ Name: string; Thickness: number; Category?: string; IsVentilated?: boolean }> }): void;
334
- /** Attach a property set to an element. Returns pset expressId. */
335
- addIfcPropertySet(handle: number, elementId: number, pset: { Name: string; Properties: Array<{ Name: string; NominalValue: string | number | boolean; Type?: string }> }): number;
336
- /** Attach element quantities to an element. Returns qset expressId. */
337
- addIfcElementQuantity(handle: number, elementId: number, qset: { Name: string; Quantities: Array<{ Name: string; Value: number; Kind: 'IfcQuantityLength' | 'IfcQuantityArea' | 'IfcQuantityVolume' | 'IfcQuantityCount' | 'IfcQuantityWeight' }> }): number;
338
- /** Generate the IFC STEP file content. Returns { content, entities, stats }. */
339
- toIfc(handle: number): { content: string; entities: Array<{ expressId: number; type: string; Name?: string }>; stats: { entityCount: number; fileSize: number } };
340
351
  };
341
352
  /** Uploaded file attachments */
342
353
  files: {
@@ -349,6 +360,17 @@ declare const bim: {
349
360
  /** Get parsed CSV column names for an uploaded attachment by file name */
350
361
  csvColumns(name: string): string[];
351
362
  };
363
+ /** 4D / IFC construction schedule reader (IfcTask, IfcWorkSchedule, IfcRelSequence) */
364
+ schedule: {
365
+ /** Full schedule extraction — tasks, dependencies, and work schedules. */
366
+ data(modelId?: string): { HasSchedule: boolean; WorkSchedules: Array<{ GlobalId: string; ExpressId: number; Name: string; Description?: string; Identification?: string; CreationDate?: string; StartTime?: string; FinishTime?: string; Purpose?: string; Duration?: string; PredefinedType?: string; Kind: 'WorkSchedule' | 'WorkPlan'; TaskGlobalIds: string[] }>; Tasks: Array<{ GlobalId: string; ExpressId: number; Name: string; Description?: string; ObjectType?: string; Identification?: string; LongDescription?: string; Status?: string; WorkMethod?: string; IsMilestone: boolean; Priority?: number; PredefinedType?: string; ParentTaskGlobalId?: string; ChildTaskGlobalIds: string[]; AssignedProductExpressIds: number[]; AssignedProductGlobalIds: string[]; ControllingScheduleGlobalIds: string[]; TaskTime?: { ScheduleStart?: string; ScheduleFinish?: string; ScheduleDuration?: string; ActualStart?: string; ActualFinish?: string; ActualDuration?: string; EarlyStart?: string; EarlyFinish?: string; LateStart?: string; LateFinish?: string; FreeFloat?: string; TotalFloat?: string; RemainingTime?: string; StatusTime?: string; IsCritical?: boolean; Completion?: number; DurationType?: 'WORKTIME' | 'ELAPSEDTIME' | 'NOTDEFINED' } }>; Sequences: Array<{ RelatingProcessGlobalId: string; RelatedProcessGlobalId: string; SequenceType: 'START_START' | 'START_FINISH' | 'FINISH_START' | 'FINISH_FINISH' | 'USERDEFINED' | 'NOTDEFINED'; UserDefinedSequenceType?: string; TimeLagSeconds?: number; TimeLagDuration?: string }> };
367
+ /** All IfcTask entities with their times and assigned products. */
368
+ tasks(modelId?: string): Array<{ GlobalId: string; ExpressId: number; Name: string; Description?: string; ObjectType?: string; Identification?: string; LongDescription?: string; Status?: string; WorkMethod?: string; IsMilestone: boolean; Priority?: number; PredefinedType?: string; ParentTaskGlobalId?: string; ChildTaskGlobalIds: string[]; AssignedProductExpressIds: number[]; AssignedProductGlobalIds: string[]; ControllingScheduleGlobalIds: string[]; TaskTime?: { ScheduleStart?: string; ScheduleFinish?: string; ScheduleDuration?: string; ActualStart?: string; ActualFinish?: string; ActualDuration?: string; EarlyStart?: string; EarlyFinish?: string; LateStart?: string; LateFinish?: string; FreeFloat?: string; TotalFloat?: string; RemainingTime?: string; StatusTime?: string; IsCritical?: boolean; Completion?: number; DurationType?: 'WORKTIME' | 'ELAPSEDTIME' | 'NOTDEFINED' } }>;
369
+ /** All IfcWorkSchedule and IfcWorkPlan containers. */
370
+ workSchedules(modelId?: string): Array<{ GlobalId: string; ExpressId: number; Name: string; Description?: string; Identification?: string; CreationDate?: string; StartTime?: string; FinishTime?: string; Purpose?: string; Duration?: string; PredefinedType?: string; Kind: 'WorkSchedule' | 'WorkPlan'; TaskGlobalIds: string[] }>;
371
+ /** All IfcRelSequence dependency edges (FS/SS/FF/SF, with optional IfcLagTime). */
372
+ sequences(modelId?: string): Array<{ RelatingProcessGlobalId: string; RelatedProcessGlobalId: string; SequenceType: 'START_START' | 'START_FINISH' | 'FINISH_START' | 'FINISH_FINISH' | 'USERDEFINED' | 'NOTDEFINED'; UserDefinedSequenceType?: string; TimeLagSeconds?: number; TimeLagDuration?: string }>;
373
+ };
352
374
  /** Data export */
353
375
  export: {
354
376
  /** Export entities to CSV string */
@@ -356,8 +378,8 @@ declare const bim: {
356
378
  /** Export entities to JSON array */
357
379
  json(entities: BimEntity[], columns: string[]): Record<string, unknown>[];
358
380
  /** Export entities to IFC STEP text. Pass filename to auto-download a valid .ifc file */
359
- ifc(entities: BimEntity[], options?: { schema?: "IFC2X3" | "IFC4" | "IFC4X3"; filename?: string; includeMutations?: boolean; visibleOnly?: boolean }): string;
360
- /** Trigger a browser file download with raw content */
381
+ ifc(entities: BimEntity[], options: { schema?: "IFC2X3" | "IFC4" | "IFC4X3"; filename?: string; includeMutations?: boolean; visibleOnly?: boolean }): string | Uint8Array;
382
+ /** Trigger a browser file download with the given content. mimeType defaults to text/plain. */
361
383
  download(content: string, filename: string, mimeType?: string): void;
362
384
  };
363
385
  };
@@ -0,0 +1,223 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ export {} // module boundary (stripped by transpiler)
6
+
7
+ // ─────────────────────────────────────────────────────────────────────────
8
+ // Construction schedule — build an IfcWorkSchedule + IfcTasks + sequences
9
+ //
10
+ // Two modes:
11
+ // 1) Attach a construction sequence to the CURRENTLY LOADED model.
12
+ // The script reads CSV task rows (attached via the chat paperclip)
13
+ // and creates IfcTasks whose products are resolved by name/type.
14
+ //
15
+ // 2) No model loaded — generate a standalone demo IFC file with a few
16
+ // walls and a matching 4-task construction schedule.
17
+ //
18
+ // CSV expected columns (case-insensitive, any subset works):
19
+ // id, name, start, finish, duration, predecessor, products, predefinedType,
20
+ // isMilestone, isCritical, completion
21
+ //
22
+ // Dates are ISO 8601 (e.g. 2024-05-01T08:00:00).
23
+ // Durations are ISO 8601 (e.g. P5D, PT8H).
24
+ // `products` is a comma-separated list of IFC types (e.g. "IfcWall,IfcSlab")
25
+ // OR entity globalIds; elements matching each row are assigned to that task.
26
+ // `predecessor` is the `id` of the row that must finish before this one.
27
+ // ─────────────────────────────────────────────────────────────────────────
28
+
29
+ function toIso(v: string | undefined): string | undefined {
30
+ if (!v) return undefined
31
+ const s = String(v).trim()
32
+ if (!s) return undefined
33
+ // Accept "YYYY-MM-DD" → append midnight
34
+ if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return `${s}T00:00:00`
35
+ return s
36
+ }
37
+
38
+ function toBool(v: unknown): boolean | undefined {
39
+ if (v === undefined || v === null || v === '') return undefined
40
+ const s = String(v).trim().toLowerCase()
41
+ if (s === 'true' || s === '1' || s === 'yes' || s === 'y') return true
42
+ if (s === 'false' || s === '0' || s === 'no' || s === 'n') return false
43
+ return undefined
44
+ }
45
+
46
+ function toNumber(v: unknown): number | undefined {
47
+ if (v === undefined || v === null || v === '') return undefined
48
+ const n = Number(v)
49
+ return Number.isFinite(n) ? n : undefined
50
+ }
51
+
52
+ // Canonicalize a column name so "Start Date", "start_date" and "start" all match.
53
+ function findCol(cols: string[], ...aliases: string[]): string | null {
54
+ const norm = (s: string) => s.toLowerCase().replace(/[\s_-]+/g, '')
55
+ const wanted = aliases.map(norm)
56
+ for (const c of cols) if (wanted.includes(norm(c))) return c
57
+ return null
58
+ }
59
+
60
+ const files = bim.files.list()
61
+ const csvFile = files.find((f) => f.name.toLowerCase().endsWith('.csv'))
62
+
63
+ if (csvFile) {
64
+ // ─── Mode 1: attach schedule to currently loaded model ────────────────
65
+ const rows = bim.files.csv(csvFile.name) ?? []
66
+ const cols = bim.files.csvColumns(csvFile.name)
67
+ if (rows.length === 0) {
68
+ console.warn(`[schedule] ${csvFile.name} has no rows`)
69
+ } else {
70
+ console.log(`[schedule] loading ${rows.length} tasks from ${csvFile.name}`)
71
+ }
72
+
73
+ const idCol = findCol(cols, 'id', 'taskid')
74
+ const nameCol = findCol(cols, 'name', 'task', 'activity')
75
+ const startCol = findCol(cols, 'start', 'startdate', 'schedulestart')
76
+ const finishCol = findCol(cols, 'finish', 'end', 'enddate', 'schedulefinish')
77
+ const durCol = findCol(cols, 'duration', 'scheduleduration')
78
+ const predCol = findCol(cols, 'predecessor', 'depends', 'dependson')
79
+ const productsCol = findCol(cols, 'products', 'type', 'entities', 'targets')
80
+ const typeCol = findCol(cols, 'predefinedtype', 'kind')
81
+ const mileCol = findCol(cols, 'ismilestone', 'milestone')
82
+ const critCol = findCol(cols, 'iscritical', 'critical')
83
+ const compCol = findCol(cols, 'completion', 'percentcomplete', 'progress')
84
+
85
+ // Discover every loaded product once so we can resolve `products` values
86
+ // (IFC type OR globalId substring) into a list of expressIds.
87
+ const allProducts = bim.query.byType(
88
+ 'IfcWall', 'IfcSlab', 'IfcColumn', 'IfcBeam', 'IfcRoof', 'IfcStair',
89
+ 'IfcDoor', 'IfcWindow', 'IfcRailing', 'IfcFooting', 'IfcCurtainWall',
90
+ 'IfcMember', 'IfcPlate', 'IfcFurnishingElement', 'IfcBuildingElementProxy',
91
+ )
92
+
93
+ // Minimum character count before we fall back to a globalId prefix match;
94
+ // avoids accidental wildcarding when the CSV column holds short tokens.
95
+ const MIN_GID_PREFIX_LEN = 4
96
+
97
+ function resolveProducts(spec: string | undefined): number[] {
98
+ if (!spec) return []
99
+ const parts = spec.split(/[,;]/).map((s) => s.trim()).filter(Boolean)
100
+ const ids = new Set<number>()
101
+ for (const part of parts) {
102
+ const upper = part.toUpperCase()
103
+ if (upper.startsWith('IFC')) {
104
+ // IFC type — match all loaded entities of that class
105
+ for (const e of allProducts) {
106
+ if (e.type.toUpperCase() === upper) ids.add(e.ref.expressId)
107
+ }
108
+ } else {
109
+ // Exact globalId match, OR prefix match when the token is long enough
110
+ // to uniquely identify an element (≥ 4 chars).
111
+ for (const e of allProducts) {
112
+ if (e.globalId === part) {
113
+ ids.add(e.ref.expressId)
114
+ } else if (part.length >= MIN_GID_PREFIX_LEN && e.globalId.startsWith(part)) {
115
+ ids.add(e.ref.expressId)
116
+ }
117
+ }
118
+ }
119
+ }
120
+ return Array.from(ids)
121
+ }
122
+
123
+ // We can't use bim.create on an existing model in this iteration — the
124
+ // creator produces a fresh IFC file. So we log what *would* be created
125
+ // and print a plan. The plan is directly feedable to a follow-up
126
+ // save/export workflow.
127
+ console.log('[schedule] plan:')
128
+ for (const row of rows) {
129
+ const id = idCol ? row[idCol] : '-'
130
+ const name = nameCol ? row[nameCol] : '(unnamed)'
131
+ const start = startCol ? toIso(row[startCol]) : undefined
132
+ const finish = finishCol ? toIso(row[finishCol]) : undefined
133
+ const dur = durCol ? row[durCol] : undefined
134
+ const pred = predCol ? row[predCol] : undefined
135
+ const prodSpec = productsCol ? row[productsCol] : undefined
136
+ const prodIds = resolveProducts(prodSpec)
137
+ const predefinedType = typeCol ? row[typeCol] : undefined
138
+ const isMilestone = mileCol ? toBool(row[mileCol]) : undefined
139
+ const isCritical = critCol ? toBool(row[critCol]) : undefined
140
+ const completion = compCol ? toNumber(row[compCol]) : undefined
141
+ console.log(
142
+ ` • [${id}] ${name} ${start ?? '?'} → ${finish ?? dur ?? '?'} ` +
143
+ `prod=${prodIds.length} pred=${pred ?? '-'} ` +
144
+ `type=${predefinedType ?? '-'} mile=${isMilestone ?? '-'} ` +
145
+ `crit=${isCritical ?? '-'} comp=${completion ?? '-'}`,
146
+ )
147
+ }
148
+ console.log(
149
+ '[schedule] Attaching tasks to an existing IFC requires a separate ' +
150
+ 'mutation workflow — ask the assistant to wire the plan into a fresh ' +
151
+ 'IFC export using bim.create.* so the 4D Gantt panel can play it.',
152
+ )
153
+ } else {
154
+ // ─── Mode 2: generate a demo IFC with walls + a matching schedule ─────
155
+ console.log('[schedule] No CSV attached — building demo model + schedule')
156
+
157
+ const h = bim.create.project({ Name: 'Demo with schedule', Schema: 'IFC4' })
158
+ const storey = bim.create.addIfcBuildingStorey(h, { Name: 'Ground', Elevation: 0 })
159
+
160
+ const wallA = bim.create.addIfcWall(h, storey, {
161
+ Name: 'Wall A', Start: [0, 0, 0], End: [5, 0, 0], Thickness: 0.2, Height: 3,
162
+ })
163
+ const wallB = bim.create.addIfcWall(h, storey, {
164
+ Name: 'Wall B', Start: [5, 0, 0], End: [5, 5, 0], Thickness: 0.2, Height: 3,
165
+ })
166
+ const wallC = bim.create.addIfcWall(h, storey, {
167
+ Name: 'Wall C', Start: [5, 5, 0], End: [0, 5, 0], Thickness: 0.2, Height: 3,
168
+ })
169
+ const wallD = bim.create.addIfcWall(h, storey, {
170
+ Name: 'Wall D', Start: [0, 5, 0], End: [0, 0, 0], Thickness: 0.2, Height: 3,
171
+ })
172
+
173
+ const schedule = bim.create.addIfcWorkSchedule(h, {
174
+ Name: 'Construction schedule',
175
+ StartTime: '2024-05-01T08:00:00',
176
+ FinishTime: '2024-05-20T17:00:00',
177
+ PredefinedType: 'PLANNED',
178
+ })
179
+
180
+ const tFoundation = bim.create.addIfcTask(h, {
181
+ Name: 'Site preparation',
182
+ PredefinedType: 'CONSTRUCTION',
183
+ ScheduleStart: '2024-05-01T08:00:00',
184
+ ScheduleFinish: '2024-05-03T17:00:00',
185
+ ScheduleDuration: 'P3D',
186
+ IsMilestone: false,
187
+ })
188
+ const tWallAB = bim.create.addIfcTask(h, {
189
+ Name: 'Install walls A+B',
190
+ PredefinedType: 'INSTALLATION',
191
+ ScheduleStart: '2024-05-06T08:00:00',
192
+ ScheduleFinish: '2024-05-10T17:00:00',
193
+ ScheduleDuration: 'P5D',
194
+ })
195
+ const tWallCD = bim.create.addIfcTask(h, {
196
+ Name: 'Install walls C+D',
197
+ PredefinedType: 'INSTALLATION',
198
+ ScheduleStart: '2024-05-13T08:00:00',
199
+ ScheduleFinish: '2024-05-17T17:00:00',
200
+ ScheduleDuration: 'P5D',
201
+ IsCritical: true,
202
+ })
203
+ const tHandover = bim.create.addIfcTask(h, {
204
+ Name: 'Handover',
205
+ PredefinedType: 'CONSTRUCTION',
206
+ ScheduleStart: '2024-05-20T08:00:00',
207
+ ScheduleFinish: '2024-05-20T17:00:00',
208
+ IsMilestone: true,
209
+ })
210
+
211
+ bim.create.assignTasksToWorkSchedule(h, schedule, [tFoundation, tWallAB, tWallCD, tHandover])
212
+ bim.create.assignProductsToTask(h, tWallAB, [wallA, wallB])
213
+ bim.create.assignProductsToTask(h, tWallCD, [wallC, wallD])
214
+
215
+ bim.create.addIfcRelSequence(h, tFoundation, tWallAB, { SequenceType: 'FINISH_START', TimeLag: 'P2D' })
216
+ bim.create.addIfcRelSequence(h, tWallAB, tWallCD, { SequenceType: 'FINISH_START' })
217
+ bim.create.addIfcRelSequence(h, tWallCD, tHandover, { SequenceType: 'FINISH_START' })
218
+
219
+ const result = bim.create.toIfc(h)
220
+ console.log(`[schedule] generated ${result.stats.entityCount} entities (${result.stats.fileSize} bytes)`)
221
+ bim.export.download(result.content, 'demo-with-schedule.ifc', 'model/ifc')
222
+ console.log('[schedule] downloaded demo-with-schedule.ifc — open it in this viewer to see the 4D Gantt panel animate the construction.')
223
+ }
@@ -24,6 +24,7 @@ import spaceValidation from './templates/space-validation.ts?raw';
24
24
  import federationCompare from './templates/federation-compare.ts?raw';
25
25
  import resetView from './templates/reset-view.ts?raw';
26
26
  import createBuilding from './templates/create-building.ts?raw';
27
+ import constructionSchedule from './templates/construction-schedule.ts?raw';
27
28
 
28
29
 
29
30
  export interface ScriptTemplate {
@@ -86,6 +87,12 @@ export const SCRIPT_TEMPLATES: ScriptTemplate[] = [
86
87
  'Developer — generate a complete IFC file with walls, slab, columns, beams, stair, and parametric timber gridshell roof with diamond lattice',
87
88
  code: stripModuleLine(createBuilding),
88
89
  },
90
+ {
91
+ name: 'Construction schedule (4D)',
92
+ description:
93
+ 'Scheduler — build an IfcWorkSchedule with IfcTasks, IfcRelSequence dependencies, and product assignments that drive the 4D Gantt animation. Accepts a CSV attachment for real task data.',
94
+ code: stripModuleLine(constructionSchedule),
95
+ },
89
96
  {
90
97
  name: 'Reset view',
91
98
  description: 'Utility — remove all color overrides and show all entities',
@@ -0,0 +1,36 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ /**
6
+ * Starter IFC type catalog used as a dropdown fallback when the active
7
+ * model's `entityIndex.byType` isn't yet populated (e.g. server-loaded
8
+ * stores without the on-demand maps). Once a model is loaded, the
9
+ * filter-schema layer surfaces only the types actually present so users
10
+ * don't waste time picking IfcBeam from a house model that doesn't have
11
+ * one.
12
+ */
13
+ export const COMMON_IFC_TYPES: readonly string[] = [
14
+ 'IfcWall',
15
+ 'IfcWallStandardCase',
16
+ 'IfcSlab',
17
+ 'IfcBeam',
18
+ 'IfcColumn',
19
+ 'IfcDoor',
20
+ 'IfcWindow',
21
+ 'IfcRoof',
22
+ 'IfcStair',
23
+ 'IfcStairFlight',
24
+ 'IfcRailing',
25
+ 'IfcRamp',
26
+ 'IfcSpace',
27
+ 'IfcCovering',
28
+ 'IfcCurtainWall',
29
+ 'IfcFooting',
30
+ 'IfcPlate',
31
+ 'IfcMember',
32
+ 'IfcOpeningElement',
33
+ 'IfcBuildingElementProxy',
34
+ 'IfcFurnishingElement',
35
+ 'IfcDistributionElement',
36
+ ];