@twinfinity/printing 6.1.1-beta → 6.1.2-ci.30738-beta

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 (157) hide show
  1. package/dist/BuildInfo.js +3 -3
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/layout/analyzeTemplate.d.ts +4 -4
  7. package/dist/layout/analyzeTemplate.d.ts.map +1 -1
  8. package/dist/layout/analyzeTemplate.js +18 -16
  9. package/dist/layout/analyzeTemplate.js.map +1 -1
  10. package/dist/layout/classClosure.d.ts +41 -0
  11. package/dist/layout/classClosure.d.ts.map +1 -0
  12. package/dist/layout/classClosure.js +143 -0
  13. package/dist/layout/classClosure.js.map +1 -0
  14. package/dist/layout/clipUtils.d.ts +11 -0
  15. package/dist/layout/clipUtils.d.ts.map +1 -1
  16. package/dist/layout/clipUtils.js +67 -6
  17. package/dist/layout/clipUtils.js.map +1 -1
  18. package/dist/layout/filters.d.ts +14 -8
  19. package/dist/layout/filters.d.ts.map +1 -1
  20. package/dist/layout/filters.js +28 -3
  21. package/dist/layout/filters.js.map +1 -1
  22. package/dist/layout/index.d.ts +24 -57
  23. package/dist/layout/index.d.ts.map +1 -1
  24. package/dist/layout/index.js +20 -337
  25. package/dist/layout/index.js.map +1 -1
  26. package/dist/layout/itemBuilders.d.ts +11 -0
  27. package/dist/layout/itemBuilders.d.ts.map +1 -1
  28. package/dist/layout/itemBuilders.js +17 -3
  29. package/dist/layout/itemBuilders.js.map +1 -1
  30. package/dist/layout/labelsRender.d.ts.map +1 -1
  31. package/dist/layout/labelsRender.js +15 -27
  32. package/dist/layout/labelsRender.js.map +1 -1
  33. package/dist/layout/legendRender.d.ts +18 -6
  34. package/dist/layout/legendRender.d.ts.map +1 -1
  35. package/dist/layout/legendRender.js +49 -79
  36. package/dist/layout/legendRender.js.map +1 -1
  37. package/dist/layout/metadata.d.ts.map +1 -1
  38. package/dist/layout/metadata.js +26 -5
  39. package/dist/layout/metadata.js.map +1 -1
  40. package/dist/layout/model.d.ts +4 -3
  41. package/dist/layout/model.d.ts.map +1 -1
  42. package/dist/layout/model.js +17 -57
  43. package/dist/layout/model.js.map +1 -1
  44. package/dist/layout/options.d.ts +1 -2
  45. package/dist/layout/options.d.ts.map +1 -1
  46. package/dist/layout/options.js.map +1 -1
  47. package/dist/layout/preflight.d.ts +32 -0
  48. package/dist/layout/preflight.d.ts.map +1 -0
  49. package/dist/layout/preflight.js +69 -0
  50. package/dist/layout/preflight.js.map +1 -0
  51. package/dist/layout/qrRender.d.ts.map +1 -1
  52. package/dist/layout/qrRender.js +11 -10
  53. package/dist/layout/qrRender.js.map +1 -1
  54. package/dist/layout/renderDrawing.d.ts +28 -17
  55. package/dist/layout/renderDrawing.d.ts.map +1 -1
  56. package/dist/layout/renderDrawing.js +107 -88
  57. package/dist/layout/renderDrawing.js.map +1 -1
  58. package/dist/layout/renderLayout.d.ts +25 -0
  59. package/dist/layout/renderLayout.d.ts.map +1 -0
  60. package/dist/layout/renderLayout.js +315 -0
  61. package/dist/layout/renderLayout.js.map +1 -0
  62. package/dist/layout/renderTemplateSheet.d.ts +99 -0
  63. package/dist/layout/renderTemplateSheet.d.ts.map +1 -0
  64. package/dist/layout/renderTemplateSheet.js +296 -0
  65. package/dist/layout/renderTemplateSheet.js.map +1 -0
  66. package/dist/layout/renderUtils.d.ts +19 -0
  67. package/dist/layout/renderUtils.d.ts.map +1 -1
  68. package/dist/layout/renderUtils.js +47 -4
  69. package/dist/layout/renderUtils.js.map +1 -1
  70. package/dist/layout/sectionDefs.d.ts +65 -0
  71. package/dist/layout/sectionDefs.d.ts.map +1 -0
  72. package/dist/layout/sectionDefs.js +88 -0
  73. package/dist/layout/sectionDefs.js.map +1 -0
  74. package/dist/layout/slabModelView.d.ts +34 -0
  75. package/dist/layout/slabModelView.d.ts.map +1 -0
  76. package/dist/layout/slabModelView.js +175 -0
  77. package/dist/layout/slabModelView.js.map +1 -0
  78. package/dist/layout/templateVariables.d.ts +1 -1
  79. package/dist/layout/templateVariables.d.ts.map +1 -1
  80. package/dist/layout/templateVariables.js +21 -9
  81. package/dist/layout/templateVariables.js.map +1 -1
  82. package/dist/layout/types.d.ts +164 -83
  83. package/dist/layout/types.d.ts.map +1 -1
  84. package/dist/layout/types.js.map +1 -1
  85. package/dist/layout/validation.d.ts.map +1 -1
  86. package/dist/layout/validation.js +78 -33
  87. package/dist/layout/validation.js.map +1 -1
  88. package/dist/layout/viewportPrep.d.ts +8 -6
  89. package/dist/layout/viewportPrep.d.ts.map +1 -1
  90. package/dist/layout/viewportPrep.js +35 -23
  91. package/dist/layout/viewportPrep.js.map +1 -1
  92. package/dist/layout/viewportRender.d.ts +9 -7
  93. package/dist/layout/viewportRender.d.ts.map +1 -1
  94. package/dist/layout/viewportRender.js +93 -126
  95. package/dist/layout/viewportRender.js.map +1 -1
  96. package/dist/layout/viewportUtils.d.ts +20 -0
  97. package/dist/layout/viewportUtils.d.ts.map +1 -1
  98. package/dist/layout/viewportUtils.js +107 -4
  99. package/dist/layout/viewportUtils.js.map +1 -1
  100. package/dist/printToPdf.d.ts +7 -1
  101. package/dist/printToPdf.d.ts.map +1 -1
  102. package/dist/printToPdf.js +81 -14
  103. package/dist/printToPdf.js.map +1 -1
  104. package/dist/printToSvg.d.ts.map +1 -1
  105. package/dist/printToSvg.js +7 -3
  106. package/dist/printToSvg.js.map +1 -1
  107. package/dist/schemaUtils.d.ts +9 -0
  108. package/dist/schemaUtils.d.ts.map +1 -0
  109. package/dist/schemaUtils.js +14 -0
  110. package/dist/schemaUtils.js.map +1 -0
  111. package/dist/templates/default-template.json +30 -8
  112. package/dist/types.d.ts +2 -1
  113. package/dist/types.d.ts.map +1 -1
  114. package/dist/types.js +10 -1
  115. package/dist/types.js.map +1 -1
  116. package/package.json +8 -3
  117. package/src/index.ts +4 -0
  118. package/src/layout/analyzeTemplate.ts +21 -19
  119. package/src/layout/classClosure.ts +142 -0
  120. package/src/layout/clipUtils.ts +65 -6
  121. package/src/layout/filters.ts +31 -3
  122. package/src/layout/index.ts +61 -571
  123. package/src/layout/itemBuilders.ts +20 -5
  124. package/src/layout/labelsRender.ts +23 -40
  125. package/src/layout/legendRender.ts +64 -84
  126. package/src/layout/metadata.ts +26 -5
  127. package/src/layout/model.ts +21 -66
  128. package/src/layout/options.ts +1 -2
  129. package/src/layout/preflight.ts +96 -0
  130. package/src/layout/qrRender.ts +11 -10
  131. package/src/layout/renderDrawing.ts +132 -110
  132. package/src/layout/renderLayout.ts +483 -0
  133. package/src/layout/renderTemplateSheet.ts +435 -0
  134. package/src/layout/renderUtils.ts +53 -4
  135. package/src/layout/sectionDefs.ts +131 -0
  136. package/src/layout/slabModelView.ts +196 -0
  137. package/src/layout/templateVariables.ts +25 -9
  138. package/src/layout/types.ts +160 -70
  139. package/src/layout/validation.ts +98 -32
  140. package/src/layout/viewportPrep.ts +47 -29
  141. package/src/layout/viewportRender.ts +114 -141
  142. package/src/layout/viewportUtils.ts +118 -5
  143. package/src/printToPdf.ts +84 -15
  144. package/src/printToSvg.ts +7 -3
  145. package/src/schemaUtils.ts +13 -0
  146. package/src/templates/default-template.json +30 -8
  147. package/src/types.ts +12 -2
  148. package/templates/default-a0-landscape.json +171 -66
  149. package/templates/default-a0-portrait.json +159 -60
  150. package/templates/default-a1-landscape.json +135 -48
  151. package/templates/default-a1-portrait.json +123 -42
  152. package/templates/default-a3-landscape.json +87 -24
  153. package/templates/default-a3-portrait.json +99 -30
  154. package/templates/default-a4-landscape.json +75 -18
  155. package/templates/default-a4-portrait.json +75 -18
  156. package/templates/llm-authoring-guide.md +247 -0
  157. package/templates/template-schema.json +295 -120
