@pygmalionjs/pygmalion 0.5.14 → 0.5.15

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 (108) hide show
  1. package/dist-lib/types/App.d.ts +5 -0
  2. package/dist-lib/types/canvas/CameraLayer.d.ts +9 -0
  3. package/dist-lib/types/canvas/Canvas.d.ts +19 -0
  4. package/dist-lib/types/canvas/FrameLabelBanner.d.ts +7 -0
  5. package/dist-lib/types/canvas/FrameView.d.ts +9 -0
  6. package/dist-lib/types/canvas/FrozenRoutePreview.d.ts +12 -0
  7. package/dist-lib/types/canvas/InspectOverlay.d.ts +10 -0
  8. package/dist-lib/types/canvas/LightweightCanvas.d.ts +10 -0
  9. package/dist-lib/types/canvas/ObjectControls.d.ts +22 -0
  10. package/dist-lib/types/canvas/Preview.d.ts +3 -0
  11. package/dist-lib/types/canvas/SectionBoxes.d.ts +24 -0
  12. package/dist-lib/types/canvas/ShadowRoutePreview.d.ts +14 -0
  13. package/dist-lib/types/canvas/StoryboardConnections.d.ts +31 -0
  14. package/dist-lib/types/canvas/cameraPlacement.d.ts +45 -0
  15. package/dist-lib/types/canvas/domTags.d.ts +10 -0
  16. package/dist-lib/types/canvas/layoutContext.d.ts +9 -0
  17. package/dist-lib/types/canvas/useFlowSession.d.ts +36 -0
  18. package/dist-lib/types/canvas/useFrameLod.d.ts +35 -0
  19. package/dist-lib/types/editor/adaptiveFrameLayout.d.ts +67 -0
  20. package/dist-lib/types/editor/assetEditing.d.ts +10 -0
  21. package/dist-lib/types/editor/bannerStyle.d.ts +18 -0
  22. package/dist-lib/types/editor/catalog.d.ts +101 -0
  23. package/dist-lib/types/editor/codegen.d.ts +11 -0
  24. package/dist-lib/types/editor/componentConnections.d.ts +63 -0
  25. package/dist-lib/types/editor/componentInstances.d.ts +27 -0
  26. package/dist-lib/types/editor/contentBounds.d.ts +34 -0
  27. package/dist-lib/types/editor/designCompiler.d.ts +100 -0
  28. package/dist-lib/types/editor/designImport.d.ts +448 -0
  29. package/dist-lib/types/editor/documentSync.d.ts +28 -0
  30. package/dist-lib/types/editor/domImport.d.ts +58 -0
  31. package/dist-lib/types/editor/editModePolicy.d.ts +17 -0
  32. package/dist-lib/types/editor/fiberMap.d.ts +16 -0
  33. package/dist-lib/types/editor/flowSessionScheduler.d.ts +97 -0
  34. package/dist-lib/types/editor/flowSessions.d.ts +137 -0
  35. package/dist-lib/types/editor/frameHeight.d.ts +14 -0
  36. package/dist-lib/types/editor/frameIdentity.d.ts +9 -0
  37. package/dist-lib/types/editor/frameLabels.d.ts +124 -0
  38. package/dist-lib/types/editor/frameLanes.d.ts +62 -0
  39. package/dist-lib/types/editor/frameLod.d.ts +123 -0
  40. package/dist-lib/types/editor/frameLodRuntime.d.ts +64 -0
  41. package/dist-lib/types/editor/framePointerHit.d.ts +67 -0
  42. package/dist-lib/types/editor/framePointerIntent.d.ts +53 -0
  43. package/dist-lib/types/editor/framePreviewChannels.d.ts +26 -0
  44. package/dist-lib/types/editor/framePreviewKeys.d.ts +21 -0
  45. package/dist-lib/types/editor/frameWheelRouting.d.ts +16 -0
  46. package/dist-lib/types/editor/frozenImport.d.ts +70 -0
  47. package/dist-lib/types/editor/host.d.ts +114 -0
  48. package/dist-lib/types/editor/inspect.d.ts +225 -0
  49. package/dist-lib/types/editor/interactiveStates.d.ts +103 -0
  50. package/dist-lib/types/editor/livePreviewInstances.d.ts +93 -0
  51. package/dist-lib/types/editor/liveScreens.d.ts +20 -0
  52. package/dist-lib/types/editor/nodeSelector.d.ts +20 -0
  53. package/dist-lib/types/editor/previewBootstrap.d.ts +189 -0
  54. package/dist-lib/types/editor/previewEnvironmentControls.d.ts +33 -0
  55. package/dist-lib/types/editor/previewHydration.d.ts +5 -0
  56. package/dist-lib/types/editor/previewIntent.d.ts +17 -0
  57. package/dist-lib/types/editor/previewSweep.d.ts +129 -0
  58. package/dist-lib/types/editor/previewWarmup.d.ts +77 -0
  59. package/dist-lib/types/editor/projectBootGate.d.ts +45 -0
  60. package/dist-lib/types/editor/projectRuntime.d.ts +138 -0
  61. package/dist-lib/types/editor/registry.d.ts +38 -0
  62. package/dist-lib/types/editor/routePreview.d.ts +285 -0
  63. package/dist-lib/types/editor/routePreviewArtifactV2.d.ts +34 -0
  64. package/dist-lib/types/editor/routePreviewArtifactV3.d.ts +64 -0
  65. package/dist-lib/types/editor/routePreviewPlacement.d.ts +9 -0
  66. package/dist-lib/types/editor/routePreviewStatus.d.ts +48 -0
  67. package/dist-lib/types/editor/scenarioCoverage.d.ts +167 -0
  68. package/dist-lib/types/editor/screenCards.d.ts +101 -0
  69. package/dist-lib/types/editor/screenDimensions.d.ts +63 -0
  70. package/dist-lib/types/editor/screenFlows.d.ts +47 -0
  71. package/dist-lib/types/editor/screenInteractions.d.ts +4 -0
  72. package/dist-lib/types/editor/screenLists.d.ts +40 -0
  73. package/dist-lib/types/editor/screenStateGroups.d.ts +36 -0
  74. package/dist-lib/types/editor/screenshotBitmaps.d.ts +20 -0
  75. package/dist-lib/types/editor/sectionHeaders.d.ts +117 -0
  76. package/dist-lib/types/editor/shadowPreview.d.ts +103 -0
  77. package/dist-lib/types/editor/sharedSource.d.ts +40 -0
  78. package/dist-lib/types/editor/sourceJournal.d.ts +27 -0
  79. package/dist-lib/types/editor/store.d.ts +838 -0
  80. package/dist-lib/types/editor/storyboardComposition.d.ts +116 -0
  81. package/dist-lib/types/editor/storyboardDiscovery.d.ts +105 -0
  82. package/dist-lib/types/editor/storyboardEnvironment.d.ts +22 -0
  83. package/dist-lib/types/editor/storyboardGraph.d.ts +120 -0
  84. package/dist-lib/types/editor/storyboardGraphRuntime.d.ts +12 -0
  85. package/dist-lib/types/editor/storyboardGraphView.d.ts +104 -0
  86. package/dist-lib/types/editor/surfaceDemands.d.ts +138 -0
  87. package/dist-lib/types/editor/tokens.d.ts +26 -0
  88. package/dist-lib/types/editor/useObserved.d.ts +1 -0
  89. package/dist-lib/types/editor/viewportPresets.d.ts +21 -0
  90. package/dist-lib/types/editor/visualQa.d.ts +50 -0
  91. package/dist-lib/types/lib.d.ts +345 -0
  92. package/dist-lib/types/shell/ApplyPanel.d.ts +1 -0
  93. package/dist-lib/types/shell/AssetsPanel.d.ts +3 -0
  94. package/dist-lib/types/shell/CanvasStatusProbe.d.ts +5 -0
  95. package/dist-lib/types/shell/CodePanel.d.ts +1 -0
  96. package/dist-lib/types/shell/ComponentStateControls.d.ts +108 -0
  97. package/dist-lib/types/shell/ContextMenu.d.ts +1 -0
  98. package/dist-lib/types/shell/LayerTree.d.ts +7 -0
  99. package/dist-lib/types/shell/PropsPanel.d.ts +1 -0
  100. package/dist-lib/types/shell/StoryboardGraphPanel.d.ts +23 -0
  101. package/dist-lib/types/shell/ZoomIndicator.d.ts +4 -0
  102. package/dist-lib/types/shell/qaPresentation.d.ts +9 -0
  103. package/dist-lib/types/testing.d.ts +8 -0
  104. package/dist-lib/types/ui/SourceRefControl.d.ts +38 -0
  105. package/dist-lib/types/ui/icons.d.ts +30 -0
  106. package/package.json +7 -8
  107. package/testing.d.ts +0 -26
  108. package/types.d.ts +0 -2675
