@seatlayer/core 0.96.0 → 0.98.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-2MXDWZQ4.js +1 -0
  6. package/dist/chunk-2P72QUJR.js +1 -0
  7. package/dist/chunk-5N4H3KMR.js +1 -0
  8. package/dist/chunk-ASIIXY5M.js +1 -0
  9. package/dist/{chunk-O3DGXAIC.js → chunk-CUACREZL.js} +1 -1
  10. package/dist/{chunk-CEIVHWRB.js → chunk-FLMKHAUT.js} +1 -1
  11. package/dist/{chunk-TKYTTEJ2.js → chunk-IW7QZIMF.js} +1 -1
  12. package/dist/chunk-M5VINTGE.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 +283 -78
  74. package/dist/view3d/index.d.cts +152 -78
  75. package/dist/view3d/index.d.ts +152 -78
  76. package/dist/view3d/index.js +281 -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,46 +174,16 @@ 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
- }
132
-
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;
183
+ /** A picked seat's pin base (scene/seatPin): its tag rides the pin's stem. */
184
+ pinBase?: [number, number, number];
185
+ /** A seat label's row, so the row under the pointer can show its numbers. */
186
+ rowId?: string;
167
187
  }
168
188
 
169
189
  /**
@@ -216,6 +236,8 @@ interface SeatInstanceData {
216
236
  iRing: Float32Array;
217
237
  /** float per instance: owning floor index, for per-floor isolation. */
218
238
  iFloor: Float32Array;
239
+ /** float per instance: owning section's index in SceneModel.sections, -1 = none. */
240
+ iSection: Float32Array;
219
241
  /**
220
242
  * float per instance: facing yaw in radians, for the near-field chair mesh.
221
243
  *
@@ -313,6 +335,11 @@ interface SceneSection {
313
335
  center: [number, number, number];
314
336
  /** Half-diagonal of its seat footprint, world metres (camera fit). */
315
337
  radius: number;
338
+ /** Seat envelope including furniture height, used for projected camera fitting. */
339
+ box?: {
340
+ min: [number, number, number];
341
+ max: [number, number, number];
342
+ };
316
343
  /** What this section faces — the camera approaches from this side. */
317
344
  focalWorld: [number, number, number];
318
345
  }
@@ -350,6 +377,8 @@ interface SectionSolidRange {
350
377
  count: number;
351
378
  }
