@seatlayer/core 0.96.0 → 0.97.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 (123) hide show
  1. package/dist/ar-Q44JP5JY.js +1 -0
  2. package/dist/be-CGFFSIQL.js +1 -0
  3. package/dist/bg-WOYK6OLH.js +1 -0
  4. package/dist/ca-77ZVI3X5.js +1 -0
  5. package/dist/chunk-2P72QUJR.js +1 -0
  6. package/dist/chunk-5N4H3KMR.js +1 -0
  7. package/dist/chunk-ASIIXY5M.js +1 -0
  8. package/dist/{chunk-O3DGXAIC.js → chunk-CUACREZL.js} +1 -1
  9. package/dist/{chunk-CEIVHWRB.js → chunk-FLMKHAUT.js} +1 -1
  10. package/dist/{chunk-TKYTTEJ2.js → chunk-IW7QZIMF.js} +1 -1
  11. package/dist/chunk-M5VINTGE.js +1 -0
  12. package/dist/chunk-NGZXKXOY.js +1 -0
  13. package/dist/{chunk-U7CVRE4P.js → chunk-OLGPAFXW.js} +1 -1
  14. package/dist/{chunk-M5X6G7FD.js → chunk-P4C24CIZ.js} +1 -1
  15. package/dist/{chunk-A3ZL3R75.js → chunk-QEPYNCBJ.js} +1 -1
  16. package/dist/chunk-VAI2VDQR.js +1 -0
  17. package/dist/{chunk-Q3MSDG4S.js → chunk-YPESNMTC.js} +1 -1
  18. package/dist/chunk-Z43H6AWN.js +1 -0
  19. package/dist/core/chart-ops/index.cjs +1 -1
  20. package/dist/core/chart-ops/index.d.cts +40 -18
  21. package/dist/core/chart-ops/index.d.ts +40 -18
  22. package/dist/core/chart-ops/index.js +1 -1
  23. package/dist/core/inventory/index.cjs +1 -1
  24. package/dist/core/inventory/index.js +1 -1
  25. package/dist/core/layout/index.cjs +1 -1
  26. package/dist/core/layout/index.js +1 -1
  27. package/dist/core/quality/index.js +1 -1
  28. package/dist/core/render-assets/index.js +1 -1
  29. package/dist/core/sections/index.js +1 -1
  30. package/dist/cs-OSBZYCSR.js +1 -0
  31. package/dist/cy-ZCOJW2WH.js +1 -0
  32. package/dist/da-2PDK6JTR.js +1 -0
  33. package/dist/de-R5LLVFUU.js +1 -0
  34. package/dist/el-ZPFVDCWA.js +1 -0
  35. package/dist/es-7YASJP32.js +1 -0
  36. package/dist/et-J4TV6KQL.js +1 -0
  37. package/dist/fa-4TEO7UGM.js +1 -0
  38. package/dist/fi-GIUDDKMH.js +1 -0
  39. package/dist/fr-J5J2XJLA.js +1 -0
  40. package/dist/he-OCEHSVUJ.js +1 -0
  41. package/dist/hi-EK5CTBW5.js +1 -0
  42. package/dist/hr-SLDTQOYC.js +1 -0
  43. package/dist/hu-2QNE77NO.js +1 -0
  44. package/dist/id-LGDAFQJK.js +1 -0
  45. package/dist/index.cjs +1 -1
  46. package/dist/index.d.cts +8 -16
  47. package/dist/index.d.ts +8 -16
  48. package/dist/index.js +1 -1
  49. package/dist/it-DT4Y3IYB.js +1 -0
  50. package/dist/ja-D5EY2XCQ.js +1 -0
  51. package/dist/ko-DD2NV45Q.js +1 -0
  52. package/dist/ku-KZCMVLBE.js +1 -0
  53. package/dist/localeLoaders-GGAKX22E.js +1 -0
  54. package/dist/lt-QWGTJ47Y.js +1 -0
  55. package/dist/lv-LYAIG3VK.js +1 -0
  56. package/dist/ms-XTF4KNGD.js +1 -0
  57. package/dist/nl-QEXY6XHS.js +1 -0
  58. package/dist/no-HCOXN2CN.js +1 -0
  59. package/dist/pl-BWY53TSD.js +1 -0
  60. package/dist/pt-2UJUBCPL.js +1 -0
  61. package/dist/ro-GGXOLTED.js +1 -0
  62. package/dist/ru-ZTFK3WCU.js +1 -0
  63. package/dist/sk-KU543Y2U.js +1 -0
  64. package/dist/sl-FT576R7A.js +1 -0
  65. package/dist/sr-WE3J46JE.js +1 -0
  66. package/dist/stage-CKb7aNoH.d.cts +18 -0
  67. package/dist/stage-CKb7aNoH.d.ts +18 -0
  68. package/dist/sv-YEAOPSEB.js +1 -0
  69. package/dist/th-BEBRDHJA.js +1 -0
  70. package/dist/tr-LOAHUPSH.js +1 -0
  71. package/dist/uk-2GMICSHN.js +1 -0
  72. package/dist/vi-TC5B6AUR.js +1 -0
  73. package/dist/view3d/index.cjs +241 -78
  74. package/dist/view3d/index.d.cts +146 -78
  75. package/dist/view3d/index.d.ts +146 -78
  76. package/dist/view3d/index.js +239 -76
  77. package/dist/view3d/scene/scene.worker.cjs +1 -1
  78. package/dist/view3d/scene/scene.worker.js +1 -1
  79. package/dist/zh-Hans-TSZWTZQY.js +1 -0
  80. package/dist/zh-Hant-TLB4FZYM.js +1 -0
  81. package/package.json +1 -1
  82. package/dist/ar-3S65PDDG.js +0 -1
  83. package/dist/be-WJKGEBTI.js +0 -1
  84. package/dist/bg-TZUF36MP.js +0 -1
  85. package/dist/ca-WLW64J7W.js +0 -1
  86. package/dist/chunk-F2EXXZSZ.js +0 -1
  87. package/dist/chunk-F7TP67LK.js +0 -1
  88. package/dist/chunk-LAX7F5ML.js +0 -1
  89. package/dist/chunk-LFJUXTIO.js +0 -1
  90. package/dist/chunk-M7JA4BGP.js +0 -1
  91. package/dist/cs-HQXANWJA.js +0 -1
  92. package/dist/cy-EG5BJOG7.js +0 -1
  93. package/dist/da-5XEBRUEE.js +0 -1
  94. package/dist/de-SCVAU32D.js +0 -1
  95. package/dist/el-KBW7YAF5.js +0 -1
  96. package/dist/es-IFLC65KX.js +0 -1
  97. package/dist/et-OXB22VMP.js +0 -1
  98. package/dist/fa-GFAZXHP6.js +0 -1
  99. package/dist/fi-AI67VYYH.js +0 -1
  100. package/dist/fr-V3RG2KYP.js +0 -1
  101. package/dist/he-J3I6MRUR.js +0 -1
  102. package/dist/hr-SA4WZ3AG.js +0 -1
  103. package/dist/hu-TM35NZ4U.js +0 -1
  104. package/dist/it-E4QYIYC4.js +0 -1
  105. package/dist/ja-S5M7EINH.js +0 -1
  106. package/dist/ku-DNZQIUUG.js +0 -1
  107. package/dist/localeLoaders-JTNNRDK2.js +0 -1
  108. package/dist/lt-ETQDX2HL.js +0 -1
  109. package/dist/lv-FYFIWI4F.js +0 -1
  110. package/dist/nl-XOG5SBZQ.js +0 -1
  111. package/dist/no-7UGUTFXW.js +0 -1
  112. package/dist/pl-5HR7DQIK.js +0 -1
  113. package/dist/pt-L4CCONDZ.js +0 -1
  114. package/dist/ro-KZVPOCZ6.js +0 -1
  115. package/dist/ru-CD7HYORB.js +0 -1
  116. package/dist/sk-AQZOHJYW.js +0 -1
  117. package/dist/sl-XYRITXI6.js +0 -1
  118. package/dist/sr-6VTXFVHT.js +0 -1
  119. package/dist/sv-EJWP7WJV.js +0 -1
  120. package/dist/tr-VKVADTIZ.js +0 -1
  121. package/dist/uk-QSJV3LDS.js +0 -1
  122. package/dist/zh-Hans-2FN4LFAW.js +0 -1
  123. package/dist/zh-Hant-5T2AB4FR.js +0 -1
