@seatlayer/core 0.16.0 → 0.17.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.
package/dist/index.d.cts CHANGED
@@ -11,12 +11,44 @@ interface Point {
11
11
  x: number;
12
12
  y: number;
13
13
  }
14
+ interface CubicPath {
15
+ start: Point;
16
+ control1: Point;
17
+ control2: Point;
18
+ end: Point;
19
+ }
20
+ /** A real closed section boundary. `outline` remains its sampled collision and
21
+ * persistence fallback; this path is the smooth authoring/buyer paint source. */
22
+ type SectionPathSegment = {
23
+ kind: 'line';
24
+ end: Point;
25
+ } | {
26
+ kind: 'arc';
27
+ center: Point;
28
+ radius: number;
29
+ clockwise: boolean;
30
+ end: Point;
31
+ } | {
32
+ kind: 'bezier';
33
+ control1: Point;
34
+ control2: Point;
35
+ end: Point;
36
+ };
37
+ interface SectionOutlinePath {
38
+ version: 1;
39
+ closed: true;
40
+ start: Point;
41
+ segments: SectionPathSegment[];
42
+ }
14
43
  interface Category {
15
44
  key: string;
16
45
  label: string;
17
46
  color: string;
18
47
  /** Base price — used when the category has no explicit tiers. */
19
48
  price?: number;
49
+ /** Durable evidence for semantic/display facts proposed while converting a
50
+ * private reference into sellable inventory. */
51
+ referenceCategorySource?: ReferenceCategorySource;
20
52
  /**
21
53
  * Ticket tiers (Adult / Child / Senior…). When present, a buyer picks a tier
22
54
  * per seat in this category and the tier's price applies; the first tier is the
@@ -25,6 +57,33 @@ interface Category {
25
57
  */
26
58
  tiers?: CategoryTier[];
27
59
  }
60
+ interface ReferenceCategorySource {
61
+ assetId: string;
62
+ /** Original sampled section color. `Category.color` is the approved output
63
+ * color and may differ only with separately recorded evidence. */
64
+ sourceColor: string;
65
+ /** Every exact sampled color normalized into the same original 4-bit/channel
66
+ * segmentation class. Older documents may contain only `sourceColor`. */
67
+ sourceColors?: string[];
68
+ /** Logical sections whose generated inventory uses this category. */
69
+ logicalSectionIds?: string[];
70
+ /** Source-color grouping is deterministic; a semantic regrouping needs its
71
+ * own confirmed assignment evidence. */
72
+ assignmentDerivation?: 'source-color-class' | 'confirmed-logical-sections';
73
+ assignmentEvidence?: 'user-confirmed' | 'authoritative-source';
74
+ assignmentSourceDescription?: string;
75
+ /** Optional legend/commercial swatch stated by the source. This remains
76
+ * immutable provenance when the approved accessible output color differs. */
77
+ sourcePaletteColor?: string;
78
+ sourcePaletteColorEvidence?: 'user-confirmed' | 'authoritative-source';
79
+ sourcePaletteColorSourceDescription?: string;
80
+ labelEvidence: 'user-confirmed' | 'authoritative-source';
81
+ labelSourceDescription: string;
82
+ priceEvidence: 'user-confirmed' | 'authoritative-source';
83
+ priceSourceDescription: string;
84
+ outputColorEvidence?: 'user-confirmed' | 'authoritative-source';
85
+ outputColorSourceDescription?: string;
86
+ }
28
87
  /** One ticket tier within a category: a named price (Adult, Child, Senior…). */