352
379
  interface SceneModel {
380
+ /** Geometric proposals only; not verified routes or rendered architecture. */
381
+ sharedAisles?: SharedAisleCandidate[];
353
382
  /** Every non-seat surface merged into one triangle soup (1 draw call). */
354
383
  solids: MeshData;
355
384
  /**
@@ -362,6 +391,8 @@ interface SceneModel {
362
391
  */
363
392
  sectionSolidRanges: SectionSolidRange[];
364
393
  seats: SeatInstanceData;
394
+ /** Physical section ownership in input-seat order; absent on older prepared models. */
395
+ seatSectionIds?: Array<string | null>;
365
396
  bounds: {
366
397
  /** World-metre venue centre (camera target). */
367
398
  center: [number, number, number];
@@ -385,6 +416,12 @@ interface SceneModel {
385
416
  center: [number, number, number];
386
417
  radius: number;
387
418
  };
419
+ /** Everything drawn, including the site around the venue: camera clipping
420
+ * only. Absent on models built before the site existed. */
421
+ clipBounds?: {
422
+ center: [number, number, number];
423
+ radius: number;
424
+ };
388
425
  /** 5 × vec3 flat LUT for the seat fragment shader. */
389
426
  stateColorLUT: number[];
390
427
  /** Resolved colours for this chart's authored theme (background, seat scale). */
@@ -438,33 +475,6 @@ interface SceneModelInput {
438
475
  initialState?: (seat: ExpandedSeat) => SeatState3D;
439
476
  }
440
477
 
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
478
  declare function buildSceneModel(input: SceneModelInput): SceneModel;
469
479
 
470
480
  /**
@@ -487,12 +497,77 @@ type Analytics3DCallback = (event: string, props?: Record<string, unknown>) => v
487
497
  */
488
498
  type Scene3DPrepSource = 'worker' | 'main' | 'inline';
489
499
 
500
+ interface AutoVenueSection {
501
+ id: string;
502
+ /** Owning floor on a multi-floor chart. */
503
+ floorId?: string;
504
+ /** Surface the estimate implies: stepped rows, or a level deck. */
505
+ surfaceKind: 'flat' | 'rakedRows';
506
+ height: number;
507
+ rake: number;
508
+ /** Section this one continues from, when it stands behind another. */
509
+ stackedOn?: string;
510
+ }
511
+ interface AutoVenueReport {
512
+ /** Shape id treated as the stage and whether that was inferred; `deck`
513
+ * when an unmarked shape was given the stage role. */
514
+ stage?: {
515
+ id: string;
516
+ inferred: boolean;
517
+ floorId?: string;
518
+ deck?: boolean;
519
+ field?: StageKind;
520
+ };
521
+ focalInferred: boolean;
522
+ /** The facing point each floor was given, where it was moved to the stage. */
523
+ focal?: {
524
+ floorId?: string;
525
+ point: Point;
526
+ }[];
527
+ /**
528
+ * The estimate knows what the audience looks at: a stage (drawn or found)
529
+ * or a focal point the organizer placed. Without either, heights are a
530
+ * guess and buyers keep the flat venue.
531
+ */
532
+ confident: boolean;
533
+ sections: AutoVenueSection[];
534
+ /** Free-standing row blocks given a hidden section in the 3D copy only. */
535
+ looseRowBlocks?: number;
536
+ /** The chart's drawn walls enclose its seating: tiers were raked as a hall's. */
537
+ indoor?: boolean;
538
+ /** Plain shapes given the role their label names (a Bar, the WC, a Screen). */
539
+ roles?: {
540
+ id: string;
541
+ floorId?: string;
542
+ role: string;
543
+ }[];
544
+ }
545
+ /** Derive a 3D-ready copy of `doc`; see the module comment for the rules. */
546
+ declare function autoVenue3d(doc: ChartDoc, defaultFocal?: Point): {
547
+ doc: ChartDoc;
548
+ report: AutoVenueReport;
549
+ };
550
+
551
+ interface EstimatedVenue3D {
552
+ doc: ChartDoc;
553
+ report: AutoVenueReport;
554
+ /** Per seat, in input order: eye height (NaN = unset). */
555
+ eyeHeightM: Float64Array;
556
+ /** Per seat, in input order: facing point x, y (NaN = unset). */
557
+ focal: Float64Array;
558
+ }
559
+ /** The estimate to render for `doc`, or null to render the chart as saved. */
560
+ declare function estimateVenue3D(doc: ChartDoc, seats: readonly ExpandedSeat[]): EstimatedVenue3D | null;
561
+
490
562
  interface PreparedVenue3D {
491
563
  model: SceneModel;
492
564
  buildMs: number;
493
565
  /** Reported on `3d_opened` as `prepSource`. `inline` is not reachable here —
494
566
  * it is what `mountVenue3D` reports when no prepared scene was handed in. */
495
567
  source: Exclude<Scene3DPrepSource, 'inline'>;
568
+ /** The estimated venue the model was built from; `mountVenue3D` mounts it
569
+ * in place of the saved chart, with each seat's eye height and facing point. */
570
+ estimate?: EstimatedVenue3D;
496
571
  }
497
572
  interface PrepareVenue3DInput {
498
573
  doc: ChartDoc;
@@ -501,6 +576,8 @@ interface PrepareVenue3DInput {
501
576
  /** Exact content delivered only with the lazy 3D request. */
502
577
  eventConfiguration?: EventConfigurationVersion;
503
578
  registeredShellGlb?: ArrayBuffer;
579
+ /** False renders the chart exactly as saved, with no estimated heights. */
580
+ estimate?: boolean;
504
581
  }
505
582
  type PrepareVenue3DFromChartInput = Omit<PrepareVenue3DInput, 'seats'>;
506
583
  /** Designer-friendly result: expansion and scene compilation both happened
@@ -706,6 +783,9 @@ interface Venue3DInput {
706
783
  initialState?: (seat: ExpandedSeat) => SeatState3D;
707
784
  /** CPU scene prepared by `prepareVenue3D`; avoids rebuilding on mount. */
708
785
  prepared?: PreparedVenue3D;
786
+ /** False renders the chart exactly as saved, with no estimated heights.
787
+ * Ignored with `prepared`, which already made that choice. */
788
+ estimate?: boolean;
709
789
  }
710
790
  interface Venue3DOptions {
711
791
  /** Fired on a tap that hits a seat (GPU color-pick). Not fired on empty taps. */
@@ -795,6 +875,8 @@ interface Venue3DOptions {
795
875
  * contain framing; validated for the buyer across `/dev/3d` fixtures.
796
876
  */
797
877
  portraitOverviewCrop?: boolean;
878
+ /** Optional authored presentation angle; stage-derived orientation otherwise wins. */
879
+ overviewAzimuthDeg?: number;
798
880
  /** Start on the final overview pose without the decorative stand-up intro.
799
881
  * Intended for deterministic rendered review and screenshot capture. */
800
882
  skipInitialOverviewAnimation?: boolean;
@@ -824,6 +906,8 @@ interface Venue3DOptions {
824
906
 
825
907
  interface Venue3DStats extends RenderLoopStats {
826
908
  drawCalls: number;
909
+ /** Submitted fallback triangles, including collapsed bays; excludes near chairs. */
910
+ fallbackTriangles?: number;
827
911
  seatCount: number;
828
912
  }
829
913
  interface Venue3DHandle {
@@ -861,6 +945,9 @@ interface Venue3DHandle {
861
945
  resize(): void;
862
946
  stats(): Venue3DStats;
863
947
  /** Machine-readable evidence from the exact parked WebGL frame and DOM labels. */
948
+ /** The current view as a JPEG data URL, longest edge at most `maxEdge` px
949
+ * (default 1280); null when the GPU context is gone. */
950
+ captureImage(maxEdge?: number): string | null;
864
951
  getQualityEvidence(): Venue3DQualityEvidence;
865
952
  getQualityReport(): Venue3DQualityReport;
866
953
  loseContextForTest(): void;
@@ -909,19 +996,6 @@ interface Venue3DHandle {
909
996
  focusFloor(index: number | null): boolean;
910
997
  }
911
998
 
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
999
  declare function mountVenue3D(container: HTMLElement, input: Venue3DInput, opts?: Venue3DOptions): Venue3DHandle;
926
1000
 
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 };
1001
+ 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,46 +174,16 @@ 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
- }
132
-
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;
183
+ /** A picked seat's pin base (scene/seatPin): its tag rides the pin's stem. */
184
+ pinBase?: [number, number, number];
185
+ /** A seat label's row, so the row under the pointer can show its numbers. */
186
+ rowId?: string;
167
187
  }
168
188
 
169
189
  /**
@@ -216,6 +236,8 @@ interface SeatInstanceData {
216
236
  iRing: Float32Array;
217
237
  /** float per instance: owning floor index, for per-floor isolation. */
218
238
  iFloor: Float32Array;
239
+ /** float per instance: owning section's index in SceneModel.sections, -1 = none. */
240
+ iSection: Float32Array;
219
241
  /**
220
242
  * float per instance: facing yaw in radians, for the near-field chair mesh.
221
243
  *
@@ -313,6 +335,11 @@ interface SceneSection {
313
335
  center: [number, number, number];
314
336
  /** Half-diagonal of its seat footprint, world metres (camera fit). */
315
337
  radius: number;
338
+ /** Seat envelope including furniture height, used for projected camera fitting. */
339
+ box?: {
340
+ min: [number, number, number];
341
+ max: [number, number, number];
342
+ };
316
343
  /** What this section faces — the camera approaches from this side. */
317
344
  focalWorld: [number, number, number];
318
345
  }
@@ -350,6 +377,8 @@ interface SectionSolidRange {
350
377
  count: number;
351
378
  }
352
379
  interface SceneModel {
380
+ /** Geometric proposals only; not verified routes or rendered architecture. */
381
+ sharedAisles?: SharedAisleCandidate[];
353
382
  /** Every non-seat surface merged into one triangle soup (1 draw call). */
354
383
  solids: MeshData;
355
384
  /**
@@ -362,6 +391,8 @@ interface SceneModel {
362
391
  */
363
392
  sectionSolidRanges: SectionSolidRange[];
364
393
  seats: SeatInstanceData;
394
+ /** Physical section ownership in input-seat order; absent on older prepared models. */
395
+ seatSectionIds?: Array<string | null>;
365
396
  bounds: {
366
397
  /** World-metre venue centre (camera target). */
367
398
  center: [number, number, number];
@@ -385,6 +416,12 @@ interface SceneModel {
385
416
  center: [number, number, number];
386
417
  radius: number;
387
418
  };
419
+ /** Everything drawn, including the site around the venue: camera clipping
420
+ * only. Absent on models built before the site existed. */
421
+ clipBounds?: {
422
+ center: [number, number, number];
423
+ radius: number;
424
+ };
388
425
  /** 5 × vec3 flat LUT for the seat fragment shader. */
389
426
  stateColorLUT: number[];
390
427
  /** Resolved colours for this chart's authored theme (background, seat scale). */
@@ -438,33 +475,6 @@ interface SceneModelInput {
438
475
  initialState?: (seat: ExpandedSeat) => SeatState3D;
439
476
  }
440
477
 
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
478
  declare function buildSceneModel(input: SceneModelInput): SceneModel;
469
479
 
470
480
  /**
@@ -487,12 +497,77 @@ type Analytics3DCallback = (event: string, props?: Record<string, unknown>) => v
487
497
  */
488
498
  type Scene3DPrepSource = 'worker' | 'main' | 'inline';
489
499
 
500
+ interface AutoVenueSection {
501
+ id: string;
502
+ /** Owning floor on a multi-floor chart. */
503
+ floorId?: string;
504
+ /** Surface the estimate implies: stepped rows, or a level deck. */
505
+ surfaceKind: 'flat' | 'rakedRows';
506
+ height: number;
507
+ rake: number;
508
+ /** Section this one continues from, when it stands behind another. */
509
+ stackedOn?: string;
510
+ }
511
+ interface AutoVenueReport {
512
+ /** Shape id treated as the stage and whether that was inferred; `deck`
513
+ * when an unmarked shape was given the stage role. */
514
+ stage?: {
515
+ id: string;
516
+ inferred: boolean;
517
+ floorId?: string;
518
+ deck?: boolean;
519
+ field?: StageKind;
520
+ };
521
+ focalInferred: boolean;
522
+ /** The facing point each floor was given, where it was moved to the stage. */
523
+ focal?: {
524
+ floorId?: string;
525
+ point: Point;
526
+ }[];
527
+ /**
528
+ * The estimate knows what the audience looks at: a stage (drawn or found)
529
+ * or a focal point the organizer placed. Without either, heights are a
530
+ * guess and buyers keep the flat venue.
531
+ */
532
+ confident: boolean;
533
+ sections: AutoVenueSection[];
534
+ /** Free-standing row blocks given a hidden section in the 3D copy only. */
535
+ looseRowBlocks?: number;
536
+ /** The chart's drawn walls enclose its seating: tiers were raked as a hall's. */
537
+ indoor?: boolean;
538
+ /** Plain shapes given the role their label names (a Bar, the WC, a Screen). */
539
+ roles?: {
540
+ id: string;
541
+ floorId?: string;
542
+ role: string;
543
+ }[];
544
+ }
545
+ /** Derive a 3D-ready copy of `doc`; see the module comment for the rules. */
546
+ declare function autoVenue3d(doc: ChartDoc, defaultFocal?: Point): {
547
+ doc: ChartDoc;
548
+ report: AutoVenueReport;
549
+ };
550
+
551
+ interface EstimatedVenue3D {
552
+ doc: ChartDoc;
553
+ report: AutoVenueReport;
554
+ /** Per seat, in input order: eye height (NaN = unset). */
555
+ eyeHeightM: Float64Array;
556
+ /** Per seat, in input order: facing point x, y (NaN = unset). */
557
+ focal: Float64Array;
558
+ }
559
+ /** The estimate to render for `doc`, or null to render the chart as saved. */
560
+ declare function estimateVenue3D(doc: ChartDoc, seats: readonly ExpandedSeat[]): EstimatedVenue3D | null;
561
+
490
562
  interface PreparedVenue3D {
491
563
  model: SceneModel;
492
564
  buildMs: number;
493
565
  /** Reported on `3d_opened` as `prepSource`. `inline` is not reachable here —
494
566
  * it is what `mountVenue3D` reports when no prepared scene was handed in. */
495
567
  source: Exclude<Scene3DPrepSource, 'inline'>;
568
+ /** The estimated venue the model was built from; `mountVenue3D` mounts it
569
+ * in place of the saved chart, with each seat's eye height and facing point. */
570
+ estimate?: EstimatedVenue3D;
496
571
  }
497
572
  interface PrepareVenue3DInput {
498
573
  doc: ChartDoc;
@@ -501,6 +576,8 @@ interface PrepareVenue3DInput {
501
576
  /** Exact content delivered only with the lazy 3D request. */
502
577
  eventConfiguration?: EventConfigurationVersion;
503
578
  registeredShellGlb?: ArrayBuffer;
579
+ /** False renders the chart exactly as saved, with no estimated heights. */
580
+ estimate?: boolean;
504
581
  }
505
582
  type PrepareVenue3DFromChartInput = Omit<PrepareVenue3DInput, 'seats'>;
506
583
  /** Designer-friendly result: expansion and scene compilation both happened
@@ -706,6 +783,9 @@ interface Venue3DInput {
706
783
  initialState?: (seat: ExpandedSeat) => SeatState3D;
707
784
  /** CPU scene prepared by `prepareVenue3D`; avoids rebuilding on mount. */
708
785
  prepared?: PreparedVenue3D;
786
+ /** False renders the chart exactly as saved, with no estimated heights.
787
+ * Ignored with `prepared`, which already made that choice. */
788
+ estimate?: boolean;
709
789
  }
710
790
  interface Venue3DOptions {
711
791
  /** Fired on a tap that hits a seat (GPU color-pick). Not fired on empty taps. */
@@ -795,6 +875,8 @@ interface Venue3DOptions {
795
875
  * contain framing; validated for the buyer across `/dev/3d` fixtures.
796
876
  */
797
877
  portraitOverviewCrop?: boolean;
878
+ /** Optional authored presentation angle; stage-derived orientation otherwise wins. */
879
+ overviewAzimuthDeg?: number;
798
880
  /** Start on the final overview pose without the decorative stand-up intro.
799
881
  * Intended for deterministic rendered review and screenshot capture. */
800
882
  skipInitialOverviewAnimation?: boolean;
@@ -824,6 +906,8 @@ interface Venue3DOptions {
824
906
 
825
907
  interface Venue3DStats extends RenderLoopStats {
826
908
  drawCalls: number;
909
+ /** Submitted fallback triangles, including collapsed bays; excludes near chairs. */
910
+ fallbackTriangles?: number;
827
911
  seatCount: number;
828
912
  }
829
913
  interface Venue3DHandle {
@@ -861,6 +945,9 @@ interface Venue3DHandle {
861
945
  resize(): void;
862
946
  stats(): Venue3DStats;
863
947
  /** Machine-readable evidence from the exact parked WebGL frame and DOM labels. */
948
+ /** The current view as a JPEG data URL, longest edge at most `maxEdge` px
949
+ * (default 1280); null when the GPU context is gone. */
950
+ captureImage(maxEdge?: number): string | null;
864
951
  getQualityEvidence(): Venue3DQualityEvidence;
865
952
  getQualityReport(): Venue3DQualityReport;
866
953
  loseContextForTest(): void;
@@ -909,19 +996,6 @@ interface Venue3DHandle {
909
996
  focusFloor(index: number | null): boolean;
910
997
  }
911
998
 
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
999
  declare function mountVenue3D(container: HTMLElement, input: Venue3DInput, opts?: Venue3DOptions): Venue3DHandle;
926
1000
 
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 };
1001
+ 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 };