@@ -0,0 +1,17 @@
1
+ /** Explains a control that is inert because the editor is in view-only. */
2
+ export declare const VIEW_ONLY_REASON = "View only \u2014 switch to Editing to change this.";
3
+ interface ModeKeyEvent {
4
+ key: string;
5
+ code?: string;
6
+ metaKey?: boolean;
7
+ ctrlKey?: boolean;
8
+ shiftKey?: boolean;
9
+ altKey?: boolean;
10
+ }
11
+ /**
12
+ * True when this keystroke would change the design and the editor is not in
13
+ * edit mode. Selection, zoom, panning, tool switching and copy are absent
14
+ * from the lists above by design — reading a canvas needs all of them.
15
+ */
16
+ export declare function viewOnlyBlocksKey(editMode: boolean, event: ModeKeyEvent): boolean;
17
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { ComponentRegistry, RegistryPropValue } from './registry';
2
+ export interface InstanceHit {
3
+ /** Registry key. */
4
+ name: string;
5
+ /** Registry importPath. If not present, name — Identifies the same implementation source across multiple screens. */
6
+ sourceId: string;
7
+ /** Only safe literal props are retained (functions, objects, and ReactElement are discarded). */
8
+ props: Record<string, RegistryPropValue>;
9
+ /** It is used by the source editor to safely create AST operations by preserving the original literal type. */
10
+ primitiveProps: Record<string, string | number | boolean>;
11
+ /** only if memoizedProps.children is string. */
12
+ childrenText: string;
13
+ }
14
+ export type InstanceResolver = (el: Element, exclude?: ReadonlySet<string>) => InstanceHit | null;
15
+ /** Create a resolver that creates a registry reverse map (component → name) once and closes it — does not rebuild it on each call. */
16
+ export declare function createInstanceResolver(registry: ComponentRegistry): InstanceResolver;
@@ -0,0 +1,97 @@
1
+ import { type PageModel } from './store';
2
+ /** Diagnostic counters for the headless debug surface. */
3
+ export declare const __flowSchedulerDebug: {
4
+ calls: number;
5
+ lastCanvas: string;
6
+ lastFlows: number;
7
+ lastCandidates: number;
8
+ lastQueued: number;
9
+ };
10
+ /**
11
+ * Materializes the flow-declared screens of one canvas that still lack a
12
+ * frozen snapshot. Paths delivering the active frame's screen run first.
13
+ * Returns the number of paths queued.
14
+ */
15
+ export declare function materializeCanvasFlows(input: {
16
+ canvas: string;
17
+ previewRevision: string;
18
+ }): number;
19
+ /** Session delivery state for one page, keyed by its catalog screen id. */
20
+ export declare function flowSessionWillDeliverPage(page: {
21
+ importPageId?: string;
22
+ id: string;
23
+ }): boolean;
24
+ /**
25
+ * Walks an instance to the active frame's screen in the background and parks
26
+ * it, unless a parked instance already serves that path. Returns true when a
27
+ * warming walk was queued.
28
+ */
29
+ export declare function warmActiveFrameInstance(page: PageModel, previewRevision: string): boolean;
30
+ /** Diagnostic counters for activation warming. */
31
+ export declare const __warmingDebug: {
32
+ requested: number;
33
+ noPath: number;
34
+ resolvedNull: number;
35
+ alreadyWarm: number;
36
+ queued: number;
37
+ };
38
+ /**
39
+ * Materializes one screen at an explicit viewport through its flow path.
40
+ * Prefix waypoints walk as pass-through (steps only); the target publishes
41
+ * under the page's recipe key at that viewport — the key its frame reads
42
+ * after the size change commits. Returns false when no flow claims the
43
+ * screen (the live re-import fallback stays for those).
44
+ */
45
+ export declare function materializePageViewport(page: PageModel, viewport: {
46
+ width: number;
47
+ height: number;
48
+ }, previewRevision: string): boolean;
49
+ /** True while a viewport-variant session still owes this page's snapshot. */
50
+ export declare function viewportSessionWillDeliver(page: {
51
+ importPageId?: string;
52
+ id: string;
53
+ }, viewport: {
54
+ width: number;
55
+ height: number;
56
+ }): boolean;
57
+ /** Subscribe to viewport-variant delivery changes. */
58
+ export declare function subscribeViewportSessions(listener: () => void): () => void;
59
+ /**
60
+ * Materializes one screen in its declared interactive state through the
61
+ * screen's flow path. The prefix walks as pass-through; the target publishes
62
+ * under the page's own recipe key, which already includes the option's steps
63
+ * (the store appends them to the recipe, and resolvePath replays them).
64
+ * Returns false when no flow claims the screen — those frames keep the live
65
+ * boot fallback.
66
+ */
67
+ export declare function materializePageInteractiveState(page: PageModel, previewRevision: string): boolean;
68
+ /** True while an interactive-state session still owes this page its snapshot. */
69
+ export declare function interactiveSessionWillDeliver(page: {
70
+ importPageId?: string;
71
+ id: string;
72
+ interactiveStateId?: string;
73
+ interactiveOptionId?: string;
74
+ }): boolean;
75
+ /** Subscribe to interactive-state delivery changes. */
76
+ export declare function subscribeInteractiveSessions(listener: () => void): () => void;
77
+ /** Diagnostic counters for the interactive-state path. */
78
+ export declare const __interactiveSessionDebug: {
79
+ requested: number;
80
+ noPath: number;
81
+ resolvedNull: number;
82
+ queued: number;
83
+ };
84
+ /** Interactive-runner delivery states for the headless debug surface. */
85
+ export declare function __debugInteractiveSessionStates(): Record<string, unknown>;
86
+ /** Diagnostic counters for the viewport-commit path. */
87
+ export declare const __viewportCommitDebug: {
88
+ requested: number;
89
+ resolvedNull: number;
90
+ controllerMissing: number;
91
+ markerGone: number;
92
+ editsWon: number;
93
+ captureNull: number;
94
+ committed: number;
95
+ };
96
+ /** Viewport-runner delivery states for the headless debug surface. */
97
+ export declare function __debugViewportSessionStates(): Record<string, unknown>;
@@ -0,0 +1,137 @@
1
+ import type { DesignScreenAssertion, DesignScreenCaptureReport, DesignScreenInteraction, DesignScreenPreset } from './designImport';
2
+ export interface ResolvedFlowWaypoint {
3
+ screenId: string;
4
+ /**
5
+ * Route-preview store key the snapshot publishes under. An empty key marks
6
+ * a pass-through waypoint: its steps advance the instance so LATER
7
+ * waypoints stay reachable, but nothing publishes and no delivery status
8
+ * is tracked (viewport-variant paths walk their prefix this way).
9
+ */
10
+ cacheKey: string;
11
+ /** Viewport of this waypoint's frame; the instance resizes when it differs. */
12
+ width: number;
13
+ height: number;
14
+ steps: readonly DesignScreenInteraction[];
15
+ /** The waypoint's own capture assertions, checked after its steps settle. */
16
+ assertions?: readonly DesignScreenAssertion[];
17
+ /**
18
+ * Runs against the settled live instance after the snapshot publishes,
19
+ * while the iframe is still mounted. Viewport-variant deliveries commit
20
+ * their layer import here: the walk iframe is a TRUE viewport, so width
21
+ * media queries hold — unlike canvas shadow mounts, which evaluate them
22
+ * against the editor window.
23
+ */
24
+ afterSerialize?: (iframe: HTMLIFrameElement) => Promise<void>;
25
+ }
26
+ export interface ResolvedFlowPath {
27
+ id: string;
28
+ /** Boot URL with route and declarative environment already encoded. */
29
+ url: string;
30
+ /** Authored route, forwarded to the capture-preparation spec. */
31
+ route: string;
32
+ /**
33
+ * Shared screen preset of every waypoint on this path (mock APIs, identity,
34
+ * timers). Applied through the host executor with the FIRST waypoint's
35
+ * preparation; the instance keeps it for the rest of the walk.
36
+ */
37
+ preset?: DesignScreenPreset;
38
+ waypoints: readonly ResolvedFlowWaypoint[];
39
+ }
40
+ export type FlowScreenStatus = 'pending' | 'running' | 'delivered' | 'failed';
41
+ export interface FlowScreenState {
42
+ status: FlowScreenStatus;
43
+ pathId: string;
44
+ /** Failure reason, present only for failed screens. */
45
+ reason?: string;
46
+ }
47
+ export interface FlowSessionRunnerOptions {
48
+ /**
49
+ * Concurrent live instances. The default is 1: mocked app backends
50
+ * (STT sockets, summary generators) are commonly single-session, and two
51
+ * concurrent walks contending for them time out deterministically. Raise
52
+ * it only for apps whose fixtures are proven concurrency-safe.
53
+ */
54
+ concurrency?: number;
55
+ /** Names this supply in the boot counters, so a stray boot is attributable. */
56
+ label?: string;
57
+ createIframe?: () => HTMLIFrameElement;
58
+ resolveContainer?: () => (Node & {
59
+ appendChild(node: Node): unknown;
60
+ }) | null;
61
+ /** Navigates the instance and resolves when the document loaded. */
62
+ boot?: (iframe: HTMLIFrameElement, url: string) => Promise<void>;
63
+ /**
64
+ * Prepares one waypoint on the instance: preset (host executor) ->
65
+ * interactions -> assertions, exactly the capture pipeline's contract.
66
+ * Defaults to the design-import controller's prepareScreenCapture.
67
+ */
68
+ prepare?: (iframe: HTMLIFrameElement, spec: {
69
+ pageId: string;
70
+ route?: string;
71
+ preset?: DesignScreenPreset;
72
+ interactions?: readonly DesignScreenInteraction[];
73
+ assertions?: readonly DesignScreenAssertion[];
74
+ }) => Promise<DesignScreenCaptureReport>;
75
+ /** Extra settle before serializing a waypoint (fonts, trailing paints). */
76
+ settle?: (iframe: HTMLIFrameElement, ms: number) => Promise<void>;
77
+ /** Layout-stability wait before serializing. Defaults to waitForGeometryStability. */
78
+ waitForStability?: (iframe: HTMLIFrameElement) => Promise<void>;
79
+ serialize?: (iframe: HTMLIFrameElement, fallbackUrl: string) => string | null;
80
+ /** Writes one waypoint snapshot into the route preview store. */
81
+ publish?: (cacheKey: string, snapshot: string) => boolean;
82
+ onError?: (pathId: string, error: unknown) => void;
83
+ }
84
+ /**
85
+ * Resolves when the document's layout stops moving: two consecutive
86
+ * animation frames with an identical element-geometry hash. JS-driven
87
+ * entrance animations (rAF springs writing inline transforms) are invisible
88
+ * to the frozen stylesheet's animation:none — serializing mid-flight pins
89
+ * intermediate rects as overlapping boxes, so the walk waits them out.
90
+ * Perpetual animations hit the timeout and serialize best-effort.
91
+ */
92
+ export declare function waitForGeometryStability(iframe: HTMLIFrameElement, timeoutMs?: number): Promise<void>;
93
+ export declare function createFlowSessionIframe(): HTMLIFrameElement;
94
+ /** Test/tuning hook for how long a parked instance stays claimable. */
95
+ export declare function setFlowSessionWarmTtl(ms: number): void;
96
+ /** Warm-pool counters for the headless debug surface. */
97
+ export declare const __flowSessionWarmDebug: {
98
+ boots: number;
99
+ reuses: number;
100
+ parks: number;
101
+ evictions: number;
102
+ /** Which supply booted, so a stray second boot is attributable. */
103
+ bootsByRunner: Record<string, number>;
104
+ };
105
+ /** Drops every parked instance — identity change, canvas change, teardown. */
106
+ export declare function evictFlowSessionWarmInstances(): void;
107
+ /**
108
+ * True when a walk of this path would resume on a parked instance. Activation
109
+ * warming reads it to decide whether the frame already has a resumable
110
+ * instance or one has to be walked in the background.
111
+ */
112
+ export declare function warmInstanceServesPath(path: ResolvedFlowPath): boolean;
113
+ export declare function createFlowSessionRunner(options?: FlowSessionRunnerOptions): {
114
+ /**
115
+ * Queues paths for materialization. Screens already delivered, failed, or
116
+ * claimed by a queued path are skipped — callers re-request freely.
117
+ */
118
+ materialize(paths: readonly ResolvedFlowPath[]): number;
119
+ /** Session state of one screen, or null when no session claims it. */
120
+ screenState(screenId: string): FlowScreenState | null;
121
+ /** True while the session still owes this screen its snapshot. */
122
+ willDeliver(screenId: string): boolean;
123
+ subscribe(listener: () => void): () => void;
124
+ /**
125
+ * Drops all session state. Running paths notice the round change at their
126
+ * next waypoint boundary and stop; their remaining screens re-queue on
127
+ * the next materialize call.
128
+ */
129
+ reset(): void;
130
+ /** Test/diagnostic snapshot of every tracked screen. */
131
+ debugScreenStates(): Record<string, FlowScreenState>;
132
+ /** How many finished walks currently have an instance parked for reuse. */
133
+ debugWarmInstancesParked(): number;
134
+ };
135
+ export type FlowSessionRunner = ReturnType<typeof createFlowSessionRunner>;
136
+ export declare function getFlowSessionRunner(): FlowSessionRunner;
137
+ export declare function resetFlowSessionRunner(): void;
@@ -0,0 +1,14 @@
1
+ export type DesignFrameHeightMode = 'fixed' | 'document';
2
+ export declare const DEFAULT_DOCUMENT_FRAME_MAX_HEIGHT = 12000;
3
+ export declare const ABSOLUTE_DOCUMENT_FRAME_MAX_HEIGHT = 32000;
4
+ interface FrameHeightInput {
5
+ height?: number;
6
+ heightMode?: DesignFrameHeightMode;
7
+ maxHeight?: number;
8
+ resolvedDocumentHeight?: number;
9
+ }
10
+ export declare function documentFrameHeightLimit(viewportHeight: number, maxHeight?: number): number;
11
+ export declare function resolveFrameHeight(page: FrameHeightInput): number;
12
+ export declare function measurePreviewDocumentHeight(root: Document | ShadowRoot): number;
13
+ export declare function observePreviewDocumentHeight(root: Document | ShadowRoot, onHeightChange: (height: number) => void): () => void;
14
+ export {};
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Source inventory and QA use the stable host-owned screen id, while the editor
3
+ * keeps its own unique page id for selection, layout, and navigation.
4
+ */
5
+ export interface FrameIdentitySource {
6
+ id: string;
7
+ importPageId?: string;
8
+ }
9
+ export declare function canonicalFrameId(page: FrameIdentitySource): string;
@@ -0,0 +1,124 @@
1
+ import type { PageModel } from './store';
2
+ /**
3
+ * Host-declared presentation of one branch kind.
4
+ *
5
+ * `kind` matches either a `stateKind` a case declares, or one of the two kinds
6
+ * the core derives on its own: `step` for a plain screen and `variant` for a
7
+ * numbered branch that declares no state kind.
8
+ */
9
+ export interface FrameBranchKindDef {
10
+ kind: string;
11
+ /** Word shown in the pill. */
12
+ label: string;
13
+ /** Accent colour for the rule and the pill text. */
14
+ accent: string;
15
+ }
16
+ /**
17
+ * Words for the facts the core counts. Defaults are English; a host renders
18
+ * its own language by declaring them, so the core carries no product copy.
19
+ */
20
+ export interface FrameLabelLabels {
21
+ /** Unit for the layer count. Default "layers". */
22
+ layers?: string;
23
+ /** Shown when a screen frame claims no scenario at all. Default "no scenario". */
24
+ noScenario?: string;
25
+ /** Shown when the import dropped nodes. Default "some omissions". */
26
+ omissions?: string;
27
+ /** Shown when the import failed. Default "check flow". */
28
+ checkFlow?: string;
29
+ }
30
+ export declare function resolveFrameLabelLabels(labels: FrameLabelLabels | undefined): Required<FrameLabelLabels>;
31
+ /** Branch kinds the core derives when a frame declares no state kind. */
32
+ export declare const FRAME_BRANCH_STEP = "step";
33
+ export declare const FRAME_BRANCH_VARIANT = "variant";
34
+ /** Neutral accent for a kind the host has not described. */
35
+ export declare const FRAME_BRANCH_FALLBACK_ACCENT = "#8b8b9e";
36
+ export interface FrameBranchKindDiagnostic {
37
+ severity: 'error' | 'warning';
38
+ kind: string;
39
+ message: string;
40
+ }
41
+ export declare function validateFrameBranchKinds(defs: readonly FrameBranchKindDef[], context?: {
42
+ stateKinds?: readonly string[];
43
+ }): FrameBranchKindDiagnostic[];
44
+ /** Every scenario a page claims: the whole declared set, or its canonical id. */
45
+ export declare function pageScenarioIds(page: PageModel): readonly string[];
46
+ /**
47
+ * A screen frame with nothing to say about coverage. Catalog sheets are not
48
+ * screens and are not expected to claim scenarios, so only routed frames
49
+ * count as a hole.
50
+ */
51
+ export declare function pageMissesScenario(page: PageModel): boolean;
52
+ export declare function framesMissingScenario(pages: readonly PageModel[]): readonly PageModel[];
53
+ /**
54
+ * Branch kind of a frame.
55
+ *
56
+ * A declared state kind wins, because the host said what the branch is. Absent
57
+ * one, a case number with a third segment (`02.02.2` beside `02.02`) is the
58
+ * catalog's own way of saying "branch of the screen before it" — the same
59
+ * convention the fold groups read.
60
+ */
61
+ export declare function frameBranchKind(page: PageModel): string;
62
+ /** Leading case number of a frame name, or null when it has none. */
63
+ export declare function frameLabelCode(page: PageModel): string | null;
64
+ export interface FrameLabelParts {
65
+ /** Case number, or null for a frame that is not numbered. */
66
+ code: string | null;
67
+ /** Title after the flow prefix, e.g. "recording error". */
68
+ title: string;
69
+ /** Secondary clause: the state this branch is in. */
70
+ state?: string;
71
+ }
72
+ /**
73
+ * Splits a frame name into the banner's slots.
74
+ *
75
+ * Catalog names carry `<code> <flow> / <title>`; the flow is already the
76
+ * section, so repeating it in the title would spend the widest slot on the
77
+ * thing the section band above it already says.
78
+ */
79
+ export declare function frameLabelParts(page: PageModel): FrameLabelParts;
80
+ /**
81
+ * The counted line, in the order a reviewer scans it. An import that failed or
82
+ * dropped nodes says so first — it changes whether the frame can be trusted at
83
+ * all — and a screen claiming no scenario says that rather than staying quiet,
84
+ * which is how fourteen uncovered screens went unnoticed.
85
+ */
86
+ export declare function frameLabelFacts(page: PageModel, labels: Required<FrameLabelLabels>): string;
87
+ export declare const FRAME_LABEL_STYLE: {
88
+ readonly radius: 10;
89
+ readonly pillRadius: 999;
90
+ readonly ruleWidth: 6;
91
+ readonly gap: 14;
92
+ readonly paddingY: 10;
93
+ readonly paddingRight: 16;
94
+ readonly codeSize: 32;
95
+ readonly titleSize: 20;
96
+ readonly metaSize: 14;
97
+ readonly pillSize: 12;
98
+ readonly pillPaddingY: 4;
99
+ readonly pillPaddingX: 10;
100
+ /** Bottom margin between the label and its frame. */
101
+ readonly marginBottom: 8;
102
+ readonly surface: "#343441";
103
+ readonly pillSurface: "#2e2c3a";
104
+ readonly caption: "#a1a1b3";
105
+ readonly code: "#ffffff";
106
+ readonly title: "#e7e7f0";
107
+ readonly titleMuted: "#a1a1b3";
108
+ readonly meta: "#bebecb";
109
+ readonly purpose: "#c4ccd8";
110
+ };
111
+ /**
112
+ * Below this zoom the label keeps only its rule and code.
113
+ *
114
+ * At overview zoom the label is a few pixels tall: a 20px title renders at 5px
115
+ * and is noise, while a 32px code renders at 8px and still parses, and colour
116
+ * survives any scale at all. So the overview tier spends everything on the two
117
+ * signals that keep working — which branch kind, which number — and a canvas
118
+ * of sixty frames reads as a coloured structure instead of grey mush.
119
+ */
120
+ export declare const FRAME_LABEL_COMPACT_ZOOM = 0.35;
121
+ export declare function setFrameBranchKinds(defs: readonly FrameBranchKindDef[], labels?: FrameLabelLabels): void;
122
+ export declare function getFrameBranchKinds(): readonly FrameBranchKindDef[];
123
+ export declare function getFrameLabelLabels(): FrameLabelLabels | undefined;
124
+ export declare function frameBranchKindFor(kind: string): FrameBranchKindDef;
@@ -0,0 +1,62 @@
1
+ /** A situation group within one section. Declaration order is lane order. */
2
+ export interface ScreenLaneDef {
3
+ /** Unique within its section. */
4
+ id: string;
5
+ /** Human-readable, in the host's language — drawn as the lane caption. */
6
+ label: string;
7
+ /** The section this lane belongs to, matched against `page.section`. */
8
+ section: string;
9
+ /** Caption rule colour. Defaults to the neutral caption colour. */
10
+ accent?: string;
11
+ }
12
+ export interface ScreenLaneDiagnostic {
13
+ severity: 'error' | 'warning';
14
+ laneId: string;
15
+ message: string;
16
+ }
17
+ export declare const LANE_CAPTION_STYLE: {
18
+ /** Rule width and the gap between rule and text. */
19
+ readonly ruleWidth: 4;
20
+ readonly gap: 10;
21
+ /** Caption band height, and the space between caption and the first label. */
22
+ readonly height: 26;
23
+ readonly marginBottom: 14;
24
+ readonly fontSize: 17;
25
+ readonly fontWeight: 700;
26
+ readonly color: "#6b6b76";
27
+ readonly accent: "#b8b8c2";
28
+ readonly countColor: "#a1a1b3";
29
+ readonly countSize: 14;
30
+ };
31
+ /**
32
+ * Lane layout constants. `maxFramesPerRow` is what a designer can take in
33
+ * without panning at overview zoom — six 1280px screens is about one viewport
34
+ * — so a longer lane wraps into continuation rows rather than running off.
35
+ */
36
+ export declare const LANE_LAYOUT: {
37
+ readonly gap: 80;
38
+ readonly laneGap: 210;
39
+ readonly maxFramesPerRow: 6;
40
+ };
41
+ /** The implicit lane that collects frames no declaration placed. */
42
+ export declare const UNDECLARED_LANE_ID = "";
43
+ export declare function validateScreenLanes(lanes: readonly ScreenLaneDef[], context?: {
44
+ sections?: readonly string[];
45
+ }): ScreenLaneDiagnostic[];
46
+ export declare function setScreenLanes(lanes: readonly ScreenLaneDef[] | undefined): void;
47
+ export declare function getScreenLanes(): readonly ScreenLaneDef[];
48
+ /** Declared lanes of one section, in declaration order. */
49
+ export declare function lanesForSection(section: string): ScreenLaneDef[];
50
+ export declare function laneCaptionFor(section: string, laneId: string): ScreenLaneDef | null;
51
+ /**
52
+ * Groups frames into lanes in declaration order, appending the implicit lane
53
+ * last. A frame tagged with a lane the section did not declare counts as
54
+ * undeclared rather than creating a lane of its own, so a typo shows up as a
55
+ * frame that fell out of its situation instead of as a phantom row.
56
+ */
57
+ export declare function groupByLane<T extends {
58
+ lane?: string;
59
+ }>(section: string, frames: readonly T[]): {
60
+ laneId: string;
61
+ frames: T[];
62
+ }[];
@@ -0,0 +1,123 @@
1
+ export type FrameLifecycleTier = 'full' | 'contained' | 'detached';
2
+ export interface FrameLodRect {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ }
8
+ export interface FrameLodCamera {
9
+ panX: number;
10
+ panY: number;
11
+ zoom: number;
12
+ }
13
+ export interface FrameLodViewport {
14
+ width: number;
15
+ height: number;
16
+ }
17
+ export interface FrameLodConfig {
18
+ /** Distance below which a contained or detached frame promotes to full. */
19
+ fullEnter: number;
20
+ /** Distance above which a full frame demotes to contained. */
21
+ fullExit: number;
22
+ /** Distance beyond which a contained frame may detach after the dwell. */
23
+ detachEnter: number;
24
+ /** Distance below which a detached frame reattaches as contained. */
25
+ detachExit: number;
26
+ /**
27
+ * How long a frame must have held its contained tier before it may detach.
28
+ * Counted from the tier-entry timestamp, so a pan that sweeps a frame out
29
+ * and back within the dwell never pays a remount.
30
+ */
31
+ dwellMs: number;
32
+ /** Slack factor when testing whether the frame union fits the viewport. */
33
+ overviewFitSlack: number;
34
+ /** Frames intersecting the viewport at once that force overview mode. */
35
+ overviewVisibleCount: number;
36
+ }
37
+ export declare const DEFAULT_FRAME_LOD_CONFIG: FrameLodConfig;
38
+ export interface FrameLodFrame {
39
+ id: string;
40
+ rect: FrameLodRect;
41
+ /** Pinned frames (active, selected, preview-intended, live) stay full. */
42
+ pinned: boolean;
43
+ /** Retained snapshot weight proxy: serialized snapshot length times two. */
44
+ weightBytes: number;
45
+ /**
46
+ * Screenshot bitmap pixels stored per frame CSS pixel; null or absent when
47
+ * the frame has no captured screenshot. Input to the magnification signal.
48
+ */
49
+ screenshotDensity?: number | null;
50
+ }
51
+ export interface FrameLodTierState {
52
+ tier: FrameLifecycleTier;
53
+ /** Timestamp at which the frame entered its current tier. */
54
+ since: number;
55
+ }
56
+ /**
57
+ * Screen-space gap between a frame and the viewport, normalized by the
58
+ * viewport diagonal. A frame intersecting the viewport is at distance zero;
59
+ * one whole viewport diagonal away is at distance one.
60
+ */
61
+ export declare function frameViewportDistance(frameRect: FrameLodRect, camera: FrameLodCamera, viewport: FrameLodViewport): number;
62
+ /**
63
+ * An overview camera sees the storyboard as a whole: either the union of all
64
+ * frames roughly fits the viewport, or many frames intersect it at once. In
65
+ * overview every frame legitimately needs pixels, so tier demotion is off and
66
+ * the imperative camera writer alone pays for the pan.
67
+ */
68
+ export declare function isOverviewCamera(frames: readonly FrameLodRect[], camera: FrameLodCamera, viewport: FrameLodViewport, config?: FrameLodConfig): boolean;
69
+ /**
70
+ * True when the camera draws a frame above its screenshot's pixel density —
71
+ * the bitmap would visibly blur, so the frame should trade its screenshot for
72
+ * the frozen DOM surface. Gated on the `full` tier: at magnifying zoom levels
73
+ * only a handful of frames are near the viewport, which keeps simultaneous
74
+ * DOM reconstruction bounded.
75
+ *
76
+ * An overview camera never magnifies. Overview marks every frame `full`
77
+ * because they all need pixels at once — and a low-density bitmap (a legacy
78
+ * 1x capture on a 2x display) can sit "past its density" at overview zoom,
79
+ * which would reconstruct the whole storyboard's frozen DOM in one pass.
80
+ */
81
+ export declare function frameMagnifiedPastBitmap(tier: FrameLifecycleTier, displayDensity: number, screenshotDensity: number | null | undefined, overview: boolean): boolean;
82
+ /**
83
+ * Whether frame screenshots should display at their native (2x) resolution.
84
+ * Below one device pixel per CSS pixel a half-scale bitmap is
85
+ * indistinguishable, and an overview showing every frame at native capture
86
+ * resolution keeps gigabytes of decoded bitmap resident — the canvas pans
87
+ * like it is buffering. The display density is camera-global, so this is one
88
+ * signal, not a per-frame one; the ±5% band keeps a zoom hovering at the
89
+ * boundary from flapping between decodes.
90
+ */
91
+ export declare function resolveBitmapFullSignal(previous: boolean, displayDensity: number): boolean;
92
+ export declare const FRAME_LOD_BUDGET_BYTES_PER_GB: number;
93
+ export declare const FRAME_LOD_BUDGET_MIN_BYTES: number;
94
+ export declare const FRAME_LOD_BUDGET_MAX_BYTES: number;
95
+ export declare const FRAME_LOD_BUDGET_MIN_BYTES_PER_FRAME: number;
96
+ /**
97
+ * Total attached-preview weight allowed before the governor demotes the
98
+ * farthest unpinned frames. Scales with device memory, clamped, and never
99
+ * drops below a small per-frame allowance so a large storyboard is not forced
100
+ * into a wall of placeholders on a small device.
101
+ */
102
+ export declare function resolveFrameLodBudget({ deviceMemoryGb, frameCount, }: {
103
+ deviceMemoryGb?: number;
104
+ frameCount: number;
105
+ }): number;
106
+ /**
107
+ * Resolves the lifecycle tier for every frame. Rules, in order: an overview
108
+ * camera keeps everything full; pinned frames are always full; otherwise the
109
+ * hysteresis step above applies; finally the memory governor demotes the
110
+ * farthest unpinned attached frames (skipping weightless ones — demoting them
111
+ * frees nothing) until the attached weight fits the budget. Governor
112
+ * demotion is allowed to bypass the dwell: it exists to cap memory, not to
113
+ * smooth pans.
114
+ */
115
+ export declare function resolveFrameLodTiers({ frames, camera, viewport, previous, now, config, budget, }: {
116
+ frames: readonly FrameLodFrame[];
117
+ camera: FrameLodCamera;
118
+ viewport: FrameLodViewport;
119
+ previous: ReadonlyMap<string, FrameLodTierState>;
120
+ now: number;
121
+ config?: FrameLodConfig;
122
+ budget: number;
123
+ }): Map<string, FrameLifecycleTier>;
@@ -0,0 +1,64 @@
1
+ import { type FrameLifecycleTier, type FrameLodCamera, type FrameLodConfig, type FrameLodFrame, type FrameLodViewport } from './frameLod';
2
+ /** Frames the controller has not classified render at full detail. */
3
+ export declare const DEFAULT_FRAME_LOD_TIER: FrameLifecycleTier;
4
+ export declare function getFrameTier(frameId: string): FrameLifecycleTier;
5
+ /**
6
+ * True when the camera currently draws this frame beyond its screenshot's
7
+ * pixel density. Published from the same recompute as the tiers, over the
8
+ * same per-frame channels, so only frames whose flag flips re-render.
9
+ */
10
+ export declare function getFrameMagnification(frameId: string): boolean;
11
+ /**
12
+ * Whether screenshots should display at native capture resolution right now.
13
+ * Camera-global: below one device pixel per CSS pixel every frame's
14
+ * half-scale bitmap is indistinguishable and far cheaper to keep decoded.
15
+ */
16
+ export declare function getFrameBitmapFull(): boolean;
17
+ export declare function subscribeFrameBitmapScale(listener: () => void): () => void;
18
+ /** Diagnostic view of the published LOD state, for headless debugging. */
19
+ export declare function __debugFrameLodState(): {
20
+ tiers: [string, FrameLifecycleTier][];
21
+ magnified: [string, boolean][];
22
+ lastRecompute: {
23
+ displayDensity?: number;
24
+ overview?: boolean;
25
+ frames?: {
26
+ id: string;
27
+ screenshotDensity: number | null | undefined;
28
+ tier: string;
29
+ }[];
30
+ };
31
+ };
32
+ export declare function subscribeFrameLod(frameId: string, listener: () => void): () => void;
33
+ /**
34
+ * Total live tier listeners across all frames. A diagnostic seam for leak
35
+ * tests: after any number of mount/unmount cycles the count must return to
36
+ * what it was before them, because every subscribeFrameLod cleanup removes
37
+ * its listener and drops the frame's empty set.
38
+ */
39
+ export declare function countFrameLodListeners(): number;
40
+ export interface FrameLodCameraSample extends FrameLodCamera {
41
+ /** Tracked so a canvas switch retriggers the reaction; unused by the math. */
42
+ canvas?: string;
43
+ }
44
+ export interface FrameLodControllerOptions {
45
+ /** Read inside the MobX reaction — its observable reads drive recomputes. */
46
+ readCamera(): FrameLodCameraSample;
47
+ /** Read untracked at compute time. */
48
+ readFrames(): readonly FrameLodFrame[];
49
+ readViewport(): FrameLodViewport;
50
+ /** Throttle for camera-driven recomputes. Defaults to requestAnimationFrame. */
51
+ schedule?(recompute: () => void): () => void;
52
+ now?(): number;
53
+ config?: FrameLodConfig;
54
+ resolveBudget?(frames: readonly FrameLodFrame[]): number;
55
+ /** Screen device pixels per CSS pixel. Defaults to window.devicePixelRatio. */
56
+ readDevicePixelRatio?(): number;
57
+ }
58
+ export interface FrameLodController {
59
+ start(): void;
60
+ stop(): void;
61
+ /** Runs the tier computation immediately (initial mount and tests). */
62
+ recompute(): void;
63
+ }
64
+ export declare function createFrameLodController(options: FrameLodControllerOptions): FrameLodController;