29
88
  interface CategoryTier {
30
89
  id: string;
@@ -111,7 +170,14 @@ interface RowObject {
111
170
  seatCount: number;
112
171
  /** Distance between adjacent seat centers, in chart units. */
113
172
  seatSpacing: number;
173
+ /** Optional exact cubic centreline. Normal code owns these coordinates and
174
+ * distributes seats by arc length; MCP/model inputs never submit them. */
175
+ path?: CubicPath;
114
176
  categoryKey: string;
177
+ /** Deterministic provenance for rows fitted from confirmed reference
178
+ * inventory. It enables revision-safe replacement without touching manually
179
+ * authored rows or accepting client coordinates. */
180
+ referenceInventorySource?: ReferenceInventorySource;
115
181
  /** First seat number (default 1). */
116
182
  seatLabelStart?: number;
117
183
  /** Seat numbering within the row (default ltr, step 1). */
@@ -141,8 +207,59 @@ interface GAAreaObject {
141
207
  label: string;
142
208
  /** Closed polygon, in chart units. */
143
209
  points: Point[];
210
+ /** Explicit aisles/pillars/cutouts excluded from the sellable GA surface. */
211
+ holes?: Point[][];
144
212
  capacity: number;
145
213
  categoryKey: string;
214
+ referenceInventorySource?: ReferenceInventorySource;
215
+ }
216
+ /**
217
+ * Durable evidence link for sellable objects generated from a private reference.
218
+ * The client supplies facts and stable logical-section ids, never coordinates.
219
+ */
220
+ interface ReferenceAccessibilitySource {
221
+ placementDerivation: 'server-synthesized-row-edges';
222
+ groupLogicalSectionIds: string[];
223
+ assignmentEvidence: 'user-confirmed' | 'authoritative-source';
224
+ assignmentSourceDescription: string;
225
+ counts: Array<{
226
+ type: AccessibilityType;
227
+ count: number;
228
+ evidence: 'user-confirmed' | 'authoritative-source';
229
+ sourceDescription: string;
230
+ }>;
231
+ }
232
+ interface ReferenceInventorySource {
233
+ assetId: string;
234
+ logicalSectionId: string;
235
+ evidence: 'user-confirmed' | 'authoritative-source';
236
+ sourceDescription: string;
237
+ /** Distinguishes directly supplied inventory from a user-approved server
238
+ * distribution based only on an aggregate capacity. */
239
+ derivation?: 'explicit-inventory' | 'server-synthesized-from-aggregate';
240
+ /** Evidence for the aggregate figure; synthesized rows remain
241
+ * `user-confirmed` and are never mislabeled as source-extracted. */
242
+ aggregateEvidence?: 'user-confirmed' | 'authoritative-source';
243
+ /** Separate evidence for assigning standing inventory to this logical
244
+ * section. Aggregate evidence alone cannot prove section placement. */
245
+ sectionAssignmentEvidence?: 'user-confirmed' | 'authoritative-source';
246
+ sectionAssignmentSourceDescription?: string;
247
+ /** Aggregate row synthesis may propose numbering, but persistence requires
248
+ * the applying user/agent to confirm that policy explicitly. */
249
+ numberingEvidence?: 'user-confirmed';
250
+ numberingSourceDescription?: string;
251
+ /** Evidence and deterministic placement contract for synthesized accessible
252
+ * units in this logical section. */
253
+ accessibility?: ReferenceAccessibilitySource;
254
+ }
255
+ /** Durable evidence that a visible source-backed section shell intentionally
256
+ * carries no generated sellable inventory in this reference configuration. */
257
+ interface ReferenceInventoryExclusionSource {
258
+ assetId: string;
259
+ logicalSectionId: string;
260
+ reason: string;
261
+ evidence: 'user-confirmed' | 'authoritative-source';
262
+ sourceDescription: string;
146
263
  }
147
264
  /** Non-bookable décor: stage, walls, exits. */
148
265
  interface ShapeObject {
@@ -198,6 +315,7 @@ interface TableObject {
198
315
  categoryKey: string;
199
316
  /** Whole-table booking: buyers get all seats or none (per-event override later). */
200
317
  bookAsWhole?: boolean;
318
+ referenceInventorySource?: ReferenceInventorySource;
201
319
  }
202
320
  /** A booth: one bookable unit rendered as a block (trade shows, VIP boxes). */
203
321
  interface BoothObject {
@@ -209,6 +327,7 @@ interface BoothObject {
209
327
  height: number;
210
328
  rotation: number;
211
329
  categoryKey: string;
330
+ referenceInventorySource?: ReferenceInventorySource;
212
331
  }
213
332
  /**
214
333
  * A named region of the venue (Balcony Left, Floor B…). Sections are outlines
@@ -221,8 +340,40 @@ interface SectionObject {
221
340
  type: 'section';
222
341
  id: string;
223
342
  label: string;
343
+ /**
344
+ * Stable management/inventory identity shared by disconnected visual
345
+ * components of one logical section. When absent, `id` is the logical id.
346
+ * Each component keeps its own `id` and reference provenance so rendering,
347
+ * editing, measured diffs, and source restoration remain exact.
348
+ */
349
+ logicalSectionId?: string;
224
350
  /** Closed polygon, chart units. */
225
351
  outline: Point[];
352
+ /** Optional true line/arc/cubic boundary. `outline` is a deterministic sample
353
+ * of this path and remains authoritative for membership, validation, and
354
+ * clients that predate curved section rendering. */
355
+ outlinePath?: SectionOutlinePath;
356
+ /** Explicit aisle/cutout polygons excluded from rendering, hit-testing, and membership. */
357
+ holes?: Point[][];
358
+ /** Durable opaque link to the private reference component. Unlike generator
359
+ * provenance, this survives manual geometry edits so a measured diff can
360
+ * report drift and server-owned code can restore the source contour. */
361
+ referenceSource?: {
362
+ assetId: string;
363
+ regionId: string;
364
+ };
365
+ /** Evidence-backed reason this source section remains a visible shell without
366
+ * synthesized sellable inventory (press, closed technical zone, etc.). */
367
+ referenceInventoryExclusion?: ReferenceInventoryExclusionSource;
368
+ /** Deterministic generator provenance for editable reference/parametric shells. */
369
+ geometry?: {
370
+ kind: 'rectangle' | 'tapered' | 'bezier' | 'contour';
371
+ sourceRegionId?: string;
372
+ contourMethod?: 'pixel-edge-loops-rdp' | 'shared-edge-vector-fit-v1';
373
+ simplificationTolerancePx?: number;
374
+ vectorFitErrorPx?: number;
375
+ sharedEdgeCount?: number;
376
+ };
226
377
  /** Optional tint override (defaults to a neutral fill / dominant category mix). */
227
378
  color?: string;
228
379
  /** Zone this section belongs to (id into `ChartDoc.zones`). Far-zoom nav + pricing group. */
@@ -306,6 +457,53 @@ interface Floor {
306
457
  focalPoint: Point;
307
458
  backgroundImage?: ChartDoc['backgroundImage'];
308
459
  }
460
+ interface ReferenceCalibration {
461
+ type: 'two-point';
462
+ /** Points in immutable source-image pixels, selected by a human or trusted detector. */
463
+ sourceA: Point;
464
+ sourceB: Point;
465
+ /** Verified real-world distance between the two source points. */
466
+ distance: number;
467
+ unit: 'm' | 'ft' | 'chart-unit';
468
+ /** Derived and stored for deterministic geometry compilers. */
469
+ pixelsPerUnit: number;
470
+ }
471
+ /** Coordinate-free physical scale derived by server code from a confirmed
472
+ * semantic feature. Unlike manual two-point calibration, no source points pass
473
+ * through an MCP client or language model. */
474
+ interface ReferenceDerivedScale {
475
+ method: 'confirmed-focal-axis-v1';
476
+ feature: 'focal-long-axis' | 'focal-short-axis';
477
+ distance: number;
478
+ unit: 'm' | 'ft';
479
+ evidence: 'user-confirmed' | 'authoritative-source';
480
+ sourceDescription: string;
481
+ chartUnitsPerUnit: number;
482
+ }
483
+ interface ChartReferenceImage {
484
+ /** Stable private reference asset. New cloud-authored charts use this. */
485
+ assetId?: string;
486
+ /** Legacy/self-contained source. Optional when assetId is present. */
487
+ url?: string;
488
+ center: Point;
489
+ /** Rendered width in chart units (height follows the cropped image aspect). */
490
+ width: number;
491
+ opacity: number;
492
+ rotation?: number;
493
+ visible?: boolean;
494
+ layer?: 'below' | 'above';
495
+ locked?: boolean;
496
+ /** Normalized source crop; defaults to the full image. */
497
+ crop?: {
498
+ x: number;
499
+ y: number;
500
+ width: number;
501
+ height: number;
502
+ };
503
+ calibration?: ReferenceCalibration;
504
+ /** Server-derived semantic calibration without source-image coordinates. */
505
+ derivedScale?: ReferenceDerivedScale;
506
+ }
309
507
  interface ChartDoc {
310
508
  version: 1;
311
509
  name: string;
@@ -322,14 +520,7 @@ interface ChartDoc {
322
520
  floors?: Floor[];
323
521
  objects: ChartObject[];
324
522
  /** Floor-plan photo the organizer traces over (designer-only aid, also rendered dimly in picker if kept). */
325
- backgroundImage?: {
326
- url: string;
327
- center: Point;
328
- /** Rendered width in chart units (height follows the image aspect). */
329
- width: number;
330
- opacity: number;
331
- locked?: boolean;
332
- };
523
+ backgroundImage?: ChartReferenceImage;
333
524
  /** Brand/venue theming (colors); categories carry their own colors separately. */
334
525
  theme?: ChartTheme;
335
526
  /** Parametric-template provenance: present ⇒ the chart came from a capacity-
@@ -362,6 +553,8 @@ type SeatStatus = 'free' | 'held' | 'booked' | 'not_for_sale';
362
553
  interface RendererCallbacks {
363
554
  onSelect?: (seat: ExpandedSeat) => void;
364
555
  onDeselect?: (seat: ExpandedSeat) => void;
556
+ /** Buyer tried to add a seat after the active selection cap was reached. */
557
+ onSelectionLimit?: (maxSelection: number) => void;
365
558
  /** seat is null when the pointer leaves any seat. */
366
559
  onHover?: (seat: ExpandedSeat | null) => void;
367
560
  /** Keyboard focus moved to a seat (arrow-key navigation) — for screen-reader announcements. */
@@ -425,6 +618,130 @@ interface RendererOptions extends RendererCallbacks {
425
618
  */
426
619
  marqueeSelect?: boolean;
427
620
  }
621
+ type RenderedLabelHiddenReason = 'below-minimum-size' | 'outside-viewport' | 'dimmed-or-unavailable' | 'clutter-or-fit' | 'renderer-hidden';
622
+ /** Browser-renderer evidence used by visual QA and catalog release gates. */
623
+ interface RenderedBookableLabelEvidence {
624
+ seatId: string;
625
+ label: string;
626
+ kind: 'seat' | 'booth';
627
+ categoryKey: string;
628
+ sectionId?: string;
629
+ zoneId?: string;
630
+ status: SeatStatus;
631
+ selected: boolean;
632
+ visible: boolean;
633
+ renderedFontPx: number;
634
+ fill: string;
635
+ ink: string;
636
+ opacity: number;
637
+ /** Direct Konva shape bounds and the production near-miss rescue combined. */
638
+ pointerTarget: {
639
+ active: boolean;
640
+ directWidthPx: number;
641
+ directHeightPx: number;
642
+ effectiveMinimumPx: number;
643
+ };
644
+ /** Centre of the painted unit, even when its text is intentionally hidden. */
645
+ screenCenter: {
646
+ x: number;
647
+ y: number;
648
+ };
649
+ screenBox?: {
650
+ x: number;
651
+ y: number;
652
+ width: number;
653
+ height: number;
654
+ };
655
+ hiddenReason?: RenderedLabelHiddenReason;
656
+ }
657
+ interface RenderedHierarchyLabelEvidence {
658
+ id: string;
659
+ kind: 'section' | 'zone';
660
+ role: 'name' | 'availability' | 'price';
661
+ label: string;
662
+ visible: boolean;
663
+ renderedFontPx: number;
664
+ opacity: number;
665
+ fill: string;
666
+ ink: string;
667
+ /** Independent geometric containment check for section-owned text. */
668
+ fitsContainer?: boolean;
669
+ screenBox?: {
670
+ x: number;
671
+ y: number;
672
+ width: number;
673
+ height: number;
674
+ };
675
+ }
676
+ interface RenderedFreeTextEvidence {
677
+ objectId: string;
678
+ kind: 'free-text' | 'stage' | 'table' | 'decor' | 'ga-label' | 'ga-capacity';
679
+ text: string;
680
+ visible: boolean;
681
+ renderedFontPx: number;
682
+ ink: string;
683
+ background: string;
684
+ opacity: number;
685
+ screenBox?: {
686
+ x: number;
687
+ y: number;
688
+ width: number;
689
+ height: number;
690
+ };
691
+ hiddenReason?: 'below-minimum-size' | 'outside-viewport' | 'renderer-hidden';
692
+ }
693
+ interface RenderedGAAreaEvidence {
694
+ areaId: string;
695
+ label: string;
696
+ capacity: number;
697
+ categoryKey: string;
698
+ /** Owning logical section when the rendered GA surface is section-contained. */
699
+ sectionId?: string;
700
+ visible: boolean;
701
+ interactive: boolean;
702
+ opacity: number;
703
+ fill: string;
704
+ effectiveBackground: string;
705
+ screenBox?: {
706
+ x: number;
707
+ y: number;
708
+ width: number;
709
+ height: number;
710
+ };
711
+ }
712
+ interface RendererQualityEvidence {
713
+ viewport: {
714
+ width: number;
715
+ height: number;
716
+ };
717
+ canvasBackground: string;
718
+ effectiveScale: number;
719
+ rung: LodRung;
720
+ minimumVisibleLabelPx: number;
721
+ totalLabelledBookableUnits: number;
722
+ visibleLabels: number;
723
+ hiddenLabels: number;
724
+ /** Seats/table-seats/booths plus the full GA capacity. */
725
+ totalBookableUnits: number;
726
+ selectionRingSeatIds: string[];
727
+ selectionRingColor: string;
728
+ focusedSectionId: string | null;
729
+ focusBackdropVisible: boolean;
730
+ categoryFilterKeys: string[] | null;
731
+ /** Exact scene-graph proof for the clean section-first overview contract. */
732
+ overviewStyle: {
733
+ visibleSectionShells: number;
734
+ categoryPaintedSectionShells: number;
735
+ visibleCategoryDetailOutlines: number;
736
+ visibleSectionRowHints: number;
737
+ visibleSectionAvailabilityLabels: number;
738
+ visibleSectionGADetails: number;
739
+ };
740
+ labels: RenderedBookableLabelEvidence[];
741
+ gaAreas: RenderedGAAreaEvidence[];
742
+ hierarchyLabels: RenderedHierarchyLabelEvidence[];
743
+ freeTextLabels: RenderedFreeTextEvidence[];
744
+ }
428
745
  interface ISeatmapRenderer {
429
746
  /** Replace the chart. Resets selection and statuses, zooms to fit.
430
747
  * `opts.floorId` picks which floor to render on a multi-floor chart (Batch 5). */
@@ -461,6 +778,13 @@ interface ISeatmapRenderer {
461
778
  getStatus(seatId: string): SeatStatus;
462
779
  getSelection(): ExpandedSeat[];
463
780
  clearSelection(): void;
781
+ /** Update the buyer selection cap without rebuilding the chart or camera. */
782
+ setMaxSelection?(maxSelection: number): void;
783
+ /**
784
+ * Programmatically restore free seats (for example an Undo action). Added
785
+ * seats respect the active cap and do not reopen a confirmation popover.
786
+ */
787
+ select?(seatIds: string[]): ExpandedSeat[];
464
788
  /**
465
789
  * Dynamically update organizer-only interaction without rebuilding the
466
790
  * renderer. No buyer surface calls this; every behavior remains gated by
@@ -483,6 +807,8 @@ interface ISeatmapRenderer {
483
807
  */
484
808
  selectAllSelectable?(): ExpandedSeat[];
485
809
  selectByLabels?(labels: string[]): ExpandedSeat[];
810
+ /** Exact-render QA only: select one server-chosen unit without label ambiguity. */
811
+ setEvidenceSelection?(seatId: string): boolean;
486
812
  /** Selectable seats belonging to a section OR zone id (no selection side-effect). */
487
813
  getSelectableInSection?(sectionId: string): ExpandedSeat[];
488
814
  /** Programmatic deselect of specific seats (e.g. chip × in the cart). */
@@ -493,13 +819,21 @@ interface ISeatmapRenderer {
493
819
  * delta. Purely visual; no state change. `color` overrides the default.
494
820
  */
495
821
  flashSeat(seatId: string, color?: string): void;
822
+ /**
823
+ * Brief organizer attention pulse around a whole section. This is a visual
824
+ * overlay only: it never changes section geometry, hit targets, selection, or
825
+ * the active camera. Useful for grouped realtime operations at venue overview.
826
+ */
827
+ flashSection?(sectionId: string, color?: string): void;
496
828
  zoomToFit(): void;
497
829
  /** Zoom in one step about the viewport center, clamped to the usual zoom bounds. */
498
830
  zoomIn(): void;
499
831
  /** Zoom out one step about the viewport center, clamped to the usual zoom bounds. */
500
832
  zoomOut(): void;
501
- /** Total seat count of the current chart. */
833
+ /** Individually status-managed seats/table-seats/booths; excludes GA capacity. */
502
834
  seatCount(): number;
835
+ /** Seats/table-seats/booths plus the full capacity of rendered GA areas. */
836
+ bookableCount(): number;
503
837
  /**
504
838
  * Maps a chart-space point (or a seat, by its x/y) to container-relative
505
839
  * screen pixels, using the current stage scale/position. Lets host UI anchor
@@ -607,6 +941,9 @@ interface ISeatmapRenderer {
607
941
  getRung?(): LodRung;
608
942
  /** Jump the camera to a rung's zoom band, centred on the chart (glided). */
609
943
  setRung?(rung: LodRung): void;
944
+ /** Read actual browser-rendered label visibility, size, fill, ink and state.
945
+ * Pure diagnostic: it never changes chart or renderer state. */
946
+ getRenderedQualityEvidence(): RendererQualityEvidence;
610
947
  destroy(): void;
611
948
  }
612
949
  /** localStorage key the Designer writes and the Picker reads. */
@@ -647,6 +984,9 @@ declare function expandTable(t: TableObject): ExpandedSeat[];
647
984
  declare function expandBooth(b: BoothObject): ExpandedSeat[];
648
985
  /** Ray-cast point-in-polygon test — odd crossings ⇒ inside. */
649
986
  declare function pointInPolygon(p: Point, poly: Point[]): boolean;
987
+ declare function pointInPolygonWithHoles(p: Point, outer: Point[], holes: Point[][] | undefined): boolean;
988
+ /** Stable interior label anchor that cannot land inside a polygon cutout. */
989
+ declare function polygonLabelPoint(outer: Point[], holes: Point[][] | undefined): Point;
650
990
  /**
651
991
  * Visual centre of any object — used for spatial section membership and for
652
992
  * rotating an object about its centre. Rows: centroid of expanded seats (or
@@ -792,11 +1132,21 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
792
1132
  private circleById;
793
1133
  /** Booth block geometry, keyed by booth id (= the unit's rowId). */
794
1134
  private boothDims;
795
- /** Booth label node so status changes can say HELD/SOLD on the full block. */
1135
+ /** Booth labels live with the booth shape but obey the shared rendered-size LOD. */
796
1136
  private boothLabelById;
1137
+ /** Viewport seat labels are rebuilt after each settled camera change. */
1138
+ private seatLabelById;
1139
+ /** Authored free-text nodes obey the same rendered-size visibility floor. */
1140
+ private freeTextById;
1141
+ /** Stage/rink landmarks retain a readable screen-space caption at overview. */
1142
+ private primaryFocalLabels;
1143
+ /** GA paint and text share price/highlight filter state. */
1144
+ private gaById;
797
1145
  private statusById;
798
1146
  private catColor;
799
1147
  private theme;
1148
+ /** Opaque paint actually visible behind transparent Konva canvases. */
1149
+ private canvasBackground;
800
1150
  /** Effective selection/hover ring color — resolved per chart in setChart(). */
801
1151
  private effSelection;
802
1152
  /** Colorblind-safe mode (Okabe-Ito hues + hollow booked seats). */
@@ -913,6 +1263,8 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
913
1263
  getStatus(seatId: string): SeatStatus;
914
1264
  getSelection(): ExpandedSeat[];
915
1265
  clearSelection(): void;
1266
+ setMaxSelection(maxSelection: number): void;
1267
+ select(seatIds: string[]): ExpandedSeat[];
916
1268
  /** Switch organizer interaction in place so the host preserves camera, LOD,
917
1269
  * focus and live status state while moving between Monitor and Block. */
918
1270
  setManageInteraction(options: {
@@ -930,6 +1282,9 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
930
1282
  /** Select the selectable seats matching these public labels (category/row/
931
1283
  * section bulk resolves to labels host-side). Returns the newly added seats. */
932
1284
  selectByLabels(labels: string[]): ExpandedSeat[];
1285
+ /** Exact SDK capture helper. MCP never accepts this id; the SDK derives it
1286
+ * from the persisted floor and uses the normal selected paint/ring path. */
1287
+ setEvidenceSelection(seatId: string): boolean;
933
1288
  /** Selectable seats in a section OR zone id — pure read (no selection change). */
934
1289
  getSelectableInSection(sectionId: string): ExpandedSeat[];
935
1290
  /**
@@ -950,6 +1305,12 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
950
1305
  */
951
1306
  private finishMarquee;
952
1307
  flashSeat(seatId: string, color?: string): void;
1308
+ /**
1309
+ * Pulse a section outline without moving the camera or mutating the authored
1310
+ * geometry. The temporary halo is drawn in the non-listening overlay layer,
1311
+ * so the apparent 4% lift never changes hit testing or selection bounds.
1312
+ */
1313
+ flashSection(sectionId: string, color?: string): void;
953
1314
  private onKeyDown;
954
1315
  /** Nearest seat from `fromId` in a cardinal direction (aligned + close wins). */
955
1316
  private nearestSeat;
@@ -962,6 +1323,7 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
962
1323
  zoomIn(): void;
963
1324
  zoomOut(): void;
964
1325
  seatCount(): number;
1326
+ bookableCount(): number;
965
1327
  worldToScreen(point: Point): {
966
1328
  x: number;
967
1329
  y: number;
@@ -975,6 +1337,10 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
975
1337
  * widget resolves which categories fall inside the buyer's chosen band.
976
1338
  */
977
1339
  setCategoryFilter(keys: string[] | null): void;
1340
+ private gaCategoryDimmed;
1341
+ /** Keep GA paint and its two labels in the same legend/price-filter state. */
1342
+ private applyGAFilterState;
1343
+ private paintGAStateForView;
978
1344
  /** Frame the currently available inventory that survived a buyer price
979
1345
  * filter. Clearing the filter glides back to the full venue. */
980
1346
  focusCategories(keys: string[] | null): void;
@@ -1028,6 +1394,9 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1028
1394
  private renderBoothUnit;
1029
1395
  /** The category's display color — Okabe-Ito hue when colorblind-safe is on. */
1030
1396
  private seatBaseColor;
1397
+ /** Authored free fills retain the chart's validated ink. Renderer-owned
1398
+ * transient fills choose an ink against the paint that is actually visible. */
1399
+ private renderedBookableLabelInk;
1031
1400
  /** Apply fill/stroke/opacity for a seat's current status + selection. */
1032
1401
  private paintSeat;
1033
1402
  /** True when a seat sits in a section/zone currently marked `closed`. */
@@ -1070,7 +1439,7 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1070
1439
  width: number;
1071
1440
  height: number;
1072
1441
  };
1073
- /** Axis-aligned world bounds of all seats + section outlines (minimap F3 frame). */
1442
+ /** Axis-aligned world bounds of seats, section outlines, and GA polygons (minimap F3 frame). */
1074
1443
  getWorldBounds(): {
1075
1444
  x: number;
1076
1445
  y: number;
@@ -1099,22 +1468,18 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1099
1468
  /**
1100
1469
  * A section renders in three coordinated layers driven by the LOD melt:
1101
1470
  * • a faint outline (the existing near-zoom look, untouched),
1102
- * • a solid category-mix block that fades in at the block rung, and
1103
- * • a name + "N LEFT" sublabel.
1104
- * Membership (which seats live inside the outline) + the mix fill + the live
1105
- * availability count are precomputed here (once), not per frame.
1471
+ * • a neutral solid shell that fades in at the overview rung, and
1472
+ * • one readable, contained section name.
1473
+ * Category, row, seat, and availability detail belongs to section focus/zoom.
1474
+ * Membership and category mix are still precomputed for the detailed state.
1106
1475
  */
1107
1476
  private renderSection;
1108
1477
  private refreshSectionHeat;
1109
- /** Recompute a section's availability-tinted fill + "N LEFT" (cheap; on status change). */
1478
+ /** Recompute a section's neutral overview state and retained detail count. */
1110
1479
  private refreshSectionFill;
1111
1480
  /** True when a section/zone is currently in the `closed` event-state. */
1112
1481
  private isSectionClosed;
1113
- /**
1114
- * The block-fill colour for a section: flat desaturated grey when `closed`,
1115
- * else the availability-darkened category mix; then desaturated toward neutral
1116
- * when another section holds focus (AXS dim treatment).
1117
- */
1482
+ /** Clean overview shells never leak category, price, or live availability paint. */
1118
1483
  private sectionBlockFill;
1119
1484
  /**
1120
1485
  * Zone rung: one giant screen-constant label per zone (+ optional "FROM $n"),
@@ -1132,17 +1497,19 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1132
1497
  * Section/zone labels are scale-compensated to hold a roughly constant screen size.
1133
1498
  */
1134
1499
  private applySectionLod;
1500
+ /** One semantic section gets one overview label, even across split contours. */
1501
+ private dedupeLogicalSectionLabels;
1135
1502
  /**
1136
- * Greedy label de-collision for the zone/section rungs (same approach as the
1137
- * designer's cullRowLabels): price/"N LEFT" sublabels are lowest priority and
1138
- * drop first; name labels keep top-to-bottom, left-to-right; anything whose
1139
- * on-screen box (+4px gap) overlaps an already-kept box hides. Recomputed on
1140
- * every LOD pass so hidden labels reappear as zoom spreads them apart.
1141
- * Culling multiplies the opacity applySectionLod just assigned (never raises).
1503
+ * Keep transitional zone pills from covering section names. Section names
1504
+ * are already proven inside disjoint shells, so they must not cull each other.
1142
1505
  */
1143
1506
  private decollideRungLabels;
1144
1507
  /** Set a centred label's world fontSize (for a target screen px) and re-anchor it. */
1145
1508
  private sizeLabel;
1509
+ /** Fit one centred section name, rotating narrow shells like the target chart. */
1510
+ private fitSectionRungLabels;
1511
+ /** Size one screen-constant zone name/price pill around its shared anchor. */
1512
+ private sizeZonePill;
1146
1513
  /**
1147
1514
  * Map a container-relative screen point back to world coords. Inverts the
1148
1515
  * stage (scale/pos) and, in iso view, the iso affine — so screen-space taps
@@ -1168,6 +1535,7 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1168
1535
  * the container's computed CSS background (walking up past transparent
1169
1536
  * ancestors). Unknown/unparseable backgrounds keep the dark default.
1170
1537
  */
1538
+ private resolveCanvasBackground;
1171
1539
  private resolveSelectionColor;
1172
1540
  private setSelected;
1173
1541
  /** Rebuild one marker after selected/held/candidate state changes. */
@@ -1179,6 +1547,7 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1179
1547
  * whether the section already fills the viewport (small container) so the tap
1180
1548
  * must fall through and pick.
1181
1549
  */
1550
+ private sectionBounds;
1182
1551
  private sectionFrameScale;
1183
1552
  /**
1184
1553
  * Resolve a seat tap: honour the 3D deck-drill and the AXS seat-pick gate,
@@ -1241,8 +1610,17 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1241
1610
  private cancelGlide;
1242
1611
  /** Current LOD rung derived from effective zoom — drives the ZONES/SECTIONS/SEATS pill. */
1243
1612
  getRung(): LodRung;
1244
- /** Jump the camera to a rung's zoom band, centred on the chart (glided). */
1613
+ getRenderedQualityEvidence(): RendererQualityEvidence;
1614
+ /** Jump the camera to a rung's zoom band (glided). */
1245
1615
  setRung(rung: LodRung): void;
1616
+ /**
1617
+ * The seat rung must account for labels that auto-fit inside a seat circle.
1618
+ * A short `A-1` remains at the normal 7u target; a table label such as
1619
+ * `T13-10` may fit at 4u and therefore needs a deeper camera target to reach
1620
+ * the same 12 CSS-pixel floor. Measurement happens only on explicit rung
1621
+ * navigation, never during pan/zoom frames.
1622
+ */
1623
+ private seatLabelTargetScale;
1246
1624
  /** Recompute LOD (cache/labels) after any pan/zoom settles. */
1247
1625
  private afterViewChange;
1248
1626
  /** rAF-coalesced `onViewChange` — at most one host callback per animation frame. */
@@ -1264,6 +1642,7 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1264
1642
  * byte-identical.
1265
1643
  */
1266
1644
  forceDraw(): void;
1645
+ private updateFreeTextVisibility;
1267
1646
  private updateLabels;
1268
1647
  private handleResize;
1269
1648
  private startFpsLoop;
@@ -1462,7 +1841,7 @@ declare class PickerController {
1462
1841
  private readonly opts;
1463
1842
  private readonly api;
1464
1843
  private readonly key;
1465
- private readonly maxSelection;
1844
+ private maxSelection;
1466
1845
  private renderer;
1467
1846
  private _doc;
1468
1847
  /** Section/zone ids hidden from buyers this event (3.3) — seats vanish, not grey. */
@@ -1523,6 +1902,8 @@ declare class PickerController {
1523
1902
  seatDetails(seatId: string): SeatHoverDetails | null;
1524
1903
  clearSelection(): void;
1525
1904
  deselect(ids: string[]): void;
1905
+ setMaxSelection(maxSelection: number): void;
1906
+ select(ids: string[]): PickerSeat[];
1526
1907
  /**
1527
1908
  * Hold the current selection (or a given label set). The controller does the
1528
1909
  * renderer/hold side (409 → deselect + repaint the taken seats held) and then
@@ -1802,4 +2183,4 @@ declare function formatMoney(amount: number, currency?: string, fractionDigits?:
1802
2183
  /** Bare symbol for input adornments ("€", "$", "₹"). */
1803
2184
  declare function currencySymbol(currency?: string): string;
1804
2185
 
1805
- export { ACCESSIBILITY_TYPES, type AccessibilityMeta, type AccessibilityType, type AvailabilityRule, type BoothObject, CHART_STORAGE_KEY, type Category, type CategoryTier, type ChartDoc, type ChartObject, type ChartTheme, DEFAULT_CURRENCY, type DecorImageObject, type Dict, type ExpandedSeat, type Floor, type GAAreaObject, type HoldConflict, type HoldInfo, type HoldSelectionRequest, type HoldServerItem, type ISeatmapRenderer, type Locale, type LodRung, MAX_EVENT_INVENTORY, MAX_GA_CAPACITY, type PanoramaResult, type PickerCallbacks, PickerController, type PickerOptions, type PickerSeat, type PickerTransport, type Point, type RendererCallbacks, type RendererOptions, type RowObject, type RowSeatSlot, SUPPORTED_LOCALES, type SeatHoverDetails, type SeatOverride, type SeatStatus, SeatmapRenderer, type SectionCategory, type SectionNode, type SectionObject, type SectionSummary, type SelectionLayer, type ShapeObject, type TableObject, type TextObject, UNGROUPED_ID, type ZoneDef, accessibilityMeta, allObjects, applyHidden, chartBounds, computeSections, createRenderer, currencySymbol, expandBooth, expandChart, expandRow, expandRowSlots, expandTable, floorObjects, floorsOf, formatDate, formatMoney, gaAreasOf, gaUnitLabel, gaUnitLabels, generateSeatPanorama, generateSeatThumb, getLocale, hiddenObjectIds, isGaUnitLabel, isSectionHidden, layerOf, loadLocale, objectCenter, pointInPolygon, resolveLocale, setLocale, setMoneyLocale, setStringOverrides, stackFloors, t, tCount };
2186
+ export { ACCESSIBILITY_TYPES, type AccessibilityMeta, type AccessibilityType, type AvailabilityRule, type BoothObject, CHART_STORAGE_KEY, type Category, type CategoryTier, type ChartDoc, type ChartObject, type ChartReferenceImage, type ChartTheme, type CubicPath, DEFAULT_CURRENCY, type DecorImageObject, type Dict, type ExpandedSeat, type Floor, type GAAreaObject, type HoldConflict, type HoldInfo, type HoldSelectionRequest, type HoldServerItem, type ISeatmapRenderer, type Locale, type LodRung, MAX_EVENT_INVENTORY, MAX_GA_CAPACITY, type PanoramaResult, type PickerCallbacks, PickerController, type PickerOptions, type PickerSeat, type PickerTransport, type Point, type ReferenceAccessibilitySource, type ReferenceCalibration, type ReferenceCategorySource, type ReferenceDerivedScale, type ReferenceInventoryExclusionSource, type ReferenceInventorySource, type RenderedBookableLabelEvidence, type RenderedFreeTextEvidence, type RenderedGAAreaEvidence, type RenderedHierarchyLabelEvidence, type RenderedLabelHiddenReason, type RendererCallbacks, type RendererOptions, type RendererQualityEvidence, type RowObject, type RowSeatSlot, SUPPORTED_LOCALES, type SeatHoverDetails, type SeatOverride, type SeatStatus, SeatmapRenderer, type SectionCategory, type SectionNode, type SectionObject, type SectionOutlinePath, type SectionPathSegment, type SectionSummary, type SelectionLayer, type ShapeObject, type TableObject, type TextObject, UNGROUPED_ID, type ZoneDef, accessibilityMeta, allObjects, applyHidden, chartBounds, computeSections, createRenderer, currencySymbol, expandBooth, expandChart, expandRow, expandRowSlots, expandTable, floorObjects, floorsOf, formatDate, formatMoney, gaAreasOf, gaUnitLabel, gaUnitLabels, generateSeatPanorama, generateSeatThumb, getLocale, hiddenObjectIds, isGaUnitLabel, isSectionHidden, layerOf, loadLocale, objectCenter, pointInPolygon, pointInPolygonWithHoles, polygonLabelPoint, resolveLocale, setLocale, setMoneyLocale, setStringOverrides, stackFloors, t, tCount };