@@ -1,4 +1,4 @@
1
- import type { SectionPath, SectionLabel } from '@twinfinity/geometry';
1
+ import type { ClassBehaviorRule, SectionPath, SectionLabel } from '@twinfinity/geometry';
2
2
 
3
3
  export type PagePresetKey = 'a1' | 'a3' | 'a4';
4
4
  export type PageOrientation = 'portrait' | 'landscape';
@@ -23,22 +23,51 @@ export interface StyleMap {
23
23
  [styleName: string]: TextStyle;
24
24
  }
25
25
 
26
- export interface AssetSpec {
26
+ export interface ResourceSpec {
27
27
  id: string;
28
28
  src?: string;
29
29
  content?: string;
30
30
  }
31
31
 
32
+ /**
33
+ * Property-value filter narrowing a set of items *within* a class — the `where`
34
+ * of an include filter, a fill rule or a legend query. Templates use it to pick
35
+ * out "the IfcSpaces that are apartments" rather than all IfcSpaces.
36
+ *
37
+ * Each key is a short property path resolved against the item's property sets
38
+ * (e.g. `"BIP.spacetype"`; see `resolveProperty`). Each value is either a scalar,
39
+ * matched for equality, or an array, matched as any-of. Multiple keys are ANDed.
40
+ *
41
+ * String comparison on both sides is lowercased and trimmed, so `"Apartment"`,
42
+ * `"apartment"` and `" APARTMENT "` are the same condition. Numbers and booleans
43
+ * compare strictly — a property holding the string `"3"` does not match `3`.
44
+ *
45
+ * A key whose path resolves to nothing simply fails to match; it is not an error,
46
+ * so a typo'd path silently selects zero items rather than reporting itself.
47
+ */
32
48
  export type WhereCondition = Record<string, string | number | boolean | Array<string | number>>;
33
49
 
50
+ /**
51
+ * A whole-value variable binding, e.g. `"{{vars.cutHeight}}"`. On numeric
52
+ * fields that accept it, substitution preserves the variable's type (a
53
+ * number variable produces a number, not a string) — this is how template
54
+ * variables drive section placement.
55
+ */
56
+ export type VariableBinding = `{{vars.${string}}}`;
57
+
34
58
  export interface ClipConfig {
35
59
  class?: string | string[];
36
60
  where: WhereCondition;
37
- expandByM?: number;
61
+ expandBy?: number;
38
62
  clipLabels?: boolean;
39
- stroke?: string;
40
- strokeWidthMm?: number;
41
- strokeOpacity?: number;
63
+ /** Outline colour (same vocabulary as viewport lineStyles). */
64
+ color?: string;
65
+ /** Outline width in mm. */
66
+ widthMm?: number;
67
+ /** Outline opacity (0..1). */
68
+ opacity?: number;
69
+ /** SVG stroke-dasharray for the clip outline (e.g. '4 2'). */
70
+ dash?: string;
42
71
  fill?: string;
43
72
  fillOpacity?: number;
44
73
  }
@@ -65,7 +94,7 @@ export interface FillRule {
65
94
  /** Fill opacity (0–1). Default: 0.35. */
66
95
  fillOpacity?: number;
67
96
  /** When true, only apply fill to items whose centroid is spatially inside the clip polygon.
68
- * Useful when expandByM reveals adjacent spaces that shouldn't be filled.
97
+ * Useful when expandBy reveals adjacent spaces that shouldn't be filled.
69
98
  * @default false */
70
99
  matchClipFilter?: boolean;
71
100
  }
@@ -75,9 +104,14 @@ export interface HighlightConfig {
75
104
  where: WhereCondition;
76
105
  /** Only highlight items that also appear in the referenced viewport (i.e., intersect both planes). */
77
106
  intersectsViewport?: string;
78
- stroke?: string;
79
- strokeWidthMm?: number;
80
- strokeOpacity?: number;
107
+ /** Outline colour (same vocabulary as viewport lineStyles). */
108
+ color?: string;
109
+ /** Outline width in mm. */
110
+ widthMm?: number;
111
+ /** Outline opacity (0..1). */
112
+ opacity?: number;
113
+ /** SVG stroke-dasharray for highlighted outlines (e.g. '4 2'). */
114
+ dash?: string;
81
115
  fill?: string;
82
116
  fillOpacity?: number;
83
117
  }
@@ -118,24 +152,39 @@ export interface ViewportLineStyle {
118
152
  /**
119
153
  * Per-category line styles for a viewport.
120
154
  *
121
- * Resolution order: category-specific → `default` → built-in defaults.
155
+ * Resolution order: category-specific → `defaultVisibleLines`/`defaultHiddenLines`
156
+ * (by the category's visibility group) → built-in category defaults → `default`
157
+ * → built-in defaults.
158
+ *
159
+ * Visibility groups: `defaultVisibleLines` covers cutLines, visibleLines,
160
+ * silhouettesVisible, featureEdges and outlineVisible; `defaultHiddenLines`
161
+ * covers hiddenLines, silhouettesHidden and outlineHidden. `stairArrows` is an
162
+ * annotation and belongs to neither group.
122
163
  *
123
164
  * Example:
124
165
  * ```json
125
166
  * {
126
- * "default": { "widthMm": 0.01, "color": "#1f2937" },
127
- * "cutLines": { "widthMm": 0.02, "color": "#000000" },
128
- * "hiddenLines": { "widthMm": 0.005, "color": "#9ca3af", "dash": "4 2" }
167
+ * "default": { "widthMm": 0.01, "color": "#1f2937" },
168
+ * "defaultVisibleLines": { "widthMm": 0.1, "color": "#000000" },
169
+ * "defaultHiddenLines": { "widthMm": 0.05, "color": "#9ca3af", "dash": "4 2" },
170
+ * "cutLines": { "widthMm": 0.2 }
129
171
  * }
130
172
  * ```
131
173
  */
132
174
  export interface ViewportLineStyles {
133
175
  /** Fallback style for any category not explicitly listed. */
134
176
  default?: ViewportLineStyle;
177
+ /** Group default for all visible-class categories (cutLines, visibleLines, silhouettesVisible, featureEdges, outlineVisible). */
178
+ defaultVisibleLines?: ViewportLineStyle;
179
+ /** Group default for all hidden-class categories (hiddenLines, silhouettesHidden, outlineHidden). */
180
+ defaultHiddenLines?: ViewportLineStyle;
135
181
  cutLines?: ViewportLineStyle;
136
182
  visibleLines?: ViewportLineStyle;
137
183
  hiddenLines?: ViewportLineStyle;
138
- silhouettes?: ViewportLineStyle;
184
+ /** Visible silhouette / apparent-contour traces. */
185
+ silhouettesVisible?: ViewportLineStyle;
186
+ /** Occluded silhouette traces — inherits the hiddenLines group style (dashed). */
187
+ silhouettesHidden?: ViewportLineStyle;
139
188
  featureEdges?: ViewportLineStyle;
140
189
  stairArrows?: ViewportLineStyle;
141
190
  outlineVisible?: ViewportLineStyle;
@@ -147,7 +196,8 @@ export interface ViewportLineStyles {
147
196
  *
148
197
  * Can be:
149
198
  * - String or string array: class names only
150
- * - Object with class + where: property-based filtering
199
+ * - Object with class + where: property-based filtering, optionally carrying the
200
+ * per-class drawing-generation flags of {@link ClassBehaviorRule} (occludes/classify)
151
201
  * - Preset reference: { preset: "presetName" }
152
202
  *
153
203
  * Examples:
@@ -160,14 +210,18 @@ export interface ViewportLineStyles {
160
210
  export type IncludeClassesFilter =
161
211
  | string
162
212
  | string[]
163
- | { class?: string | string[]; where?: WhereCondition }
213
+ | (Partial<ClassBehaviorRule> & { where?: WhereCondition })
164
214
  | { preset: string };
165
215
 
166
216
  /**
167
217
  * Resolved include filter (after preset expansion).
168
- * Either a simple class name or a class+where filter.
218
+ * Either a simple class name or a class+where filter carrying the per-class
219
+ * drawing-generation flags of {@link ClassBehaviorRule}: `occludes: false` — the
220
+ * class's geometry hides nothing; `classify: false` — its lines skip hidden-line
221
+ * testing and draw as-is. Both default true; the flags a template carries and the
222
+ * flags SlabSection evaluates are the same declaration.
169
223
  */
170
- export type ResolvedIncludeFilter = string | { class?: string | string[]; where: WhereCondition };
224
+ export type ResolvedIncludeFilter = string | (Partial<ClassBehaviorRule> & { where?: WhereCondition });
171
225
 
172
226
  export interface ViewportElement extends BaseElement {
173
227
  kind: 'viewport';
@@ -183,31 +237,29 @@ export interface ViewportElement extends BaseElement {
183
237
  rotationDeg?: number;
184
238
  includeClasses?: IncludeClassesFilter | IncludeClassesFilter[];
185
239
  /**
186
- * Per-category line styles. When set, overrides `lineWidthMm`/`lineColor`.
187
- * Use `lineStyles.default` for a single style across all categories,
188
- * or specify individual categories (cutLines, hiddenLines, etc.).
240
+ * Per-category line styles. Use `lineStyles.default` for a single style
241
+ * across all categories, or specify individual categories
242
+ * (cutLines, hiddenLines, etc.).
189
243
  */
190
244
  lineStyles?: ViewportLineStyles;
191
- /** Simple shorthand: default line width for all categories. Overridden by `lineStyles`. */
192
- lineWidthMm?: number;
193
- /** Simple shorthand: default line color for all categories. Overridden by `lineStyles`. */
194
- lineColor?: string;
195
245
  /**
196
246
  * Fill rules controlling which products get filled polygons.
197
247
  * When absent, no fills are rendered (default: no fill).
198
248
  */
199
249
  fills?: FillRule[];
200
- northArrow?: { assetId: string; sizeMm?: number; offsetXMm?: number; offsetYMm?: number; rotationDeg?: number };
201
- border?: { stroke?: string; strokeWidthMm?: number; dashed?: boolean };
250
+ northArrow?: { resourceId: string; sizeMm?: number; offsetXMm?: number; offsetYMm?: number; rotationDeg?: number };
251
+ border?: { stroke?: string; strokeWidthMm?: number; dash?: string };
202
252
  clip?: ClipConfig;
203
253
  highlight?: HighlightConfig;
204
254
 
205
255
  // Section configuration (overrides app defaults if specified)
206
256
  /**
207
- * Override cutting plane height for horizontal plans (Y coordinate).
208
- * If omitted, uses app default. Shorthand for planeNormal=[0,1,0], planePosition=cutHeight.
257
+ * Override cutting plane height for horizontal plans (Y coordinate,
258
+ * metres). Shorthand for planeNormal=[0,1,0], planePosition=cutHeight.
259
+ * May be a variable binding ("{{vars.cutHeight}}" with a number
260
+ * variable) so end users control the cut through the variables UI.
209
261
  */
210
- cutHeight?: number;
262
+ cutHeight?: number | VariableBinding;
211
263
  /**
212
264
  * Override depth above/below cutting plane. If omitted, uses app default.
213
265
  * Only applicable for SLAB mode (PLANE mode doesn't use depth).
@@ -224,21 +276,39 @@ export interface ViewportElement extends BaseElement {
224
276
  */
225
277
  planeNormal?: [number, number, number];
226
278
  /**
227
- * Distance from origin along the (normalized) plane normal.
279
+ * Distance from origin along the (normalized) plane normal (metres).
228
280
  * Used with planeNormal to define the cutting plane.
229
281
  * The plane passes through the point: normalize(planeNormal) * planePosition.
282
+ * May be a variable binding like cutHeight.
230
283
  */
231
- planePosition?: number;
284
+ planePosition?: number | VariableBinding;
232
285
  /**
233
- * Section computation mode: 'slab' or 'plane'.
234
- * - 'slab': Optimized for horizontal floor plans. Uses depth above/below to include geometry.
235
- * - 'plane': Arbitrary plane cuts (vertical sections, diagonal sections). Computes exact intersection.
236
- *
237
- * If omitted, mode is auto-detected from plane orientation:
238
- * - Horizontal planes (planeNormal ≈ Y-axis) → 'slab'
239
- * - Vertical or diagonal planes → 'plane'
286
+ * Stair-arrow geometry options for plan viewports (marker shapes and run
287
+ * sizing). These shape the GENERATED arrow geometry stroke/color/width
288
+ * and hiding stay with `lineStyles.stairArrows`. Ignored in PLANE mode
289
+ * (elevations generate no stair arrows).
240
290
  */
241
- mode?: 'slab' | 'plane';
291
+ stairArrows?: ViewportStairArrowOptions;
292
+ }
293
+
294
+ /**
295
+ * Template surface for `SlabSectionStairArrowOptions` (product-geometry) —
296
+ * kept as its own type so the template schema and the geometry package can
297
+ * evolve independently; renderTemplateSheet forwards field-by-field.
298
+ */
299
+ export interface ViewportStairArrowOptions {
300
+ /** Marker at the run's bottom end (drawing-convention circle). Default 'filled'. */
301
+ startMarker?: 'filled' | 'open' | 'none';
302
+ /** Arrowhead at the run's top end. Default 'filled' (solid triangle). */
303
+ arrowhead?: 'filled' | 'outline' | 'open';
304
+ /** Fraction of the flight length the arrow occupies. */
305
+ lengthScale?: number;
306
+ /** Minimum arrow length in metres. */
307
+ minLength?: number;
308
+ /** Maximum arrow length in metres. */
309
+ maxLength?: number;
310
+ /** How far the walking line extends onto an un-anchored landing (metres). */
311
+ landingExtension?: number;
242
312
  }
243
313
 
244
314
  export interface TextElement extends BaseElement {
@@ -247,7 +317,6 @@ export interface TextElement extends BaseElement {
247
317
  yMm: number;
248
318
  textStyle?: string;
249
319
  text: string;
250
- maxWidthMm?: number;
251
320
  align?: 'left' | 'center' | 'right';
252
321
  }
253
322
 
@@ -257,7 +326,7 @@ export interface ImageElement extends BaseElement {
257
326
  yMm: number;
258
327
  widthMm: number;
259
328
  heightMm: number;
260
- assetId: string;
329
+ resourceId: string;
261
330
  fit?: 'contain' | 'cover' | 'stretch';
262
331
  }
263
332
 
@@ -269,7 +338,8 @@ export interface LineElement extends BaseElement {
269
338
  y2Mm: number;
270
339
  stroke?: string;
271
340
  strokeWidthMm?: number;
272
- dashed?: boolean;
341
+ /** SVG stroke-dasharray in mm, e.g. "4 2". */
342
+ dash?: string;
273
343
  }
274
344
 
275
345
  export interface RectElement extends BaseElement {
@@ -281,7 +351,8 @@ export interface RectElement extends BaseElement {
281
351
  stroke?: string;
282
352
  strokeWidthMm?: number;
283
353
  fill?: string;
284
- dashed?: boolean;
354
+ /** SVG stroke-dasharray in mm, e.g. "4 2". */
355
+ dash?: string;
285
356
  }
286
357
 
287
358
  export interface CircleElement extends BaseElement {
@@ -292,7 +363,8 @@ export interface CircleElement extends BaseElement {
292
363
  stroke?: string;
293
364
  strokeWidthMm?: number;
294
365
  fill?: string;
295
- dashed?: boolean;
366
+ /** SVG stroke-dasharray in mm, e.g. "4 2". */
367
+ dash?: string;
296
368
  }
297
369
 
298
370
  export interface PointMm {
@@ -305,7 +377,8 @@ export interface PolylineElement extends BaseElement {
305
377
  points: PointMm[];
306
378
  stroke: string;
307
379
  strokeWidthMm: number;
308
- dashed?: boolean;
380
+ /** SVG stroke-dasharray in mm, e.g. "4 2". */
381
+ dash?: string;
309
382
  }
310
383
 
311
384
  export interface PolygonElement extends BaseElement {
@@ -314,7 +387,8 @@ export interface PolygonElement extends BaseElement {
314
387
  stroke?: string;
315
388
  strokeWidthMm?: number;
316
389
  fill?: string;
317
- dashed?: boolean;
390
+ /** SVG stroke-dasharray in mm, e.g. "4 2". */
391
+ dash?: string;
318
392
  }
319
393
 
320
394
  export interface ScaleBarElement extends BaseElement {
@@ -350,7 +424,6 @@ export interface LabelsElement extends BaseElement {
350
424
  text: string;
351
425
  textStyle?: string;
352
426
  align?: 'left' | 'center' | 'right';
353
- maxWidthMm?: number;
354
427
  /** When true, only show labels for items whose position is spatially inside the clip polygon.
355
428
  * @default false */
356
429
  matchClipFilter?: boolean;
@@ -358,6 +431,12 @@ export interface LabelsElement extends BaseElement {
358
431
 
359
432
  export type LegendAnchor = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
360
433
 
434
+ /** Table line style — same stroke vocabulary as shape elements. */
435
+ export interface LegendLineStyle {
436
+ stroke?: string;
437
+ strokeWidthMm?: number;
438
+ }
439
+
361
440
  export interface LegendColumn {
362
441
  id: string;
363
442
  label: string;
@@ -388,12 +467,12 @@ export interface LegendElement extends BaseElement {
388
467
  showColorColumn?: boolean;
389
468
  colorColumnWidthMm?: number;
390
469
  cellPaddingMm?: number;
391
- borderStrokeWidthMm?: number;
392
- borderStrokeColor?: string;
393
- gridStrokeWidthMm?: number;
394
- gridStrokeColor?: string;
395
- headerStrokeWidthMm?: number;
396
- headerStrokeColor?: string;
470
+ /** Outer table border — same vocabulary as the viewport border. */
471
+ border?: LegendLineStyle;
472
+ /** Inner grid lines between rows/columns. */
473
+ grid?: LegendLineStyle;
474
+ /** Header separator (and summary separator) line. */
475
+ header?: LegendLineStyle;
397
476
  columns: LegendColumn[];
398
477
  /**
399
478
  * Summary row configuration.
@@ -621,14 +700,14 @@ export interface LayoutTemplate {
621
700
 
622
701
  page: PageSpec;
623
702
  styles?: StyleMap;
624
- assets?: AssetSpec[];
703
+ resources?: ResourceSpec[];
625
704
  elements: LayoutElement[];
626
705
  presets?: {
627
706
  includeClasses?: Record<string, string[]>;
628
707
  scales?: Record<string, { preferredScales?: number[] }>;
629
708
  };
630
- /** Allow fetching remote assets (images, fonts). Default: false. */
631
- allowRemoteAssets?: boolean;
709
+ /** Allow fetching remote resources (images, fonts). Default: false. */
710
+ allowRemoteResources?: boolean;
632
711
  }
633
712
 
634
713
  export interface ModelMetadataEntry {
@@ -703,9 +782,15 @@ export type ViewportItemsMap = Record<string, { items: NormalizedProductItem[] }
703
782
  export type LayoutDataViewports = { viewports: ViewportItemsMap } & Record<string, any>;
704
783
 
705
784
  export interface ValidationOptions {
706
- allowRemoteAssets?: boolean;
785
+ allowRemoteResources?: boolean;
707
786
  allowDataUrls?: boolean;
708
787
  maxViewports?: number;
788
+ /**
789
+ * Treat an `image.resourceId` that names no declared resource as an error. Off by default:
790
+ * `renderLayout` throws on validation errors, so switching this on mid-render turns one missing
791
+ * logo into no print at all. Authoring tools want it on; rendering paths do not.
792
+ */
793
+ strictResourceRefs?: boolean;
709
794
  }
710
795
 
711
796
  export interface ValidationIssue {
@@ -750,7 +835,7 @@ export interface RenderDrawingInput {
750
835
  */
751
836
  models?: ModelContext;
752
837
  options?: {
753
- allowRemoteAssets?: boolean;
838
+ allowRemoteResources?: boolean;
754
839
  qrContext?: {
755
840
  host?: string | null;
756
841
  containerName?: string | null;
@@ -775,6 +860,8 @@ export interface RenderDrawingInput {
775
860
  *
776
861
  * Each entry needs a `product` (BIM object with gid, name, class, properties)
777
862
  * and `polylines` (for centroid computation and fill polygon rendering).
863
+ * Either one flat list applied to every viewport, or a record keyed by
864
+ * viewport id when viewports show different cuts.
778
865
  *
779
866
  * When provided, renderDrawing builds NormalizedProductItems per viewport,
780
867
  * resolving fill colors from each viewport's fill rules. This replaces
@@ -782,10 +869,7 @@ export interface RenderDrawingInput {
782
869
  *
783
870
  * Ignored when `viewportItems` is also provided (explicit items take priority).
784
871
  */
785
- productEntries?: Array<{
786
- product: unknown;
787
- polylines: Array<{ points: Array<{ x: number; z: number }> }>;
788
- }>;
872
+ productEntries?: ProductPolylineEntry[] | Record<string, ProductPolylineEntry[]>;
789
873
  /**
790
874
  * Pre-built product items when `models` is provided directly.
791
875
  * Keyed by viewport ID, each containing an array of NormalizedProductItems.
@@ -795,13 +879,13 @@ export interface RenderDrawingInput {
795
879
  */
796
880
  viewportItems?: Record<string, { items: NormalizedProductItem[] }>;
797
881
  /**
798
- * App default section settings. Used as fallback when viewports don't specify
799
- * their own cutHeight/depth configuration.
882
+ * gid class/property metadata for products beyond the entry lists. Entries
883
+ * only cover cut-bearing products, but render-time includeClasses filtering
884
+ * must classify every product with drawable lines — without this map, products
885
+ * whose geometry never crosses the cut (furniture below a plan cut) lose their
886
+ * visible/hidden lines. Entry-derived metadata overrides on shared gids.
800
887
  */
801
- sectionDefaults?: {
802
- cutHeight?: number;
803
- depth?: { above?: number; below?: number };
804
- };
888
+ metadataById?: ModelMetadata;
805
889
  /**
806
890
  * Template variable values.
807
891
  *
@@ -829,6 +913,12 @@ export interface RenderDrawingInput {
829
913
  };
830
914
  }
831
915
 
916
+ /** Raw per-product item-data entry: the product plus its cut polylines in world x/z. */
917
+ export interface ProductPolylineEntry {
918
+ product: unknown;
919
+ polylines: Array<{ points: Array<{ x: number; z: number }> }>;
920
+ }
921
+
832
922
  export interface RenderDrawingResult {
833
923
  svg: string;
834
924
  warnings: string[];