@seatlayer/core 0.28.3 → 0.29.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.
@@ -0,0 +1,53 @@
1
+ // src/core/units.ts
2
+ var METRES_PER_CHART_UNIT = 0.55 / 24;
3
+ var CHART_UNITS_PER_METRE = 1 / METRES_PER_CHART_UNIT;
4
+ var LIFT_PER_STEP_WORLD = 58;
5
+ var TIER_HEIGHT_M = LIFT_PER_STEP_WORLD * METRES_PER_CHART_UNIT;
6
+ var SECTION_ELEVATION_TIER_MIN = 0;
7
+ var SECTION_ELEVATION_TIER_MAX = 3;
8
+ var SECTION_HEIGHT_MIN_M = 0;
9
+ var SECTION_HEIGHT_MAX_M = 120;
10
+ var SECTION_RAKE_MIN_DEG = 0;
11
+ var SECTION_RAKE_MAX_DEG = 45;
12
+ var LEGACY_SECTION_ELEVATION_TIER_MAX = 7;
13
+ var SEATED_EYE_HEIGHT_M = 1.2;
14
+ function finiteClamped(value, min, max, fallback) {
15
+ return Number.isFinite(value) ? Math.max(min, Math.min(max, value)) : fallback;
16
+ }
17
+ function sectionElevationTier(value) {
18
+ if (!Number.isFinite(value)) return SECTION_ELEVATION_TIER_MIN;
19
+ return Math.max(
20
+ SECTION_ELEVATION_TIER_MIN,
21
+ Math.min(SECTION_ELEVATION_TIER_MAX, Math.round(value))
22
+ );
23
+ }
24
+ function compatibleAutomaticTier(value) {
25
+ if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) return 0;
26
+ if (value <= LEGACY_SECTION_ELEVATION_TIER_MAX) return value;
27
+ return SECTION_ELEVATION_TIER_MAX;
28
+ }
29
+ function sectionGeometry(section, context = {}) {
30
+ const floorBaseHeightM = finiteClamped(
31
+ context.floorBaseHeightM,
32
+ SECTION_HEIGHT_MIN_M,
33
+ SECTION_HEIGHT_MAX_M,
34
+ 0
35
+ );
36
+ const automaticHeight = Math.min(
37
+ SECTION_HEIGHT_MAX_M,
38
+ floorBaseHeightM + compatibleAutomaticTier(section.elevation) * TIER_HEIGHT_M
39
+ );
40
+ const height = section.height === void 0 ? automaticHeight : finiteClamped(section.height, SECTION_HEIGHT_MIN_M, SECTION_HEIGHT_MAX_M, automaticHeight);
41
+ const rake = finiteClamped(section.rake, SECTION_RAKE_MIN_DEG, SECTION_RAKE_MAX_DEG, 0);
42
+ return { height, rake };
43
+ }
44
+
45
+ export {
46
+ METRES_PER_CHART_UNIT,
47
+ CHART_UNITS_PER_METRE,
48
+ TIER_HEIGHT_M,
49
+ SEATED_EYE_HEIGHT_M,
50
+ sectionElevationTier,
51
+ sectionGeometry
52
+ };
53
+ //# sourceMappingURL=chunk-5MLADB2N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/units.ts"],"sourcesContent":["/**\n * Real-world scale primitives — the ONE place the app fixes chart-unit ↔ metre ↔\n * renderer-world scale, and the section 3D-geometry resolver that rides on it.\n *\n * Everything that converts between chart units, metres, and renderer \"world\"\n * units derives from {@link METRES_PER_CHART_UNIT}. Renderer world units and\n * chart units are 1:1, so metres → world is exactly {@link CHART_UNITS_PER_METRE}\n * (the single m→world conversion constant Phase B consumers use).\n *\n * This is a leaf module (types only) so both `layout.ts` and `sections.ts` can\n * import it without the two forming an import cycle.\n */\nimport type { SectionObject } from './types';\n\n/**\n * Chart units → metres. seatSpacing 24 ≈ 0.55 m (a real seat pitch). This single\n * constant anchors every real-world scale in the app; `generatePanorama` and the\n * iso lift both derive from it instead of re-declaring their own 0.55/24.\n */\nexport const METRES_PER_CHART_UNIT = 0.55 / 24;\n\n/**\n * Metres → chart units, i.e. metres → renderer world units (world == chart units\n * in the engine). THE single m→world conversion constant: the iso view lifts an\n * elevated section by `sectionGeometry(section).height × CHART_UNITS_PER_METRE`.\n */\nexport const CHART_UNITS_PER_METRE = 1 / METRES_PER_CHART_UNIT;\n\n/**\n * Renderer world units a section lifts per {@link SectionObject.elevation} tier in\n * the legacy iso view (mirror of `SeatmapRenderer`'s old `LIFT_PER_STEP`). Kept so\n * the tier→metres fallback below reproduces today's iso look byte-for-byte.\n */\nexport const LIFT_PER_STEP_WORLD = 58;\n\n/**\n * Metres of front-edge height one elevation tier represents. Chosen (not guessed)\n * so `elevation × TIER_HEIGHT_M` metres, scaled back through\n * {@link CHART_UNITS_PER_METRE}, equals the legacy `elevation × LIFT_PER_STEP`\n * world lift exactly — an un-authored chart stays pixel-identical. ≈ 1.329 m/tier.\n */\nexport const TIER_HEIGHT_M = LIFT_PER_STEP_WORLD * METRES_PER_CHART_UNIT;\n\n/** Canonical authored section-geometry bounds. Keep every UI/API/renderer on\n * these constants so a producer cannot silently invent a second unit system. */\nexport const SECTION_ELEVATION_TIER_MIN = 0;\nexport const SECTION_ELEVATION_TIER_MAX = 3;\nexport const SECTION_HEIGHT_MIN_M = 0;\nexport const SECTION_HEIGHT_MAX_M = 120;\nexport const SECTION_RAKE_MIN_DEG = 0;\nexport const SECTION_RAKE_MAX_DEG = 45;\n\n/** Curated charts released before the height field used coarse levels 4–7.\n * Preserve their established lift while drafts/templates migrate to an explicit\n * height. Values above 7 came from broken compiler multipliers and must never be\n * interpreted as physical tiers. */\nexport const LEGACY_SECTION_ELEVATION_TIER_MAX = 7;\n\n/**\n * Seated spectator eye height above the tier floor (arena ≈ 1.20 m; theatre refs\n * use 1.15 m). Also the flat-ground baseline eye height, so a flat, ground-level\n * seat produces zero elevation offset in the 360° stage-pitch math (back-compat).\n */\nexport const SEATED_EYE_HEIGHT_M = 1.2;\n\n/**\n * Resolve a section's real 3D geometry, applying the legacy-elevation fallback so\n * old charts and new charts share ONE code path. Every consumer (iso lift, 360°\n * eye-height, author lint, any 2D depth cue) must call this and never read the raw\n * {@link SectionObject.height}/{@link SectionObject.rake} fields — that is what\n * keeps un-authored charts rendering identically to today.\n *\n * - `height`: authored absolute metres if present, else owning-floor base height\n * plus `elevation × TIER_HEIGHT_M`.\n * - `rake`: authored degrees if present, else 0 (flat).\n *\n * Malformed values are bounded here as a last defensive barrier. Structural\n * validation still reports them so drafts can be repaired instead of silently\n * persisting a renderer-only interpretation.\n *\n * Pure — no document mutation, no side effects.\n */\nexport interface SectionGeometryContext {\n /** Absolute physical height of the owning floor above the venue datum. */\n floorBaseHeightM?: number;\n}\n\nfunction finiteClamped(value: number | undefined, min: number, max: number, fallback: number): number {\n return Number.isFinite(value) ? Math.max(min, Math.min(max, value as number)) : fallback;\n}\n\n/** Canonical 0–3 tier exposed by Designer/shared operations. */\nexport function sectionElevationTier(value: number | undefined): number {\n if (!Number.isFinite(value)) return SECTION_ELEVATION_TIER_MIN;\n return Math.max(\n SECTION_ELEVATION_TIER_MIN,\n Math.min(SECTION_ELEVATION_TIER_MAX, Math.round(value as number)),\n );\n}\n\n/** Runtime-only compatibility tier. Released curated charts used integers 4–7;\n * preserve those while bounding compiler mistakes such as 12/55/220 to the\n * canonical maximum. New documents must store only {@link sectionElevationTier}. */\nfunction compatibleAutomaticTier(value: number | undefined): number {\n if (!Number.isFinite(value) || !Number.isInteger(value) || (value as number) < 0) return 0;\n if ((value as number) <= LEGACY_SECTION_ELEVATION_TIER_MAX) return value as number;\n return SECTION_ELEVATION_TIER_MAX;\n}\n\nexport function sectionGeometry(\n section: Pick<SectionObject, 'elevation' | 'height' | 'rake'>,\n context: SectionGeometryContext = {},\n): {\n height: number;\n rake: number;\n} {\n const floorBaseHeightM = finiteClamped(\n context.floorBaseHeightM,\n SECTION_HEIGHT_MIN_M,\n SECTION_HEIGHT_MAX_M,\n 0,\n );\n const automaticHeight = Math.min(\n SECTION_HEIGHT_MAX_M,\n floorBaseHeightM + compatibleAutomaticTier(section.elevation) * TIER_HEIGHT_M,\n );\n const height = section.height === undefined\n ? automaticHeight\n : finiteClamped(section.height, SECTION_HEIGHT_MIN_M, SECTION_HEIGHT_MAX_M, automaticHeight);\n const rake = finiteClamped(section.rake, SECTION_RAKE_MIN_DEG, SECTION_RAKE_MAX_DEG, 0);\n return { height, rake };\n}\n"],"mappings":";AAmBO,IAAM,wBAAwB,OAAO;AAOrC,IAAM,wBAAwB,IAAI;AAOlC,IAAM,sBAAsB;AAQ5B,IAAM,gBAAgB,sBAAsB;AAI5C,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AACnC,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAM7B,IAAM,oCAAoC;AAO1C,IAAM,sBAAsB;AAwBnC,SAAS,cAAc,OAA2B,KAAa,KAAa,UAA0B;AACpG,SAAO,OAAO,SAAS,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAe,CAAC,IAAI;AAClF;AAGO,SAAS,qBAAqB,OAAmC;AACtE,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,SAAO,KAAK;AAAA,IACV;AAAA,IACA,KAAK,IAAI,4BAA4B,KAAK,MAAM,KAAe,CAAC;AAAA,EAClE;AACF;AAKA,SAAS,wBAAwB,OAAmC;AAClE,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,CAAC,OAAO,UAAU,KAAK,KAAM,QAAmB,EAAG,QAAO;AACzF,MAAK,SAAoB,kCAAmC,QAAO;AACnE,SAAO;AACT;AAEO,SAAS,gBACd,SACA,UAAkC,CAAC,GAInC;AACA,QAAM,mBAAmB;AAAA,IACvB,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,kBAAkB,KAAK;AAAA,IAC3B;AAAA,IACA,mBAAmB,wBAAwB,QAAQ,SAAS,IAAI;AAAA,EAClE;AACA,QAAM,SAAS,QAAQ,WAAW,SAC9B,kBACA,cAAc,QAAQ,QAAQ,sBAAsB,sBAAsB,eAAe;AAC7F,QAAM,OAAO,cAAc,QAAQ,MAAM,sBAAsB,sBAAsB,CAAC;AACtF,SAAO,EAAE,QAAQ,KAAK;AACxB;","names":[]}