@@ -1,6 +1,7 @@
1
- import { C as ChartDoc } from '../types-BbqhOJ5L.cjs';
1
+ import { P as Point, C as ChartDoc } from '../types-BbqhOJ5L.cjs';
2
2
  import { E as EventConfigurationProductionElementKind, a as EventConfigurationOcclusion, b as EventConfigurationVersion } from '../eventConfigurations-BE0rFmbQ.cjs';
3
3
  import { E as ExpandedSeat } from '../renderer-DEnthjgs.cjs';
4
+ import { S as StageKind } from '../stage-CKb7aNoH.cjs';
4
5
  import { SeatView } from './crossfade/panorama.cjs';
5
6
 
6
7
  /**
@@ -47,6 +48,55 @@ declare const STRUCTURE: {
47
48
  readonly tableWall: RGB;
48
49
  };
49
50
 
51
+ /**
52
+ * Pure geometry primitives for the view3d scene — no OGL, no DOM, so the whole
53
+ * scene-model builder is unit-testable in a plain runtime.
54
+ *
55
+ * Coordinate convention: chart units (x, y) map to world metres as
56
+ * worldX = x * METRES_PER_CHART_UNIT
57
+ * worldZ = y * METRES_PER_CHART_UNIT
58
+ * worldY = up (height in metres)
59
+ * i.e. the chart's audience-depth (+y) becomes world +Z, and Y is the vertical.
60
+ */
61
+
62
+ interface MeshData {
63
+ /** Non-indexed triangle soup: 3 floats per vertex. */
64
+ position: Float32Array;
65
+ normal: Float32Array;
66
+ /** Baked vertex colour incl. AO, 3 floats per vertex. */
67
+ color: Float32Array;
68
+ /**
69
+ * Owning floor index per vertex.
70
+ *
71
+ * Lets one merged mesh be dimmed per floor without splitting it into a draw
72
+ * call per floor. A multi-floor chart (the opera house has three) draws every
73
+ * floor at once, so the balcony sits over the parterre and hides it; isolating
74
+ * one is the only way to look at the level you are actually booking.
75
+ */
76
+ floor: Float32Array;
77
+ /**
78
+ * Small renderer material class per vertex:
79
+ * 0 = ordinary structure, 1 = authored powered display,
80
+ * 2 = row riser, 3 = row tread, 4 = football turf, 5 = generated concrete.
81
+ */
82
+ material: Float32Array;
83
+ /** Vertex count (position.length / 3). */
84
+ count: number;
85
+ }
86
+
87
+ interface SharedAisleCandidate {
88
+ sections: [string, string];
89
+ /** Block IDs are local to each section, paired in the same endpoint order. */
90
+ blocks?: [number, number];
91
+ floorIndex: number;
92
+ ends: [Point, Point];
93
+ /** Same-level clear width after reserving furniture space at both ends. */
94
+ clearWidthM: number;
95
+ heightM: number;
96
+ /** Chart-space footprint; a proposal, not an authored circulation route. */
97
+ outline: Point[];
98
+ }
99
+
50
100
  /**
51
101
  * Resolve a chart's authored theme into the 3D scene's colours.
52
102
  *
@@ -124,48 +174,14 @@ interface SceneLabel {
124
174
  anchor: [number, number, number];
125
175
  /** Authored colour (`#rrggbb`), when the object carries one. */
