@vscada/core 0.0.1

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 (145) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/a11y/contrast.d.ts +11 -0
  3. package/dist/a11y/contrast.d.ts.map +1 -0
  4. package/dist/a11y/live-region.d.ts +42 -0
  5. package/dist/a11y/live-region.d.ts.map +1 -0
  6. package/dist/a11y/reduced-motion.d.ts +55 -0
  7. package/dist/a11y/reduced-motion.d.ts.map +1 -0
  8. package/dist/a11y/static-representation-registry.d.ts +20 -0
  9. package/dist/a11y/static-representation-registry.d.ts.map +1 -0
  10. package/dist/bindings/binding-fixture.d.ts +3 -0
  11. package/dist/bindings/binding-fixture.d.ts.map +1 -0
  12. package/dist/bindings/binding-types.d.ts +52 -0
  13. package/dist/bindings/binding-types.d.ts.map +1 -0
  14. package/dist/bindings/color-ramp.d.ts +9 -0
  15. package/dist/bindings/color-ramp.d.ts.map +1 -0
  16. package/dist/bindings/transforms.d.ts +103 -0
  17. package/dist/bindings/transforms.d.ts.map +1 -0
  18. package/dist/constants-DMdpoOyH.js +4 -0
  19. package/dist/contracts/connection-renderer.d.ts +16 -0
  20. package/dist/contracts/connection-renderer.d.ts.map +1 -0
  21. package/dist/contracts/connection-state.d.ts +8 -0
  22. package/dist/contracts/connection-state.d.ts.map +1 -0
  23. package/dist/contracts/handles.d.ts +83 -0
  24. package/dist/contracts/handles.d.ts.map +1 -0
  25. package/dist/contracts/primitive.d.ts +37 -0
  26. package/dist/contracts/primitive.d.ts.map +1 -0
  27. package/dist/contracts/renderer.d.ts +34 -0
  28. package/dist/contracts/renderer.d.ts.map +1 -0
  29. package/dist/contracts/tag-value.d.ts +33 -0
  30. package/dist/contracts/tag-value.d.ts.map +1 -0
  31. package/dist/contracts/time-source.d.ts +14 -0
  32. package/dist/contracts/time-source.d.ts.map +1 -0
  33. package/dist/custom-elements.json +1068 -0
  34. package/dist/export/svg-export.d.ts +24 -0
  35. package/dist/export/svg-export.d.ts.map +1 -0
  36. package/dist/fsm/fsm.d.ts +45 -0
  37. package/dist/fsm/fsm.d.ts.map +1 -0
  38. package/dist/fsm/tween.d.ts +39 -0
  39. package/dist/fsm/tween.d.ts.map +1 -0
  40. package/dist/import/load-svg-import.d.ts +22 -0
  41. package/dist/import/load-svg-import.d.ts.map +1 -0
  42. package/dist/import/svg-source-registry.d.ts +4 -0
  43. package/dist/import/svg-source-registry.d.ts.map +1 -0
  44. package/dist/index.d.ts +61 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +4549 -0
  47. package/dist/interaction/gesture-arbiter.d.ts +20 -0
  48. package/dist/interaction/gesture-arbiter.d.ts.map +1 -0
  49. package/dist/interaction/hit-area.d.ts +44 -0
  50. package/dist/interaction/hit-area.d.ts.map +1 -0
  51. package/dist/interaction/pan-zoom-gestures.d.ts +43 -0
  52. package/dist/interaction/pan-zoom-gestures.d.ts.map +1 -0
  53. package/dist/interaction/pointer-pipeline.d.ts +38 -0
  54. package/dist/interaction/pointer-pipeline.d.ts.map +1 -0
  55. package/dist/license/console-notice.d.ts +15 -0
  56. package/dist/license/console-notice.d.ts.map +1 -0
  57. package/dist/license/format.d.ts +29 -0
  58. package/dist/license/format.d.ts.map +1 -0
  59. package/dist/license/state.d.ts +43 -0
  60. package/dist/license/state.d.ts.map +1 -0
  61. package/dist/license/vendor-keys.d.ts +12 -0
  62. package/dist/license/vendor-keys.d.ts.map +1 -0
  63. package/dist/license/verify-fallback.d.ts +31 -0
  64. package/dist/license/verify-fallback.d.ts.map +1 -0
  65. package/dist/license/verify-webcrypto.d.ts +4 -0
  66. package/dist/license/verify-webcrypto.d.ts.map +1 -0
  67. package/dist/license/watermark.d.ts +20 -0
  68. package/dist/license/watermark.d.ts.map +1 -0
  69. package/dist/media/registry.d.ts +97 -0
  70. package/dist/media/registry.d.ts.map +1 -0
  71. package/dist/registry/connection-registry.d.ts +5 -0
  72. package/dist/registry/connection-registry.d.ts.map +1 -0
  73. package/dist/registry/element-catalog.d.ts +805 -0
  74. package/dist/registry/element-catalog.d.ts.map +1 -0
  75. package/dist/registry/primitive-registry.d.ts +7 -0
  76. package/dist/registry/primitive-registry.d.ts.map +1 -0
  77. package/dist/registry/theme-registry.d.ts +6 -0
  78. package/dist/registry/theme-registry.d.ts.map +1 -0
  79. package/dist/registry.d.ts +8 -0
  80. package/dist/registry.d.ts.map +1 -0
  81. package/dist/scada-view.d.ts +322 -0
  82. package/dist/scada-view.d.ts.map +1 -0
  83. package/dist/scene/connection-geometry.d.ts +95 -0
  84. package/dist/scene/connection-geometry.d.ts.map +1 -0
  85. package/dist/scene/constants.d.ts +10 -0
  86. package/dist/scene/constants.d.ts.map +1 -0
  87. package/dist/scene/crossing-jumps.d.ts +85 -0
  88. package/dist/scene/crossing-jumps.d.ts.map +1 -0
  89. package/dist/scene/dev-validate.d.ts +24 -0
  90. package/dist/scene/dev-validate.d.ts.map +1 -0
  91. package/dist/scene/errors.d.ts +15 -0
  92. package/dist/scene/errors.d.ts.map +1 -0
  93. package/dist/scene/groups.d.ts +90 -0
  94. package/dist/scene/groups.d.ts.map +1 -0
  95. package/dist/scene/lane-offset.d.ts +69 -0
  96. package/dist/scene/lane-offset.d.ts.map +1 -0
  97. package/dist/scene/orthogonal-router.d.ts +63 -0
  98. package/dist/scene/orthogonal-router.d.ts.map +1 -0
  99. package/dist/scene/scene-schema.d.ts +881 -0
  100. package/dist/scene/scene-schema.d.ts.map +1 -0
  101. package/dist/scene/structural-validator.d.ts +25 -0
  102. package/dist/scene/structural-validator.d.ts.map +1 -0
  103. package/dist/scene/validate-scene.d.ts +26 -0
  104. package/dist/scene/validate-scene.d.ts.map +1 -0
  105. package/dist/scene-authoring.d.ts +12 -0
  106. package/dist/scene-authoring.d.ts.map +1 -0
  107. package/dist/scene-authoring.js +952 -0
  108. package/dist/scheduler/alarm-band.d.ts +33 -0
  109. package/dist/scheduler/alarm-band.d.ts.map +1 -0
  110. package/dist/scheduler/animation-registry.d.ts +38 -0
  111. package/dist/scheduler/animation-registry.d.ts.map +1 -0
  112. package/dist/scheduler/lod.d.ts +25 -0
  113. package/dist/scheduler/lod.d.ts.map +1 -0
  114. package/dist/scheduler/quality-overlay.d.ts +19 -0
  115. package/dist/scheduler/quality-overlay.d.ts.map +1 -0
  116. package/dist/scheduler/quality.d.ts +15 -0
  117. package/dist/scheduler/quality.d.ts.map +1 -0
  118. package/dist/scheduler/scheduler.d.ts +243 -0
  119. package/dist/scheduler/scheduler.d.ts.map +1 -0
  120. package/dist/scheduler/visual-state-resolver.d.ts +31 -0
  121. package/dist/scheduler/visual-state-resolver.d.ts.map +1 -0
  122. package/dist/store/value-store.d.ts +65 -0
  123. package/dist/store/value-store.d.ts.map +1 -0
  124. package/dist/tokens.d.ts +703 -0
  125. package/dist/tokens.d.ts.map +1 -0
  126. package/dist/topology/graph.d.ts +33 -0
  127. package/dist/topology/graph.d.ts.map +1 -0
  128. package/dist/topology/group-collapse.d.ts +15 -0
  129. package/dist/topology/group-collapse.d.ts.map +1 -0
  130. package/dist/topology/inference.d.ts +71 -0
  131. package/dist/topology/inference.d.ts.map +1 -0
  132. package/dist/topology/traversal.d.ts +29 -0
  133. package/dist/topology/traversal.d.ts.map +1 -0
  134. package/dist/topology/upstream-highlight.d.ts +75 -0
  135. package/dist/topology/upstream-highlight.d.ts.map +1 -0
  136. package/dist/units/formatter.d.ts +22 -0
  137. package/dist/units/formatter.d.ts.map +1 -0
  138. package/dist/units/registry.d.ts +21 -0
  139. package/dist/units/registry.d.ts.map +1 -0
  140. package/dist/view/group-view-state.d.ts +77 -0
  141. package/dist/view/group-view-state.d.ts.map +1 -0
  142. package/dist/view/viewport-state.d.ts +112 -0
  143. package/dist/view/viewport-state.d.ts.map +1 -0
  144. package/dist/vscada.umd.cjs +45 -0
  145. package/package.json +37 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-catalog.d.ts","sourceRoot":"","sources":["../../src/registry/element-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,aAAa,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACvC;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2PmB,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,eAAe,CAAC;AAC3D,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,eAAe,IAAI,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { PrimitiveGroup, PrimitiveModule } from '../contracts/primitive';