126
176
  color?: string;
177
+ /** Physical chair width, used to reveal numbers only at readable scale. */
178
+ seatWidthM?: number;
127
179
  /** Authored rotation in degrees, for annotations that specify one. */
128
180
  rotation?: number;
129
181
  /** Owning physical level, so a focused floor never keeps another level's text. */
130
182
  floorIndex?: number;
131
183
  }
132
184
 
133
- /**
134
- * Pure geometry primitives for the view3d scene — no OGL, no DOM, so the whole
135
- * scene-model builder is unit-testable in a plain runtime.
136
- *
137
- * Coordinate convention: chart units (x, y) map to world metres as
138
- * worldX = x * METRES_PER_CHART_UNIT
139
- * worldZ = y * METRES_PER_CHART_UNIT
140
- * worldY = up (height in metres)
141
- * i.e. the chart's audience-depth (+y) becomes world +Z, and Y is the vertical.
142
- */
143
-
144
- interface MeshData {
145
- /** Non-indexed triangle soup: 3 floats per vertex. */
146
- position: Float32Array;
147
- normal: Float32Array;
148
- /** Baked vertex colour incl. AO, 3 floats per vertex. */
149
- color: Float32Array;
150
- /**
151
- * Owning floor index per vertex.
152
- *
153
- * Lets one merged mesh be dimmed per floor without splitting it into a draw
154
- * call per floor. A multi-floor chart (the opera house has three) draws every
155
- * floor at once, so the balcony sits over the parterre and hides it; isolating
156
- * one is the only way to look at the level you are actually booking.
157
- */
158
- floor: Float32Array;
159
- /**
160
- * Small renderer material class per vertex:
161
- * 0 = ordinary structure, 1 = authored powered display,
162
- * 2 = row riser, 3 = row tread.
163
- */
164
- material: Float32Array;
165
- /** Vertex count (position.length / 3). */
166
- count: number;
167
- }
168
-
169
185
  /**
170
186
  * Pure builder for the instanced seat cloud. Produces the per-instance arrays a
171
187
  * single OGL InstancedMesh consumes (one draw call for every seat), plus the
@@ -216,6 +232,8 @@ interface SeatInstanceData {
216
232
  iRing: Float32Array;
217
233
  /** float per instance: owning floor index, for per-floor isolation. */
218
234
  iFloor: Float32Array;
235
+ /** float per instance: owning section's index in SceneModel.sections, -1 = none. */
236
+ iSection: Float32Array;
219
237
  /**
220
238
  * float per instance: facing yaw in radians, for the near-field chair mesh.
221
239
  *
@@ -313,6 +331,11 @@ interface SceneSection {
313
331
  center: [number, number, number];
314
332
  /** Half-diagonal of its seat footprint, world metres (camera fit). */
315
333
  radius: number;
334
+ /** Seat envelope including furniture height, used for projected camera fitting. */
335
+ box?: {
336
+ min: [number, number, number];
337
+ max: [number, number, number];
338
+ };
316
339
  /** What this section faces — the camera approaches from this side. */
317
340
  focalWorld: [number, number, number];
318
341
  }
@@ -350,6 +373,8 @@ interface SectionSolidRange {
350
373
  count: number;
351
374
  }