2
+ export declare function registerPrimitives(...groups: PrimitiveGroup[]): void;
3
+ export declare function getPrimitiveBuilder(type: string): PrimitiveModule | undefined;
4
+ export declare function getRegisteredTypes(): ReadonlySet<string>;
5
+ /** Test-only: registration is module-level global state shared across a test file. */
6
+ export declare function __resetPrimitiveRegistryForTests(): void;
7
+ //# sourceMappingURL=primitive-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitive-registry.d.ts","sourceRoot":"","sources":["../../src/registry/primitive-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAW9E,wBAAgB,kBAAkB,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CASpE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAE7E;AAED,wBAAgB,kBAAkB,IAAI,WAAW,CAAC,MAAM,CAAC,CAExD;AAED,sFAAsF;AACtF,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD"}
@@ -0,0 +1,6 @@
1
+ import type { ThemeTokens } from '../tokens';
2
+ export declare function registerThemes(...themes: ThemeTokens[]): void;
3
+ /** Falls back to an empty, pipe-less token set so unregistered themes degrade gracefully rather than crash. */
4
+ export declare function getThemeTokens(name: string): ThemeTokens;
5
+ export declare function __resetThemeRegistryForTests(): void;
6
+ //# sourceMappingURL=theme-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-registry.d.ts","sourceRoot":"","sources":["../../src/registry/theme-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAc7C,wBAAgB,cAAc,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAI7D;AAED,+GAA+G;AAC/G,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAExD;AAED,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Supply side of Story 1.2's `knownTypes` seam. Story 1.2 wired a
3
+ * placeholder (empty set); this now delegates to the real primitive
4
+ * registry (AD-3) — the structural validator itself is untouched, exactly
5
+ * as that story's seam was designed to allow.
6
+ */
7
+ export declare function getKnownElementTypes(): ReadonlySet<string>;
8
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,WAAW,CAAC,MAAM,CAAC,CAE1D"}
@@ -0,0 +1,322 @@
1
+ import { LitElement, type PropertyValues } from 'lit';
2
+ import type { Scene } from './scene/scene-schema';
3
+ import type { TagValue } from './contracts/tag-value';
4
+ import type { ConnectionState } from './contracts/connection-state';
5
+ import { type TimeSource } from './contracts/time-source';
6
+ import { type Renderer } from './contracts/renderer';
7
+ import { type SchedulerMode } from './scheduler/scheduler';
8
+ import { type AnimationPriority } from './scheduler/animation-registry';
9
+ import { type MatchMediaFn } from './a11y/reduced-motion';
10
+ /**
11
+ * Story 4.3 Task 2 — infers each animation handle's LOD-cap priority
12
+ * tier from its OWN synthetic handle-map key, which every primitive that
13
+ * registers an `AnimationHandle` already names systematically (never a
14
+ * real tag): `recipe.ts`'s `__vessel-wave-animation-${id}`,
15
+ * `rotation-drive/base.ts`'s `__rotating-animations-${id}`, and
16
+ * `conveyance/pipe`'s `nextId('pipe-flow-animation')`. Zero primitive-
17
+ * package changes needed for this — `_registerHandles` is the one place
18
+ * every primitive's `HandleMap` already funnels through.
19
+ *
20
+ * Known limitation, not introduced by this story: `rotation-drive/base.ts`
21
+ * bundles a driven-equipment element's rotation AND its state-lamp blink
22
+ * into ONE combined pause/resume handle (pre-existing architecture), so
23
+ * that handle is tagged `'rotation'`, not `'state-lamp'` — under a very
24
+ * tight LOD cap, a running pump's blink could pause alongside its
25
+ * rotation.
26
+ *
27
+ * Architecture code audit (2026-08-27, AD-5 finding P1-1) — the STANDALONE
28
+ * `indicator-lamp` primitive used to never register through
29
+ * `AnimationRegistry` at all (its blink was driven by direct
30
+ * `AnimationControl` calls inline in its own state handler), which meant a
31
+ * stale/disconnected scene could not freeze it either — the exact failure
32
+ * AD-5 exists to prevent. It now registers its blink as a proper
33
+ * `AnimationHandle` (`__indicator-lamp-animation-${id}`), tagged
34
+ * `'state-lamp'` here so it both respects freeze-on-stale AND keeps the
35
+ * originally-intended "state-lamps survive longest" property deliberately,
36
+ * via the rank-0 tier `ANIMATION_PRIORITY_RANK` already defined for it,
37
+ * rather than accidentally via non-registration.
38
+ *
39
+ * Story 3.8 — `vapor/base.ts`'s `__vapor-drift-animation-${id}` (plume and
40
+ * steam-vent's shared billow-drift handle) is tagged `'wave'`, the same
41
+ * tier as the vessel liquid wave: both are ambient, lowest-priority-to-
42
+ * survive continuous motion under a tight LOD cap, never safety-critical.
43
+ * Exported so this mapping is directly unit-testable without standing up a
44
+ * full scene (mirrors every other primitive-package registration site's
45
+ * own doc comment above — no primitive-package code needed here either).
46
+ */
47
+ export declare function inferAnimationPriority(handleKey: string): AnimationPriority;
48
+ /**
49
+ * Root element. Story 1.1 proved Lit + Shadow DOM wiring; Story 1.2 added
50
+ * the `scene` validation pipeline (AD-8). This story wires the actual
51
+ * frame pipeline (AD-1): `values`/`setValues()` feed the store; the single
52
+ * per-instance scheduler reads it on each tick and writes through handles
53
+ * → renderer. `TimeSource`/`Renderer` are constructor-injectable for
54
+ * tests (spec §8.4); real usage via `document.createElement`/markup uses
55
+ * the live defaults.
56
+ *
57
+ * @customElement scada-view
58
+ *
59
+ * @fires {CustomEvent<SceneErrorDetail>} scene-error - A structurally invalid `scene` assignment (AD-8), or a dev-only Zod diagnostic on an otherwise-valid one. Structural failures render nothing until a valid scene is assigned.
60
+ * @fires {CustomEvent<ValueWarningDetail>} value-warning - Dev-only: a pushed `TagValue` didn't map to any declared binding/state/threshold for its element.
61
+ * @fires {CustomEvent<ElementClickDetail>} element-click - A scene element's (or collapsed group's) hit area was activated by click/tap/keyboard, while `interactive` is true (§3.4).
62
+ * @fires {CustomEvent<ElementHoverDetail>} element-hover - A fine (mouse) pointer entered a scene element's hit area (§3.4).
63
+ * @fires {CustomEvent<RenderStats>} render-stats - Once per second while `debug` is true: frame-timing/element-count accounting for perf diagnostics (§3.2 `debug`).
64
+ *
65
+ * @attr {string} license-key - Plain-HTML-attribute fallback for `setLicenseKey()` (Story 6.2 Task 2). Module-level, not per-instance.
66
+ * @attr {string} tag-prefix - Plain-HTML-attribute fallback for the `tagPrefix` property (Story 2.6 AC2).
67
+ * @attr {string} interactive - Plain-HTML-attribute fallback for the `interactive` property. Any value other than the literal `"false"` means interactive.
68
+ * @attr {string} mode - Plain-HTML-attribute fallback for the `mode` property. `"static"` selects static mode; any other value (including absent) means live.
69
+ * @attr {string} animated - Plain-HTML-attribute fallback for the `animated` property. Any value other than the literal `"false"` means animated.
70
+ *
71
+ * @cssprop [--vscada-focus-ring-color=#2c7be5] - Keyboard focus ring color (§11), resolved from the active theme's `focusRing` token when declared.
72
+ * @cssprop [--vscada-focus-ring-width=2px] - Keyboard focus ring width (§11).
73
+ * @cssprop [--vscada-focus-ring-offset=2px] - Keyboard focus ring offset (§11).
74
+ *
75
+ * @csspart canvas - The root `<svg>` the whole scene renders into.
76
+ */
77
+ export declare class ScadaView extends LitElement {
78
+ static styles: import("lit").CSSResult;
79
+ private _scene;
80
+ private _lastError;
81
+ private _pendingDevValidation;
82
+ private _sceneGeneration;
83
+ private readonly _renderer;
84
+ private readonly _store;
85
+ private readonly _scheduler;
86
+ private readonly _animations;
87
+ /** Story 4.4 Task 1 — §11 reduced-motion's declared-static-swap registry, sibling to `_animations` but a distinct registration surface (see `StaticRepresentationRegistry`'s own doc). */
88
+ private readonly _staticRepresentations;
89
+ private readonly _reducedMotion;
90
+ /** Story 4.4 Task 3 — §11 ARIA live region; unsubscribed in `disconnectedCallback`. */
91
+ private readonly _liveRegion;
92
+ private _unsubscribeConditionTransition;
93
+ private _builtElements;
94
+ private _builtDefs;
95
+ private _watermark;
96
+ private _licenseVerdict;
97
+ private _needsStructureInsert;
98
+ private _schedulerStarted;
99
+ private _unsubscribeLicense;
100
+ /** Story 4.2 — §3.2 `interactive`: "Whether elements emit click events." A cheap global toggle (AC3) checked at dispatch time, never a rebuild trigger. */
101
+ private _interactive;
102
+ /** Story 4.2 Task 2 — one arbiter per instance, surviving rebuilds, so a drag begun before a mid-gesture rebuild still resolves correctly via the same tracked pointerId. */
103
+ private readonly _gestureArbiter;
104
+ private _hitLayerGroup;
105
+ /** Hit rects built THIS structure build, with enough info to recompute their box in place on a zoom change (Story 4.3 Task 1) — never rebuilt for a zoom-only change, only for a real structural rebuild. */
106
+ private _hitAreaEntries;
107
+ /** Story 4.3 Task 1 — AD-4 view state (zoom/pan), reset on scene reload, NOT scene data. Owns its own tween-drive subscription independent of `_scheduler`'s start/stop lifecycle. */
108
+ private readonly _viewportState;
109
+ private readonly _panZoomGestures;
110
+ /** The one root `<g>` every built element/hit-layer renders inside — translate+scale is the ONLY thing zoom/pan ever touches (AD-2: never re-render on zoom). Rebuilt fresh each structure build, re-stamped with the CURRENT transform immediately (a rebuild mid-gesture must not visually snap to identity). */
111
+ private _viewportGroup;
112
+ /** Story 4.3 Task 2 — previous LOD resolution, fed back into `resolveLodActive` for its hysteresis band. */
113
+ private _lodActive;
114
+ private _listenersAttached;
115
+ /** Story 4.3 Task 3 — off-screen (`IntersectionObserver`) / hidden-tab (`visibilitychange`) pause. Assumed visible until the observer's first callback. */
116
+ private _isIntersecting;
117
+ private _intersectionObserver;
118
+ private _boundVisibilityChange;
119
+ /** Story 4.3 Task 4 — `render-stats` consumer, only subscribed while `debug` is on. */
120
+ private _unsubscribeRenderStats;
121
+ /** Story 2.5 — view state (AD-4: collapse/expand), NOT scene data. Constructed lazily on first scene load, `reset()` on every subsequent one — never on a same-scene rebuild (e.g. a group toggle), which is what lets a toggle survive its own rebuild. */
122
+ private _groupViewState;
123
+ /** Story 2.4 Task 2/3 — rebuilt fresh every structure build (tied to the currently-registered handles' lifecycle, unlike `_groupViewState` above). */
124
+ private _flowInferenceCache;
125
+ private _flowStoppedSourceIds;
126
+ private _flowClosedNodeIds;
127
+ /** Adversarial-review Fix 3 — ids that got a flow-state-tracking Fsm/handle registered this build, INCLUDING hidden children of a collapsed group (never in `_builtElements`, which only holds visually-built elements). Teardown needs this separately so a hidden source's tracking registration doesn't leak across rebuilds. */
128
+ private _flowTrackedElementIds;
129
+ constructor(timeSource?: TimeSource, renderer?: Renderer, matchMedia?: MatchMediaFn | undefined);
130
+ /** §3.2 — configuring the timeout is allowed; disabling the freeze behavior it drives is not (NFR4). */
131
+ get stalenessTimeout(): number;
132
+ set stalenessTimeout(ms: number);
133
+ /** Story 1.3 Task 4 — the tween-vs-snap `|Δ|` cap, as a component-level option (sensible default, see `DEFAULT_SNAP_THRESHOLD`). */
134
+ get snapThreshold(): number;
135
+ set snapThreshold(value: number);
136
+ /** §3.2 — parent-supplied upstream health. `'disconnected'` freezes the entire scene (§4.4) regardless of individual timestamps. */
137
+ get connectionState(): ConnectionState;
138
+ set connectionState(state: ConnectionState);
139
+ /**
140
+ * §3.2 `mode` (Story 4.1, §8.3 "one code path") — delegates entirely to
141
+ * `Scheduler.mode`, which owns the live↔static transition (snap-then-stop
142
+ * / restart). Static mode is what makes `setValues()` below apply a
143
+ * synchronous write pass instead of starting the rAF loop (AC1).
144
+ */
145
+ get mode(): SchedulerMode;
146
+ set mode(value: SchedulerMode);
147
+ /**
148
+ * §3.2 `animate` (Story 4.1 AC1) — master switch for continuous animation,
149
+ * orthogonal to `mode` (§8.1: static mode keeps animations running by
150
+ * default; this is the explicit opt-out for true snapshot capture).
151
+ * Exposed as `animated`, not `animate` — `Element.prototype.animate()`
152
+ * (the native Web Animations API method every `HTMLElement` already has)
153
+ * would otherwise collide with a same-named boolean property, breaking
154
+ * the class's assignability to `Element`/`CustomElementConstructor`.
155
+ */
156
+ get animated(): boolean;
157
+ set animated(value: boolean);
158
+ /** Story 4.4 Task 1 — current `prefers-reduced-motion` state as last observed by the core-owned listener (§11). Read-only: the OS/browser preference, not a settable switch — `animated` remains the one property that toggles continuous motion directly. */
159
+ get reducedMotionActive(): boolean;
160
+ /** AC4 — every in-flight tween and data interpolation completes to its target immediately (Story 4.1's static-mode switch depends on this). Story 4.3 — a mid-flight PROGRAMMATIC zoom tween (gesture-driven zoom is never mid-flight — it's already immediate) settles the same way. */
161
+ snapToTargets(): void;
162
+ /** Story 4.2 AC3 — §3.2 `interactive`. Gates whether a tap/click ever dispatches `element-click` (checked at pointerup time); does not remove or rebuild the hit-area structure itself. */
163
+ get interactive(): boolean;
164
+ set interactive(value: boolean);
165
+ /**
166
+ * Story 4.3 Task 1 — §3.2 `zoom`, two-way. A GESTURE update (pinch/
167
+ * wheel/drag-zoom) writes `_viewportState` directly and this getter
168
+ * reflects it immediately; an external `view.zoom = x` assignment
169
+ * animates via the tween layer instead of jumping (`setZoomAnimated`).
170
+ * Never a structural rebuild (AD-2) — the root viewport `<g>` transform
171
+ * plus an in-place hit-area recompute (`_onViewportFrame`) are the ONLY
172
+ * things a zoom change touches, superseding Story 4.2's rebuild-per-
173
+ * zoom-change behavior.
174
+ */
175
+ get zoom(): number;
176
+ set zoom(value: number);
177
+ /** §3.2 `debug` — gates 1Hz `render-stats` accounting entirely; subscribes/unsubscribes the event-dispatching consumer on toggle. */
178
+ get debug(): boolean;
179
+ set debug(value: boolean);
180
+ /**
181
+ * Story 1.7 — the sanctioned deterministic-frame mechanism for visual
182
+ * regression: seeks every registered WAAPI animation (impeller
183
+ * rotation, flow dashes, lamp blink, …) to an absolute `currentTime`.
184
+ * Dev/test utility — trivially small, never load-bearing for production
185
+ * rendering. If a screenshot still shows motion after this, something
186
+ * bypassed the animation registry (AD-5) and that's a real bug this
187
+ * method exists to catch, not a test to work around.
188
+ */
189
+ seekAll(timeMs: number): void;
190
+ /**
191
+ * §3.3 `exportSVG` (Story 4.1 AC3) — works in ANY mode (live or static):
192
+ * serializes the current rendered `<svg>` to a standalone string. Returns
193
+ * `''` if no scene has been built yet (nothing to export).
194
+ */
195
+ exportSVG(): string;
196
+ /**
197
+ * Story 6.2 Task 2 — plain-HTML fallback for `setLicenseKey()`. `setLicenseKey` is module-level (per-company, not per-view), so any instance observing this attribute is enough to license the whole page.
198
+ * Story 2.6 AC2 — `tag-prefix` mirrors the same plain-HTML-attribute convention for `tagPrefix` below.
199
+ */
200
+ static get observedAttributes(): string[];
201
+ attributeChangedCallback(name: string, old: string | null, value: string | null): void;
202
+ /** Story 2.6 AC2 — every tag lookup is prefixed by this string (`ValueStore.tagPrefix`); changing it at runtime re-resolves and resets interpolation state for affected tags (see `Scheduler`'s own doc on `syncTagPrefixIfChanged`). */
203
+ get tagPrefix(): string;
204
+ set tagPrefix(prefix: string);
205
+ /** §3.2 `scene` — the currently-loaded, validated scene, or `null` if none has been assigned yet or the last assignment failed structural validation (AD-8; see the setter below). */
206
+ get scene(): Scene | null;
207
+ set scene(raw: unknown);
208
+ /** Awaitable in tests; resolves once dev-only Zod diagnostics for the current scene have run. */
209
+ get pendingDevValidation(): Promise<void> | null;
210
+ /** Reconstructed from the store's current buffer — not a cached mirror of the last-pushed array (AD-4: no extra state). */
211
+ get values(): TagValue[];
212
+ set values(values: TagValue[]);
213
+ /**
214
+ * Imperative equivalent of setting `values` (§3.3). Story 4.1 AC1 — in
215
+ * static mode this is the "single synchronous write pass, no rAF" §8.3
216
+ * describes: `Scheduler.snapToTargets()` (already the sanctioned
217
+ * immediate-write path, AC4) writes every registration's current value
218
+ * with zero tween, with no rAF loop ever started. `_viewportState` is
219
+ * deliberately untouched here (unlike the public `snapToTargets()`
220
+ * below) — a value push must not also snap an unrelated in-flight zoom/
221
+ * pan gesture.
222
+ */
223
+ setValues(values: TagValue[]): void;
224
+ /** The only way values are cleared — never an empty `setValues([])` (§3.3, §4.2). */
225
+ clearValues(): void;
226
+ connectedCallback(): void;
227
+ disconnectedCallback(): void;
228
+ /** Story 6.3 — reacts to the module-level license verdict: toggles this instance's watermark and (once, page-wide) logs the trial notice. */
229
+ private _onLicenseVerdict;
230
+ firstUpdated(): void;
231
+ updated(changed: PropertyValues): void;
232
+ render(): import("lit").TemplateResult<1>;
233
+ private _buildElements;
234
+ /**
235
+ * Story 2.4 Task 2/3 — drives `this._flowInferenceCache.update()` off an
236
+ * actual tag-value-driven state transition (never per tick — the cache's
237
+ * own doc requires "on a source/valve FSM state-change event"). The one
238
+ * event-driven mechanism this codebase has for observing a value change
239
+ * IS a scheduler-registered handle's `write()` (exactly how
240
+ * pump-centrifugal drives its own internal FSM); `FlowInferenceCache.update`
241
+ * is itself signature-guarded (a no-op unless the stopped/closed set
242
+ * actually changed), so calling it unconditionally here — rather than
243
+ * gating on `Fsm`'s own `changed` flag, which is `false` on a value's
244
+ * very first resolution — is both safe and correct.
245
+ */
246
+ private _registerFlowStateTracking;
247
+ /** Story 2.5 Task 3 — the `element-click`/`elementType:'group'` + `toggleGroup` wiring `group-view-state.ts` deferred to `<scada-view>`. A collapse-state change is a structure-once (AD-2) event exactly like a scene reload: full teardown + rebuild, just without resetting `_groupViewState` (only a genuinely new `scene` assignment does that). */
248
+ private _toggleGroup;
249
+ /**
250
+ * Story 4.4 Task 3 — resolves elementId -> a `LiveRegionController`
251
+ * announcement. `next` alone can't distinguish "stale because THIS tag
252
+ * timed out" from "stale because the whole scene disconnected" (both
253
+ * collapse into the same `Condition` by the time `Scheduler` reports
254
+ * them, §4.3's `worstOf`) — read `connectionState` at the moment of the
255
+ * transition to disambiguate, exactly as `Scheduler.onConditionTransition`'s
256
+ * own doc says the caller must.
257
+ */
258
+ private _handleConditionTransition;
259
+ /**
260
+ * Story 4.4 Task 3 — wraps every numeric handle whose tag has a declared
261
+ * threshold with a thin band-transition check (`resolveAlarmBand`),
262
+ * announcing only on an actual band CHANGE into a non-normal band (never
263
+ * every write) before delegating to the primitive's own handle. The
264
+ * quantity word in the announcement ("level", "needle", …) is the tag's
265
+ * own binding `type` — the same vocabulary the scene author already
266
+ * chose, never a new naming scheme.
267
+ */
268
+ private _wrapHandlesForLiveRegion;
269
+ private _registerHandles;
270
+ private _teardownBuiltElements;
271
+ private _maybeStartScheduler;
272
+ private _dispatchValueWarning;
273
+ /** Story 4.2 Task 2 — §3.4 `element-click`. */
274
+ private _dispatchElementClick;
275
+ /** Story 4.2 Task 2 — §3.4 `element-hover`; only ever called for a fine (mouse) pointer entering (AC2 — `attachElementInteraction`'s own gate). */
276
+ private _dispatchElementHover;
277
+ /** §3.4 `render-stats` (Story 4.3 Task 4) — only ever called while `debug` is on. */
278
+ private _dispatchRenderStats;
279
+ /**
280
+ * Story 4.3 Task 1 — the ONE per-gesture-frame write path: stamps the
281
+ * viewport `<g>`'s transform, recomputes every hit-area's box in place
282
+ * for the new zoom (no rebuild, AD-2), and re-evaluates the LOD
283
+ * threshold. Called both from a live gesture (immediate) and from the
284
+ * external-set zoom tween's own per-tick callback.
285
+ */
286
+ private _onViewportFrame;
287
+ private _applyViewportTransform;
288
+ /**
289
+ * Story 4.3 Task 1 — converts the SVG's live CSS-to-viewBox scale ratio
290
+ * (assumes uniform `xMidYMid meet` scaling — this component's own
291
+ * `render()` always sets `viewBox="0 0 canvasWidth canvasHeight"` with
292
+ * no `preserveAspectRatio` override) so a gesture's CLIENT-space (CSS
293
+ * px) delta converts to the SAME viewBox-unit space `pan` lives in.
294
+ */
295
+ private _viewBoxScale;
296
+ /** Converts an absolute CLIENT-space point (pinch centroid / wheel cursor) into the viewBox-unit space `zoomAboutPoint`'s anchor expects. */
297
+ private _toCanvasPoint;
298
+ /**
299
+ * Story 4.3 Task 1 — attached ONCE (`firstUpdated`) on the root `<svg>`,
300
+ * not per-element: Pointer Events bubble, so this observes every
301
+ * gesture including ones starting over an element's hit area (this
302
+ * component has no drag-to-reposition affordance — any drag anywhere
303
+ * pans the camera). `touch-action: none` (component styles) stops the
304
+ * browser's own native touch scroll/pinch from fighting this.
305
+ */
306
+ private _attachPanZoomListeners;
307
+ /**
308
+ * Story 4.3 Task 3 — off-screen (`IntersectionObserver`) OR hidden-tab
309
+ * (`document.hidden`) either one pauses; both must clear before
310
+ * resuming. Idempotent via `Scheduler`'s own `pauseForOffscreen`/
311
+ * `resumeFromOffscreen` guards, so calling this on every observer/
312
+ * visibilitychange firing (even a redundant one) is safe.
313
+ */
314
+ private _syncVisibilityPause;
315
+ }
316
+ /**
317
+ * Explicit registration — importing @vscada/core has no side effects
318
+ * (`"sideEffects": false`); consumers opt in, mirroring AD-3's explicit
319
+ * `registerPrimitives(...)` convention.
320
+ */
321
+ export declare function defineScadaView(tagName?: string): void;
322
+ //# sourceMappingURL=scada-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scada-view.d.ts","sourceRoot":"","sources":["../src/scada-view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import type { Connection, Scene } from './scene-schema';
2
+ import type { TopologyGraph } from '../topology/graph';
3
+ export interface Point {
4
+ x: number;
5
+ y: number;
6
+ }
7
+ export interface Segment {
8
+ from: Point;
9
+ to: Point;
10
+ }
11
+ export interface Corner {
12
+ from: Point;
13
+ to: Point;
14
+ radius: number;
15
+ /** SVG arc sweep-flag (0 or 1), derived from the turn direction. */
16
+ sweepFlag: 0 | 1;
17
+ }
18
+ export interface FlowBindingRef {
19
+ tag: string;
20
+ min: number;
21
+ max: number;
22
+ }
23
+ export interface ResolvedRoute {
24
+ /** Straight sub-segments, pre-trimmed around corners. */
25
+ segments: Segment[];
26
+ /** One entry between each pair of adjacent segments. */
27
+ corners: Corner[];
28
+ medium: string | undefined;
29
+ /** From the connection's own `bindings` (Story 1.4 addition to ConnectionSchema) — the pipe renderer's dash-speed source. */
30
+ flowBinding: FlowBindingRef | undefined;
31
+ }
32
+ /**
33
+ * Resolves a connection to an ordered point route. Story 1.4 shipped
34
+ * `direct` and `manual` + corner-rounding; Story 2.1 adds the `orthogonal`
35
+ * elbow generator behind the same `ResolvedRoute` interface — the pipe
36
+ * renderer never sees a routing mode, only resolved geometry.
37
+ *
38
+ * Mode-dispatch precedence (Task 3): `manual` waypoints, OR `orthogonal`
39
+ * with `waypoints` present, always win over the generator — waypoints are
40
+ * the sanctioned manual escape hatch for a route an author dislikes.
41
+ * `orthogonal` with no waypoints calls the elbow generator. `direct` (and
42
+ * `manual`/`orthogonal` with no waypoints supplied) resolve to a single
43
+ * straight segment, unchanged from 1.4.
44
+ *
45
+ * `connection.routing` defaults to `'orthogonal'` at the point of use here
46
+ * (not in the schema/validator): production scenes only go through the
47
+ * always-on structural validator (AD-8), never the dev-only Zod `.parse()`
48
+ * that would apply the schema's declared `.default('orthogonal')` — so an
49
+ * omitted `routing` field must still resolve to orthogonal routing, matching
50
+ * what the schema promises.
51
+ *
52
+ * Story 2.2, Task 1: `connection.laneOffset` displaces the raw centerline
53
+ * polyline perpendicular by `laneOffset * laneWidth` BEFORE corner
54
+ * rounding runs — this is what "corners re-fillet after displacement"
55
+ * means: `finalizeRoute` always rounds the already-displaced points, so
56
+ * the fillet is computed against the new (offset) corner, never the
57
+ * original centerline's. `laneOffset` of `0`/unset is a no-op
58
+ * (`applyLaneOffset` returns the identical points array), so every
59
+ * connection predating this field resolves byte-identical to before.
60
+ *
61
+ * Returns `null` when either endpoint can't be resolved to an element's
62
+ * absolute port position (e.g. it targets a group — group connection
63
+ * endpoints are Story 2.5 territory via `resolveGroupAwareConnectionGeometry`,
64
+ * out of scope here). Story 2.6 AC1: an `off-page` element's declared port
65
+ * DOES resolve here like any other element's — it needs exactly one
66
+ * terminable port so ordinary connections can end on it; only the visual
67
+ * stub and its structural exemption from the primitive-type registry are
68
+ * off-page-specific (see `structural-validator.ts`'s `CORE_NATIVE_TYPES`).
69
+ *
70
+ * `topology` (Story 2.3, Task 3) is an OPTIONAL third argument: when a
71
+ * caller passes the scene's built `TopologyGraph`, the route's `medium`
72
+ * resolves via the effective-medium precedence (`connection.medium ??` its
73
+ * topology edge's medium) instead of the connection's own field verbatim.
74
+ * Omitting it — every existing call site does, unchanged — reproduces
75
+ * exactly the Story 1.4-2.2 behavior byte-for-byte; this is purely which
76
+ * VALUE lands in `ResolvedRoute.medium`, never a change to routing/geometry.
77
+ */
78
+ export declare function resolveConnectionGeometry(connection: Connection, scene: Scene, topology?: TopologyGraph): ResolvedRoute | null;
79
+ export declare function toSegments(points: Point[]): Segment[];
80
+ /**
81
+ * Corner-rounding math, shared verbatim by the manual/direct paths above
82
+ * and by Story 2.1's orthogonal generator (`orthogonal-router.ts`) — the
83
+ * generator only produces a waypoint list; rounding is already generic and
84
+ * stays exactly as 1.4 shipped it (clamped to half the shorter adjacent
85
+ * segment, sweep-flag from the turn's cross-product sign).
86
+ */
87
+ export declare function roundedPolylinePoints(points: Point[], radius: number): {
88
+ segments: Segment[];
89
+ corners: Corner[];
90
+ };
91
+ /** SVG path `d` string for a resolved route — one `M`, then `L`/`A` pairs. */
92
+ export declare function routeToPathData(route: ResolvedRoute): string;
93
+ /** Angle (radians) of a segment's run direction — used to keep the cross-section gradient perpendicular (§7.1). */
94
+ export declare function segmentAngle(segment: Segment): number;
95
+ //# sourceMappingURL=connection-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-geometry.d.ts","sourceRoot":"","sources":["../../src/scene/connection-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAQ,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAI9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,KAAK,CAAC;IACZ,EAAE,EAAE,KAAK,CAAC;CACX;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,KAAK,CAAC;IACZ,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,6HAA6H;IAC7H,WAAW,EAAE,cAAc,GAAG,SAAS,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,aAAa,GAAG,IAAI,CAsC9H;AA8CD,wBAAgB,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,CAMrD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CA8BjH;AAyBD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAa5D;AAED,mHAAmH;AACnH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAErD"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Zero-dependency constants shared by the always-on structural validator
3
+ * and the Zod schema. Kept in their own zod-free module so the public
4
+ * entry (`index.ts`) can re-export `SUPPORTED_SCENE_VERSIONS` as a runtime
5
+ * value WITHOUT creating a static import edge into `scene-schema.ts` — that
6
+ * edge would defeat production Zod-stripping (AC3) by pulling the whole
7
+ * schema module into the main bundle graph.
8
+ */
9
+ export declare const SUPPORTED_SCENE_VERSIONS: readonly ["1.0"];
10
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/scene/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,kBAAmB,CAAC"}
@@ -0,0 +1,85 @@
1
+ import type { Point, ResolvedRoute } from './connection-geometry';
2
+ import type { Connection, Scene } from './scene-schema';
3
+ /**
4
+ * Story 2.2, Tasks 2 & 3: crossing detection + jump-over splicing. Runs
5
+ * ONLY at scene-build time (AD-2) — `resolveSceneRoutes` is the intended
6
+ * single entry point; callers must invoke it once per scene load/change,
7
+ * never inside the animation/render loop. Pure functions throughout: no
8
+ * store, no clock, no `Math.random`, no object-iteration-order
9
+ * dependence — same scene in, same geometry out, always.
10
+ */
11
+ /**
12
+ * Default jump-over arc radius: ~0.8x the reference pipe width — big
13
+ * enough to clearly read as a "hop" over the crossed pipe at reference
14
+ * scale, small enough not to visually dominate the route. Named
15
+ * constant per Story 2.1's precedent (no theme token exists for this;
16
+ * core has no theme access per AD-10).
17
+ */
18
+ export declare const JUMP_ARC_RADIUS: number;
19
+ /** A detected crossing, located on the route that will receive the jump
20
+ * (the LATER connection, by scene declaration order — see
21
+ * `detectCrossings`). */
22
+ export interface Crossing {
23
+ point: Point;
24
+ /** Index into that route's `segments` array (pre-splice) where the crossing occurs. */
25
+ segmentIndex: number;
26
+ /** Parametric position (0..1) along that segment — orders multiple crossings on one segment before splicing. */
27
+ t: number;
28
+ }
29
+ export interface RoutedConnection {
30
+ connection: Connection;
31
+ route: ResolvedRoute | null;
32
+ }
33
+ /**
34
+ * Segment-intersection pass over every pair of resolved routes — O(n^2)
35
+ * segment pairs, acceptable at scene-build time per the story (a
36
+ * sweep-line upgrade is explicitly deferred until a real scene's
37
+ * connection count proves it necessary, same "optimize only if proven
38
+ * needed" discipline as 2.1's router).
39
+ *
40
+ * A crossing is only counted where the intersection point is STRICTLY
41
+ * interior to both segments (parametric position in the open interval
42
+ * `(epsilon, 1-epsilon)` on both). Two pipes that join at a shared
43
+ * port/junction always meet exactly AT one of their segment endpoints,
44
+ * so this rule excludes junctions for free — no separate "is this a
45
+ * junction" check is needed.
46
+ *
47
+ * Deterministic winner (Task 3's design decision, binding): every
48
+ * crossing is attributed to the connection at the LATER index in
49
+ * `routes` — i.e. later in the scene's declared `connections` array.
50
+ * That connection's route is the one meant to receive the jump-over
51
+ * arc; the earlier one stays a plain centerline. This makes the winner
52
+ * a pure function of declaration order alone, so the same scene always
53
+ * produces the same jump placement.
54
+ */
55
+ export declare function detectCrossings(routes: ReadonlyArray<ResolvedRoute | null>): Map<number, Crossing[]>;
56
+ /**
57
+ * Splices a small semicircular "jump-over" arc into `route` at each of
58
+ * `crossings` — automatic and unconfigurable per connection (§5.3: no
59
+ * opt-out in v1, don't add one). Multiple crossings on the same route
60
+ * are applied highest-segment-index (and, within a segment,
61
+ * highest-parametric-position) first, so each splice's index shift
62
+ * never invalidates a not-yet-applied crossing earlier in the list.
63
+ *
64
+ * Reuses the exact `Corner` shape corner-rounding already produces
65
+ * (`{from, to, radius, sweepFlag}`) — the pipe renderer and
66
+ * `routeToPathData` need no changes at all: an `A rx ry 0 0 sweep x y`
67
+ * arc is already what they draw between two segments, and for an exact
68
+ * semicircle (chord length == diameter, guaranteed here since `before`
69
+ * and `after` are each `radius` away from the crossing point along the
70
+ * same line) the large-arc-flag is immaterial — only `sweepFlag`
71
+ * chooses which of the two mirror semicircles is drawn, fixed here for
72
+ * determinism.
73
+ */
74
+ export declare function spliceJumpOvers(route: ResolvedRoute, crossings: readonly Crossing[], radius?: number): ResolvedRoute;
75
+ /**
76
+ * Scene-build-time-only orchestration (AD-2): resolves every
77
+ * connection's geometry (Story 2.2's lane-offset displacement is
78
+ * already applied inside `resolveConnectionGeometry`), detects every
79
+ * crossing between DIFFERENT connections' routes ONCE over the whole
80
+ * set, and splices jump-over arcs into each crossing's later-declared
81
+ * connection. Callers must invoke this exactly once per scene
82
+ * load/change — never inside the animation loop.
83
+ */
84
+ export declare function resolveSceneRoutes(scene: Scene): RoutedConnection[];
85
+ //# sourceMappingURL=crossing-jumps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crossing-jumps.d.ts","sourceRoot":"","sources":["../../src/scene/crossing-jumps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,KAAK,EAAE,aAAa,EAAW,MAAM,uBAAuB,CAAC;AAGnF,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,QAA6B,CAAC;AAE1D;;yBAEyB;AACzB,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,uFAAuF;IACvF,YAAY,EAAE,MAAM,CAAC;IACrB,gHAAgH;IAChH,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;CAC7B;AAiBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAoBpG;AA0BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,QAAQ,EAAE,EAAE,MAAM,GAAE,MAAwB,GAAG,aAAa,CAmCrI;AA6FD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,gBAAgB,EAAE,CAenE"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Dev-only Zod diagnostics layer (AC3). Runs AFTER the structural gate has
3
+ * already passed — this never gates rendering, it only surfaces richer
4
+ * validation issues Zod catches that the lightweight structural validator
5
+ * does not (e.g. wrong enum value, negative canvas dimensions).
6
+ *
7
+ * The `import.meta.env.DEV` guard is a Vite build-time constant: `vite
8
+ * build` (production mode) statically replaces it with `false`, after
9
+ * which esbuild's minifier eliminates this function's body as unreachable
10
+ * — including the dynamic `import('./scene-schema')` — so the Zod runtime
11
+ * never ships in the production bundle. Verified empirically by
12
+ * `test/bundle.prod.test.ts`, not just asserted here.
13
+ */
14
+ export interface ZodDiagnostic {
15
+ path: string;
16
+ message: string;
17
+ }
18
+ /**
19
+ * Returns `null` when diagnostics are skipped (not a dev build). Returns an
20
+ * array (possibly empty) when running in dev: empty means Zod found no
21
+ * additional issues beyond the structural gate.
22
+ */
23
+ export declare function validateSceneWithZod(raw: unknown): Promise<ZodDiagnostic[] | null>;
24
+ //# sourceMappingURL=dev-validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-validate.d.ts","sourceRoot":"","sources":["../../src/scene/dev-validate.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAexF"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Structural validation error codes (AD-8). Hand-rolled union, not derived
3
+ * from Zod — this file has zero Zod dependency so it survives production
4
+ * bundling unconditionally, same as the validator that uses it.
5
+ */
6
+ export declare const SCENE_ERROR_CODES: readonly ["MISSING_VERSION", "UNSUPPORTED_VERSION", "BAD_SHAPE", "DUPLICATE_ID", "UNKNOWN_TYPE", "UNRESOLVED_PORT", "UNRESOLVED_TOPOLOGY_REF", "AMBIGUOUS_GROUP_PORT_MAP", "UNRESOLVED_GROUP_PORT_MAP", "AMBIGUOUS_GROUP_CHILD"];
7
+ export type SceneErrorCode = (typeof SCENE_ERROR_CODES)[number];
8
+ /** Error envelope per spine conventions: `{ code, message, path? }`. */
9
+ export interface SceneErrorDetail {
10
+ code: SceneErrorCode;
11
+ message: string;
12
+ path: string;
13
+ }
14
+ export declare function sceneError(code: SceneErrorCode, message: string, path: string): SceneErrorDetail;
15
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/scene/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,kOAWpB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAEhG"}