352
375
  interface SceneModel {
376
+ /** Geometric proposals only; not verified routes or rendered architecture. */
377
+ sharedAisles?: SharedAisleCandidate[];
353
378
  /** Every non-seat surface merged into one triangle soup (1 draw call). */
354
379
  solids: MeshData;
355
380
  /**
@@ -362,6 +387,8 @@ interface SceneModel {
362
387
  */
363
388
  sectionSolidRanges: SectionSolidRange[];
364
389
  seats: SeatInstanceData;
390
+ /** Physical section ownership in input-seat order; absent on older prepared models. */
391
+ seatSectionIds?: Array<string | null>;
365
392
  bounds: {
366
393
  /** World-metre venue centre (camera target). */
367
394
  center: [number, number, number];
@@ -385,6 +412,12 @@ interface SceneModel {
385
412
  center: [number, number, number];
386
413
  radius: number;
387
414
  };
415
+ /** Everything drawn, including the site around the venue: camera clipping
416
+ * only. Absent on models built before the site existed. */
417
+ clipBounds?: {
418
+ center: [number, number, number];
419
+ radius: number;
420
+ };
388
421
  /** 5 × vec3 flat LUT for the seat fragment shader. */
389
422
  stateColorLUT: number[];
390
423
  /** Resolved colours for this chart's authored theme (background, seat scale). */
@@ -438,33 +471,6 @@ interface SceneModelInput {
438
471
  initialState?: (seat: ExpandedSeat) => SeatState3D;
439
472
  }
440
473
 
441
- /**
442
- * The JS-side source of truth for the 3D scene — a pure, GPU-free description
443
- * built once from the chart's existing height contract. Everything the renderer
444
- * uploads (merged solid geometry, the instanced seat cloud, camera-framing
445
- * bounds, the seat-state colour LUT) is derived here, so it survives a WebGL
446
- * context loss: on `webglcontextrestored` the renderer simply re-uploads from
447
- * this model without recomputing anything.
448
- *
449
- * Feeds 100% from `sectionGeometry` / `Floor.baseHeightM` / `ExpandedSeat`
450
- * (docs/3d-program-workorder §Architecture) — no new chart data is invented.
451
- *
452
- * This module is the ORCHESTRATOR and the public face of `scene/model/`: it
453
- * sequences the passes and re-exports every type and helper the rest of the
454
- * codebase, the tests and the SDK import from `scene/sceneModel`. The passes
455
- * themselves live in `scene/model/` — see `docs/architecture` for the layering:
456
- *
457
- * types the shapes everything below is described in
458
- * paint AO + how an authored colour becomes an architectural tone
459
- * footprints configuration filtering, floor units, plan-space polygons
460
- * shapeArchitecture décor vocabulary → architecture, and coplanar claims
461
- * objectBuilders one prism per booth / table / shape / décor / GA area
462
- * tiers per-section decks and the per-floor bowl
463
- * labels zones, sections, rows and everything worth naming
464
- * floors per-level boxes, and the per-seat floor attribute
465
- * bounds chart footprint, ground datum, render + overview volumes
466
- */
467
-
468
474
  declare function buildSceneModel(input: SceneModelInput): SceneModel;
469
475
 
470
476
  /**
@@ -487,12 +493,75 @@ type Analytics3DCallback = (event: string, props?: Record<string, unknown>) => v
487
493
  */
488
494
  type Scene3DPrepSource = 'worker' | 'main' | 'inline';
489
495
 
496
+ interface AutoVenueSection {
497
+ id: string;
498
+ /** Owning floor on a multi-floor chart. */
499
+ floorId?: string;
500
+ /** Surface the estimate implies: stepped rows, or a level deck. */
501
+ surfaceKind: 'flat' | 'rakedRows';
502
+ height: number;
503
+ rake: number;
504
+ /** Section this one continues from, when it stands behind another. */
505
+ stackedOn?: string;
506
+ }
507
+ interface AutoVenueReport {
508
+ /** Shape id treated as the stage and whether that was inferred; `deck`
509
+ * when an unmarked shape was given the stage role. */
510
+ stage?: {
511
+ id: string;
512
+ inferred: boolean;
513
+ floorId?: string;
514
+ deck?: boolean;
515
+ field?: StageKind;
516
+ };
517
+ focalInferred: boolean;
518
+ /** The facing point each floor was given, where it was moved to the stage. */
519
+ focal?: {
520
+ floorId?: string;
521
+ point: Point;
522
+ }[];
523
+ /**
524
+ * The estimate knows what the audience looks at: a stage (drawn or found)
525
+ * or a focal point the organizer placed. Without either, heights are a
526
+ * guess and buyers keep the flat venue.
527
+ */
528
+ confident: boolean;
529
+ sections: AutoVenueSection[];
530
+ /** Free-standing row blocks given a hidden section in the 3D copy only. */
531
+ looseRowBlocks?: number;
532
+ /** Plain shapes given the role their label names (a Bar, the WC, a Screen). */
533
+ roles?: {
534
+ id: string;
535
+ floorId?: string;
536
+ role: string;
537
+ }[];
538
+ }
539
+ /** Derive a 3D-ready copy of `doc`; see the module comment for the rules. */
540
+ declare function autoVenue3d(doc: ChartDoc, defaultFocal?: Point): {
541
+ doc: ChartDoc;
542
+ report: AutoVenueReport;
543
+ };
544
+
545
+ interface EstimatedVenue3D {
546
+ doc: ChartDoc;
547
+ report: AutoVenueReport;
548
+ /** Per seat, in input order: eye height (NaN = unset). */
549
+ eyeHeightM: Float64Array;
550
+ /** Per seat, in input order: facing point x, y (NaN = unset). */
551
+ focal: Float64Array;
552
+ }
553
+ /** The estimate to render for `doc`, or null to render the chart as saved. */
554
+ declare function estimateVenue3D(doc: ChartDoc, seats: readonly ExpandedSeat[]): EstimatedVenue3D | null;
555
+
490
556
  interface PreparedVenue3D {
491
557
  model: SceneModel;
492
558
  buildMs: number;
493
559
  /** Reported on `3d_opened` as `prepSource`. `inline` is not reachable here —
494
560
  * it is what `mountVenue3D` reports when no prepared scene was handed in. */
495
561
  source: Exclude<Scene3DPrepSource, 'inline'>;
562
+ /** The estimated venue the model was built from; `mountVenue3D` mounts it
563
+ * in place of the saved chart, with each seat's eye height and facing point. */
564
+ estimate?: EstimatedVenue3D;
496
565
  }
497
566
  interface PrepareVenue3DInput {
498
567
  doc: ChartDoc;
@@ -501,6 +570,8 @@ interface PrepareVenue3DInput {
501
570
  /** Exact content delivered only with the lazy 3D request. */
502
571
  eventConfiguration?: EventConfigurationVersion;
503
572
  registeredShellGlb?: ArrayBuffer;
573
+ /** False renders the chart exactly as saved, with no estimated heights. */
574
+ estimate?: boolean;
504
575
  }
505
576
  type PrepareVenue3DFromChartInput = Omit<PrepareVenue3DInput, 'seats'>;
506
577
  /** Designer-friendly result: expansion and scene compilation both happened
@@ -706,6 +777,9 @@ interface Venue3DInput {
706
777
  initialState?: (seat: ExpandedSeat) => SeatState3D;
707
778
  /** CPU scene prepared by `prepareVenue3D`; avoids rebuilding on mount. */
708
779
  prepared?: PreparedVenue3D;
780
+ /** False renders the chart exactly as saved, with no estimated heights.
781
+ * Ignored with `prepared`, which already made that choice. */
782
+ estimate?: boolean;
709
783
  }
710
784
  interface Venue3DOptions {
711
785
  /** Fired on a tap that hits a seat (GPU color-pick). Not fired on empty taps. */
@@ -795,6 +869,8 @@ interface Venue3DOptions {
795
869
  * contain framing; validated for the buyer across `/dev/3d` fixtures.
796
870
  */
797
871
  portraitOverviewCrop?: boolean;
872
+ /** Optional authored presentation angle; stage-derived orientation otherwise wins. */
873
+ overviewAzimuthDeg?: number;
798
874
  /** Start on the final overview pose without the decorative stand-up intro.
799
875
  * Intended for deterministic rendered review and screenshot capture. */
800
876
  skipInitialOverviewAnimation?: boolean;
@@ -824,6 +900,8 @@ interface Venue3DOptions {
824
900
 
825
901
  interface Venue3DStats extends RenderLoopStats {
826
902
  drawCalls: number;
903
+ /** Submitted fallback triangles, including collapsed bays; excludes near chairs. */
904
+ fallbackTriangles?: number;
827
905
  seatCount: number;
828
906
  }
829
907
  interface Venue3DHandle {
@@ -861,6 +939,9 @@ interface Venue3DHandle {
861
939
  resize(): void;
862
940
  stats(): Venue3DStats;
863
941
  /** Machine-readable evidence from the exact parked WebGL frame and DOM labels. */
942
+ /** The current view as a JPEG data URL, longest edge at most `maxEdge` px
943
+ * (default 1280); null when the GPU context is gone. */
944
+ captureImage(maxEdge?: number): string | null;
864
945
  getQualityEvidence(): Venue3DQualityEvidence;
865
946
  getQualityReport(): Venue3DQualityReport;
866
947
  loseContextForTest(): void;
@@ -909,19 +990,6 @@ interface Venue3DHandle {
909
990
  focusFloor(index: number | null): boolean;
910
991
  }
911
992
 
912
- /**
913
- * view3d — the sole dynamic-import boundary for the lazy OGL venue-view chunk.
914
- *
915
- * const { mountVenue3D } = await import('../view3d');
916
- * const handle = mountVenue3D(container, { doc, seats }, { onSeatPick, getSeatView });
917
- * await handle.flyToSeat(seatId);
918
- *
919
- * Read-only 3D of any chart, fed entirely from the existing height contract.
920
- * Slice 1: orbit camera, extruded tiers/stage/GA, instanced seat dots, sub-range
921
- * availability, dispose + context-loss survival. Slice 2: GPU color-pick. Slice
922
- * 3: the fly-to-seat cinematic that dissolves into the view-from-seat panorama.
923
- */
924
-
925
993
  declare function mountVenue3D(container: HTMLElement, input: Venue3DInput, opts?: Venue3DOptions): Venue3DHandle;
926
994
 
927
- export { type Analytics3DCallback, type PreparedVenue3D, type PreparedVenue3DFromChart, type Scene3DPrepSource, type SeatState3D, SeatView, type SeatViewStopName, VENUE3D_QUALITY_REPORT_VERSION, type Venue3DHandle, type Venue3DInput, type Venue3DOptions, type Venue3DQualityEvidence, type Venue3DQualityReport, type Venue3DStats, buildSceneModel, inspectVenue3DQualityEvidence, mountVenue3D, prepareVenue3D, prepareVenue3DFromChart };
995
+ export { type Analytics3DCallback, type AutoVenueReport, type PreparedVenue3D, type PreparedVenue3DFromChart, type Scene3DPrepSource, type SeatState3D, SeatView, type SeatViewStopName, VENUE3D_QUALITY_REPORT_VERSION, type Venue3DHandle, type Venue3DInput, type Venue3DOptions, type Venue3DQualityEvidence, type Venue3DQualityReport, type Venue3DStats, autoVenue3d, buildSceneModel, estimateVenue3D, inspectVenue3DQualityEvidence, mountVenue3D, prepareVenue3D, prepareVenue3DFromChart };
@@ -1,6 +1,7 @@
1
- import { C as ChartDoc } from '../types-BbqhOJ5L.js';
1
+ import { P as Point, C as ChartDoc } from '../types-BbqhOJ5L.js';
2
2
  import { E as EventConfigurationProductionElementKind, a as EventConfigurationOcclusion, b as EventConfigurationVersion } from '../eventConfigurations-BEyHDxBT.js';
3
3
  import { E as ExpandedSeat } from '../renderer-CuXYGgR3.js';
4
+ import { S as StageKind } from '../stage-CKb7aNoH.js';
4
5
  import { SeatView } from './crossfade/panorama.js';
5
6
 
6
7
  /**
@@ -47,6 +48,55 @@ declare const STRUCTURE: {
47
48
  readonly tableWall: RGB;
48
49
  };
49
50
 
51
+ /**
52
+ * Pure geometry primitives for the view3d scene — no OGL, no DOM, so the whole
53
+ * scene-model builder is unit-testable in a plain runtime.
54
+ *
55
+ * Coordinate convention: chart units (x, y) map to world metres as
56
+ * worldX = x * METRES_PER_CHART_UNIT
57
+ * worldZ = y * METRES_PER_CHART_UNIT
58
+ * worldY = up (height in metres)
59
+ * i.e. the chart's audience-depth (+y) becomes world +Z, and Y is the vertical.
60
+ */
61
+
62
+ interface MeshData {
63
+ /** Non-indexed triangle soup: 3 floats per vertex. */
64
+ position: Float32Array;
65
+ normal: Float32Array;
66
+ /** Baked vertex colour incl. AO, 3 floats per vertex. */
67
+ color: Float32Array;
68
+ /**
69
+ * Owning floor index per vertex.
70
+ *
71
+ * Lets one merged mesh be dimmed per floor without splitting it into a draw
72
+ * call per floor. A multi-floor chart (the opera house has three) draws every
73
+ * floor at once, so the balcony sits over the parterre and hides it; isolating
74
+ * one is the only way to look at the level you are actually booking.
75
+ */
76
+ floor: Float32Array;
77
+ /**
78
+ * Small renderer material class per vertex:
79
+ * 0 = ordinary structure, 1 = authored powered display,
80
+ * 2 = row riser, 3 = row tread, 4 = football turf, 5 = generated concrete.
81
+ */
82
+ material: Float32Array;
83
+ /** Vertex count (position.length / 3). */
84
+ count: number;
85
+ }
86
+
87
+ interface SharedAisleCandidate {
88
+ sections: [string, string];
89
+ /** Block IDs are local to each section, paired in the same endpoint order. */
90
+ blocks?: [number, number];
91
+ floorIndex: number;
92
+ ends: [Point, Point];
93
+ /** Same-level clear width after reserving furniture space at both ends. */
94
+ clearWidthM: number;
95
+ heightM: number;
96
+ /** Chart-space footprint; a proposal, not an authored circulation route. */
97
+ outline: Point[];
98
+ }
99
+
50
100
  /**
51
101
  * Resolve a chart's authored theme into the 3D scene's colours.
52
102
  *
@@ -124,48 +174,14 @@ interface SceneLabel {
124
174
  anchor: [number, number, number];
125
175
  /** Authored colour (`#rrggbb`), when the object carries one. */
126
176
  color?: string;
177
+ /** Physical chair width, used to reveal numbers only at readable scale. */
178
+ seatWidthM?: number;
127
179
  /** Authored rotation in degrees, for annotations that specify one. */
128
180
  rotation?: number;
129
181
  /** Owning physical level, so a focused floor never keeps another level's text. */
130
182
  floorIndex?: number;
131
183
  }
132
184
 
133
- /**
134
- * Pure geometry primitives for the view3d scene — no OGL, no DOM, so the whole
135
- * scene-model builder is unit-testable in a plain runtime.
136
- *
137
- * Coordinate convention: chart units (x, y) map to world metres as
138
- * worldX = x * METRES_PER_CHART_UNIT
139
- * worldZ = y * METRES_PER_CHART_UNIT
140
- * worldY = up (height in metres)
141
- * i.e. the chart's audience-depth (+y) becomes world +Z, and Y is the vertical.
142
- */
143
-
144
- interface MeshData {
145
- /** Non-indexed triangle soup: 3 floats per vertex. */
146
- position: Float32Array;
147
- normal: Float32Array;
148
- /** Baked vertex colour incl. AO, 3 floats per vertex. */
149
- color: Float32Array;
150
- /**
151
- * Owning floor index per vertex.
152
- *
153
- * Lets one merged mesh be dimmed per floor without splitting it into a draw
154
- * call per floor. A multi-floor chart (the opera house has three) draws every
155
- * floor at once, so the balcony sits over the parterre and hides it; isolating
156
- * one is the only way to look at the level you are actually booking.
157
- */
158
- floor: Float32Array;
159
- /**
160
- * Small renderer material class per vertex:
161
- * 0 = ordinary structure, 1 = authored powered display,
162
- * 2 = row riser, 3 = row tread.
163
- */
164
- material: Float32Array;
165
- /** Vertex count (position.length / 3). */
166
- count: number;
167
- }
168
-
169
185
  /**
170
186
  * Pure builder for the instanced seat cloud. Produces the per-instance arrays a
171
187
  * single OGL InstancedMesh consumes (one draw call for every seat), plus the
@@ -216,6 +232,8 @@ interface SeatInstanceData {
216
232
  iRing: Float32Array;
217
233
  /** float per instance: owning floor index, for per-floor isolation. */
218
234
  iFloor: Float32Array;
235
+ /** float per instance: owning section's index in SceneModel.sections, -1 = none. */
236
+ iSection: Float32Array;
219
237
  /**
220
238
  * float per instance: facing yaw in radians, for the near-field chair mesh.
221
239
  *
@@ -313,6 +331,11 @@ interface SceneSection {
313
331
  center: [number, number, number];
314
332
  /** Half-diagonal of its seat footprint, world metres (camera fit). */
315
333
  radius: number;
334
+ /** Seat envelope including furniture height, used for projected camera fitting. */
335
+ box?: {
336
+ min: [number, number, number];
337
+ max: [number, number, number];
338
+ };
316
339
  /** What this section faces — the camera approaches from this side. */
317
340
  focalWorld: [number, number, number];
318
341
  }
@@ -350,6 +373,8 @@ interface SectionSolidRange {
350
373
  count: number;
351
374
  }
352
375
  interface SceneModel {
376
+ /** Geometric proposals only; not verified routes or rendered architecture. */
377
+ sharedAisles?: SharedAisleCandidate[];
353
378
  /** Every non-seat surface merged into one triangle soup (1 draw call). */
354
379
  solids: MeshData;
355
380
  /**
@@ -362,6 +387,8 @@ interface SceneModel {
362
387
  */
363
388
  sectionSolidRanges: SectionSolidRange[];
364
389
  seats: SeatInstanceData;
390
+ /** Physical section ownership in input-seat order; absent on older prepared models. */
391
+ seatSectionIds?: Array<string | null>;
365
392
  bounds: {
366
393
  /** World-metre venue centre (camera target). */
367
394
  center: [number, number, number];
@@ -385,6 +412,12 @@ interface SceneModel {
385
412
  center: [number, number, number];
386
413
  radius: number;
387
414
  };
415
+ /** Everything drawn, including the site around the venue: camera clipping
416
+ * only. Absent on models built before the site existed. */
417
+ clipBounds?: {
418
+ center: [number, number, number];
419
+ radius: number;
420
+ };
388
421
  /** 5 × vec3 flat LUT for the seat fragment shader. */
389
422
  stateColorLUT: number[];
390
423
  /** Resolved colours for this chart's authored theme (background, seat scale). */
@@ -438,33 +471,6 @@ interface SceneModelInput {
438
471
  initialState?: (seat: ExpandedSeat) => SeatState3D;
439
472
  }
440
473
 
441
- /**
442
- * The JS-side source of truth for the 3D scene — a pure, GPU-free description
443
- * built once from the chart's existing height contract. Everything the renderer
444
- * uploads (merged solid geometry, the instanced seat cloud, camera-framing
445
- * bounds, the seat-state colour LUT) is derived here, so it survives a WebGL
446
- * context loss: on `webglcontextrestored` the renderer simply re-uploads from
447
- * this model without recomputing anything.
448
- *
449
- * Feeds 100% from `sectionGeometry` / `Floor.baseHeightM` / `ExpandedSeat`
450
- * (docs/3d-program-workorder §Architecture) — no new chart data is invented.
451
- *
452
- * This module is the ORCHESTRATOR and the public face of `scene/model/`: it
453
- * sequences the passes and re-exports every type and helper the rest of the
454
- * codebase, the tests and the SDK import from `scene/sceneModel`. The passes
455
- * themselves live in `scene/model/` — see `docs/architecture` for the layering:
456
- *
457
- * types the shapes everything below is described in
458
- * paint AO + how an authored colour becomes an architectural tone
459
- * footprints configuration filtering, floor units, plan-space polygons
460
- * shapeArchitecture décor vocabulary → architecture, and coplanar claims
461
- * objectBuilders one prism per booth / table / shape / décor / GA area
462
- * tiers per-section decks and the per-floor bowl
463
- * labels zones, sections, rows and everything worth naming
464
- * floors per-level boxes, and the per-seat floor attribute
465
- * bounds chart footprint, ground datum, render + overview volumes
466
- */
467
-
468
474
  declare function buildSceneModel(input: SceneModelInput): SceneModel;
469
475
 
470
476
  /**
@@ -487,12 +493,75 @@ type Analytics3DCallback = (event: string, props?: Record<string, unknown>) => v
487
493
  */
488
494
  type Scene3DPrepSource = 'worker' | 'main' | 'inline';
489
495
 
496
+ interface AutoVenueSection {
497
+ id: string;
498
+ /** Owning floor on a multi-floor chart. */
499
+ floorId?: string;
500
+ /** Surface the estimate implies: stepped rows, or a level deck. */
501
+ surfaceKind: 'flat' | 'rakedRows';
502
+ height: number;
503
+ rake: number;
504
+ /** Section this one continues from, when it stands behind another. */
505
+ stackedOn?: string;
506
+ }
507
+ interface AutoVenueReport {
508
+ /** Shape id treated as the stage and whether that was inferred; `deck`
509
+ * when an unmarked shape was given the stage role. */
510
+ stage?: {
511
+ id: string;
512
+ inferred: boolean;
513
+ floorId?: string;
514
+ deck?: boolean;
515
+ field?: StageKind;
516
+ };
517
+ focalInferred: boolean;
518
+ /** The facing point each floor was given, where it was moved to the stage. */
519
+ focal?: {
520
+ floorId?: string;
521
+ point: Point;
522
+ }[];
523
+ /**
524
+ * The estimate knows what the audience looks at: a stage (drawn or found)
525
+ * or a focal point the organizer placed. Without either, heights are a
526
+ * guess and buyers keep the flat venue.
527
+ */
528
+ confident: boolean;
529
+ sections: AutoVenueSection[];
530
+ /** Free-standing row blocks given a hidden section in the 3D copy only. */
531
+ looseRowBlocks?: number;
532
+ /** Plain shapes given the role their label names (a Bar, the WC, a Screen). */
533
+ roles?: {
534
+ id: string;
535
+ floorId?: string;
536
+ role: string;
537
+ }[];
538
+ }
539
+ /** Derive a 3D-ready copy of `doc`; see the module comment for the rules. */
540
+ declare function autoVenue3d(doc: ChartDoc, defaultFocal?: Point): {
541
+ doc: ChartDoc;
542
+ report: AutoVenueReport;
543
+ };
544
+
545
+ interface EstimatedVenue3D {
546
+ doc: ChartDoc;
547
+ report: AutoVenueReport;
548
+ /** Per seat, in input order: eye height (NaN = unset). */
549
+ eyeHeightM: Float64Array;
550
+ /** Per seat, in input order: facing point x, y (NaN = unset). */
551
+ focal: Float64Array;
552
+ }
553
+ /** The estimate to render for `doc`, or null to render the chart as saved. */
554
+ declare function estimateVenue3D(doc: ChartDoc, seats: readonly ExpandedSeat[]): EstimatedVenue3D | null;
555
+
490
556
  interface PreparedVenue3D {
491
557
  model: SceneModel;
492
558
  buildMs: number;
493
559
  /** Reported on `3d_opened` as `prepSource`. `inline` is not reachable here —
494
560
  * it is what `mountVenue3D` reports when no prepared scene was handed in. */
495
561
  source: Exclude<Scene3DPrepSource, 'inline'>;
562
+ /** The estimated venue the model was built from; `mountVenue3D` mounts it
563
+ * in place of the saved chart, with each seat's eye height and facing point. */
564
+ estimate?: EstimatedVenue3D;
496
565
  }
497
566
  interface PrepareVenue3DInput {
498
567
  doc: ChartDoc;
@@ -501,6 +570,8 @@ interface PrepareVenue3DInput {
501
570
  /** Exact content delivered only with the lazy 3D request. */
502
571
  eventConfiguration?: EventConfigurationVersion;
503
572
  registeredShellGlb?: ArrayBuffer;
573
+ /** False renders the chart exactly as saved, with no estimated heights. */
574
+ estimate?: boolean;
504
575
  }
505
576
  type PrepareVenue3DFromChartInput = Omit<PrepareVenue3DInput, 'seats'>;
506
577
  /** Designer-friendly result: expansion and scene compilation both happened
@@ -706,6 +777,9 @@ interface Venue3DInput {
706
777
  initialState?: (seat: ExpandedSeat) => SeatState3D;
707
778
  /** CPU scene prepared by `prepareVenue3D`; avoids rebuilding on mount. */
708
779
  prepared?: PreparedVenue3D;
780
+ /** False renders the chart exactly as saved, with no estimated heights.
781
+ * Ignored with `prepared`, which already made that choice. */
782
+ estimate?: boolean;
709
783
  }
710
784
  interface Venue3DOptions {
711
785
  /** Fired on a tap that hits a seat (GPU color-pick). Not fired on empty taps. */
@@ -795,6 +869,8 @@ interface Venue3DOptions {
795
869
  * contain framing; validated for the buyer across `/dev/3d` fixtures.
796
870
  */
797
871
  portraitOverviewCrop?: boolean;
872
+ /** Optional authored presentation angle; stage-derived orientation otherwise wins. */
873
+ overviewAzimuthDeg?: number;
798
874
  /** Start on the final overview pose without the decorative stand-up intro.
799
875
  * Intended for deterministic rendered review and screenshot capture. */
800
876
  skipInitialOverviewAnimation?: boolean;
@@ -824,6 +900,8 @@ interface Venue3DOptions {
824
900
 
825
901
  interface Venue3DStats extends RenderLoopStats {
826
902
  drawCalls: number;
903
+ /** Submitted fallback triangles, including collapsed bays; excludes near chairs. */
904
+ fallbackTriangles?: number;
827
905
  seatCount: number;
828
906
  }
829
907
  interface Venue3DHandle {
@@ -861,6 +939,9 @@ interface Venue3DHandle {
861
939
  resize(): void;
862
940
  stats(): Venue3DStats;
863
941
  /** Machine-readable evidence from the exact parked WebGL frame and DOM labels. */
942
+ /** The current view as a JPEG data URL, longest edge at most `maxEdge` px
943
+ * (default 1280); null when the GPU context is gone. */
944
+ captureImage(maxEdge?: number): string | null;
864
945
  getQualityEvidence(): Venue3DQualityEvidence;
865
946
  getQualityReport(): Venue3DQualityReport;
866
947
  loseContextForTest(): void;
@@ -909,19 +990,6 @@ interface Venue3DHandle {
909
990
  focusFloor(index: number | null): boolean;
910
991
  }
911
992
 
912
- /**
913
- * view3d — the sole dynamic-import boundary for the lazy OGL venue-view chunk.
914
- *
915
- * const { mountVenue3D } = await import('../view3d');
916
- * const handle = mountVenue3D(container, { doc, seats }, { onSeatPick, getSeatView });
917
- * await handle.flyToSeat(seatId);
918
- *
919
- * Read-only 3D of any chart, fed entirely from the existing height contract.
920
- * Slice 1: orbit camera, extruded tiers/stage/GA, instanced seat dots, sub-range
921
- * availability, dispose + context-loss survival. Slice 2: GPU color-pick. Slice
922
- * 3: the fly-to-seat cinematic that dissolves into the view-from-seat panorama.
923
- */
924
-
925
993
  declare function mountVenue3D(container: HTMLElement, input: Venue3DInput, opts?: Venue3DOptions): Venue3DHandle;
926
994
 
927
- export { type Analytics3DCallback, type PreparedVenue3D, type PreparedVenue3DFromChart, type Scene3DPrepSource, type SeatState3D, SeatView, type SeatViewStopName, VENUE3D_QUALITY_REPORT_VERSION, type Venue3DHandle, type Venue3DInput, type Venue3DOptions, type Venue3DQualityEvidence, type Venue3DQualityReport, type Venue3DStats, buildSceneModel, inspectVenue3DQualityEvidence, mountVenue3D, prepareVenue3D, prepareVenue3DFromChart };
995
+ export { type Analytics3DCallback, type AutoVenueReport, type PreparedVenue3D, type PreparedVenue3DFromChart, type Scene3DPrepSource, type SeatState3D, SeatView, type SeatViewStopName, VENUE3D_QUALITY_REPORT_VERSION, type Venue3DHandle, type Venue3DInput, type Venue3DOptions, type Venue3DQualityEvidence, type Venue3DQualityReport, type Venue3DStats, autoVenue3d, buildSceneModel, estimateVenue3D, inspectVenue3DQualityEvidence, mountVenue3D, prepareVenue3D, prepareVenue3DFromChart };