supervision 0.1.7 → 0.2.0-next.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 (182) hide show
  1. package/dist/constants/media-renderer.d.ts +3 -0
  2. package/dist/constants/media-renderer.d.ts.map +1 -1
  3. package/dist/detections/chunked-detection-frame-source.d.ts.map +1 -1
  4. package/dist/index.d.ts +8 -4
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +9281 -5038
  7. package/dist/index.js.map +1 -1
  8. package/dist/mask-preparation.worker.js +409 -185
  9. package/dist/mask-preparation.worker.js.map +1 -1
  10. package/dist/media/display-pixel-ratio.d.ts +15 -0
  11. package/dist/media/display-pixel-ratio.d.ts.map +1 -0
  12. package/dist/media/engine-import-failure.d.ts +16 -0
  13. package/dist/media/engine-import-failure.d.ts.map +1 -0
  14. package/dist/media/media-errors.d.ts +6 -0
  15. package/dist/media/media-errors.d.ts.map +1 -1
  16. package/dist/media/media-normalization.d.ts.map +1 -1
  17. package/dist/media/media-probe.d.ts.map +1 -1
  18. package/dist/media/media-source-state.d.ts.map +1 -1
  19. package/dist/media/media-source.d.ts +17 -0
  20. package/dist/media/media-source.d.ts.map +1 -1
  21. package/dist/media/mediabunny-media-source.d.ts.map +1 -1
  22. package/dist/media/video-engine-media-source.d.ts +54 -0
  23. package/dist/media/video-engine-media-source.d.ts.map +1 -0
  24. package/dist/media/video-engine-media-source.js +3 -0
  25. package/dist/media/video-engine-media-source.js.map +1 -0
  26. package/dist/playback/media-playback-controller.d.ts +7 -1
  27. package/dist/playback/media-playback-controller.d.ts.map +1 -1
  28. package/dist/render-preparation/mask-frame-artifact.d.ts +48 -12
  29. package/dist/render-preparation/mask-frame-artifact.d.ts.map +1 -1
  30. package/dist/render-preparation/mask-frame-compositor.d.ts +12 -5
  31. package/dist/render-preparation/mask-frame-compositor.d.ts.map +1 -1
  32. package/dist/render-preparation/mask-frame-preparer.d.ts.map +1 -1
  33. package/dist/render-preparation/mask-preparation-worker-count.d.ts +4 -4
  34. package/dist/render-preparation/mask-preparation-worker-protocol.d.ts +13 -3
  35. package/dist/render-preparation/mask-preparation-worker-protocol.d.ts.map +1 -1
  36. package/dist/render-preparation/prepared-render-window.d.ts +44 -2
  37. package/dist/render-preparation/prepared-render-window.d.ts.map +1 -1
  38. package/dist/render-preparation/prepared-window-timeline.d.ts +2 -6
  39. package/dist/render-preparation/prepared-window-timeline.d.ts.map +1 -1
  40. package/dist/renderers/injected-pixi.d.ts +38 -0
  41. package/dist/renderers/injected-pixi.d.ts.map +1 -0
  42. package/dist/renderers/mask-palette.d.ts +14 -0
  43. package/dist/renderers/mask-palette.d.ts.map +1 -0
  44. package/dist/renderers/mask-vertex.d.ts +14 -0
  45. package/dist/renderers/mask-vertex.d.ts.map +1 -0
  46. package/dist/renderers/media-renderer-core.d.ts +9 -0
  47. package/dist/renderers/media-renderer-core.d.ts.map +1 -1
  48. package/dist/renderers/media-renderer-scene.d.ts +50 -2
  49. package/dist/renderers/media-renderer-scene.d.ts.map +1 -1
  50. package/dist/renderers/media-renderer-state.d.ts +20 -1
  51. package/dist/renderers/media-renderer-state.d.ts.map +1 -1
  52. package/dist/renderers/media-renderer-transport.d.ts +72 -0
  53. package/dist/renderers/media-renderer-transport.d.ts.map +1 -0
  54. package/dist/renderers/pixi-box-layer.d.ts +5 -0
  55. package/dist/renderers/pixi-box-layer.d.ts.map +1 -1
  56. package/dist/renderers/pixi-focus-layer.d.ts +19 -2
  57. package/dist/renderers/pixi-focus-layer.d.ts.map +1 -1
  58. package/dist/renderers/pixi-frame-present.d.ts +77 -0
  59. package/dist/renderers/pixi-frame-present.d.ts.map +1 -0
  60. package/dist/renderers/pixi-id-mask-shader.d.ts +6 -25
  61. package/dist/renderers/pixi-id-mask-shader.d.ts.map +1 -1
  62. package/dist/renderers/pixi-interaction-layer.d.ts.map +1 -1
  63. package/dist/renderers/pixi-interaction-presentation-layer.d.ts +12 -2
  64. package/dist/renderers/pixi-interaction-presentation-layer.d.ts.map +1 -1
  65. package/dist/renderers/pixi-mask-halo.d.ts +18 -23
  66. package/dist/renderers/pixi-mask-halo.d.ts.map +1 -1
  67. package/dist/renderers/pixi-mask-layer.d.ts +94 -32
  68. package/dist/renderers/pixi-mask-layer.d.ts.map +1 -1
  69. package/dist/renderers/pixi-media-scene.d.ts +67 -0
  70. package/dist/renderers/pixi-media-scene.d.ts.map +1 -1
  71. package/dist/renderers/pixi-polygon-layer.d.ts +9 -2
  72. package/dist/renderers/pixi-polygon-layer.d.ts.map +1 -1
  73. package/dist/renderers/pixi-region-coverage-mask.d.ts +62 -0
  74. package/dist/renderers/pixi-region-coverage-mask.d.ts.map +1 -0
  75. package/dist/renderers/pixi-region-effect.d.ts +42 -0
  76. package/dist/renderers/pixi-region-effect.d.ts.map +1 -0
  77. package/dist/renderers/pixi-region-layer.d.ts +43 -2
  78. package/dist/renderers/pixi-region-layer.d.ts.map +1 -1
  79. package/dist/renderers/pixi-shader-lifecycle.d.ts +14 -0
  80. package/dist/renderers/pixi-shader-lifecycle.d.ts.map +1 -0
  81. package/dist/renderers/pixi-vector-layer.d.ts.map +1 -1
  82. package/dist/renderers/prepared-annotation-window.d.ts +47 -0
  83. package/dist/renderers/prepared-annotation-window.d.ts.map +1 -0
  84. package/dist/renderers/presented-frame-channel.d.ts +138 -0
  85. package/dist/renderers/presented-frame-channel.d.ts.map +1 -0
  86. package/dist/renderers/scene-render-scheduler.d.ts +20 -0
  87. package/dist/renderers/scene-render-scheduler.d.ts.map +1 -0
  88. package/dist/sessions/media-session-defaults.d.ts +10 -6
  89. package/dist/sessions/media-session-defaults.d.ts.map +1 -1
  90. package/dist/sessions/media-session-media.d.ts.map +1 -1
  91. package/dist/sessions/media-session-state.d.ts.map +1 -1
  92. package/dist/sessions/media-session.d.ts.map +1 -1
  93. package/dist/tracking.worker.js +73 -4
  94. package/dist/tracking.worker.js.map +1 -1
  95. package/dist/types/media-normalization.d.ts +34 -0
  96. package/dist/types/media-normalization.d.ts.map +1 -1
  97. package/dist/types/media-renderer.d.ts +31 -1
  98. package/dist/types/media-renderer.d.ts.map +1 -1
  99. package/dist/types/media-session.d.ts +89 -15
  100. package/dist/types/media-session.d.ts.map +1 -1
  101. package/dist/types/render-preparation.d.ts +149 -5
  102. package/dist/types/render-preparation.d.ts.map +1 -1
  103. package/dist/video-engine-media-source-CUXnOJOV.js +450 -0
  104. package/dist/video-engine-media-source-CUXnOJOV.js.map +1 -0
  105. package/dist/web-video-engine/analysis-session.d.ts +75 -0
  106. package/dist/web-video-engine/analysis.d.ts +6 -0
  107. package/dist/web-video-engine/analysis.js +1850 -0
  108. package/dist/web-video-engine/cache-budget.d.ts +18 -0
  109. package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts +89 -0
  110. package/dist/web-video-engine/clock.d.ts +82 -0
  111. package/dist/web-video-engine/constants.d.ts +261 -0
  112. package/dist/web-video-engine/create-scrub-cursor.d.ts +65 -0
  113. package/dist/web-video-engine/decode-resolution.d.ts +114 -0
  114. package/dist/web-video-engine/decode-scheduler.d.ts +371 -0
  115. package/dist/web-video-engine/decode-session.d.ts +283 -0
  116. package/dist/web-video-engine/decode-source.d.ts +258 -0
  117. package/dist/web-video-engine/diagnostics-store.d.ts +17 -0
  118. package/dist/web-video-engine/diagnostics.d.ts +316 -0
  119. package/dist/web-video-engine/embedded-engine-worker.d.ts +1 -0
  120. package/dist/web-video-engine/engine-core.d.ts +269 -0
  121. package/dist/web-video-engine/engine.d.ts +25 -0
  122. package/dist/web-video-engine/engine.js +912 -0
  123. package/dist/web-video-engine/engine.worker.d.ts +1 -0
  124. package/dist/web-video-engine/engine.worker.js +33624 -0
  125. package/dist/web-video-engine/frame-cache.d.ts +236 -0
  126. package/dist/web-video-engine/frame-extractor.d.ts +27 -0
  127. package/dist/web-video-engine/frame-timeline-DreEwsRY.js +616 -0
  128. package/dist/web-video-engine/frame-timeline.d.ts +80 -0
  129. package/dist/web-video-engine/frame-walker.d.ts +73 -0
  130. package/dist/web-video-engine/index.d.ts +13 -0
  131. package/dist/web-video-engine/index.d.ts.map +1 -0
  132. package/dist/web-video-engine/index.js +3 -0
  133. package/dist/web-video-engine/index.js.map +1 -0
  134. package/dist/web-video-engine/key-packet.d.ts +64 -0
  135. package/dist/web-video-engine/keyframe-index.d.ts +90 -0
  136. package/dist/web-video-engine/mirror-store.d.ts +55 -0
  137. package/dist/web-video-engine/renderer.d.ts +93 -0
  138. package/dist/web-video-engine/rotation.d.ts +34 -0
  139. package/dist/web-video-engine/scrub-controller.d.ts +375 -0
  140. package/dist/web-video-engine/scrub-cursor.d.ts +347 -0
  141. package/dist/web-video-engine/scrub-trajectory.d.ts +29 -0
  142. package/dist/web-video-engine/source-residency.d.ts +91 -0
  143. package/dist/web-video-engine/trace-recorder.d.ts +163 -0
  144. package/dist/web-video-engine/types.d.ts +200 -0
  145. package/dist/web-video-engine/video-engine.d.ts +437 -0
  146. package/dist/web-video-engine/webgpu-renderer.d.ts +61 -0
  147. package/dist/web-video-engine/worker-bridge.d.ts +11 -0
  148. package/dist/web-video-engine/worker-dispatch.d.ts +16 -0
  149. package/dist/web-video-engine/worker-protocol.d.ts +282 -0
  150. package/node_modules/supervision-js-core/dist/detections/buffered-detection-timeline.d.ts.map +1 -1
  151. package/node_modules/supervision-js-core/dist/detections/composite-detection-frame-source.d.ts.map +1 -1
  152. package/node_modules/supervision-js-core/dist/index.d.ts +5 -4
  153. package/node_modules/supervision-js-core/dist/index.d.ts.map +1 -1
  154. package/node_modules/supervision-js-core/dist/index.js +1167 -280
  155. package/node_modules/supervision-js-core/dist/index.js.map +1 -1
  156. package/node_modules/supervision-js-core/dist/styles/default-annotation-presentation.d.ts.map +1 -1
  157. package/node_modules/supervision-js-core/dist/styles/interaction-style.d.ts +4 -36
  158. package/node_modules/supervision-js-core/dist/styles/interaction-style.d.ts.map +1 -1
  159. package/node_modules/supervision-js-core/dist/styles/polyline-style.d.ts +5 -0
  160. package/node_modules/supervision-js-core/dist/styles/polyline-style.d.ts.map +1 -1
  161. package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts +92 -7
  162. package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts.map +1 -1
  163. package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts +191 -17
  164. package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts.map +1 -1
  165. package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts +83 -5
  166. package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts.map +1 -1
  167. package/node_modules/supervision-js-core/dist/types/polyline-style.d.ts +2 -0
  168. package/node_modules/supervision-js-core/dist/types/polyline-style.d.ts.map +1 -1
  169. package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts +32 -0
  170. package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts.map +1 -1
  171. package/node_modules/supervision-js-core/dist/utils/detection-conversions.d.ts.map +1 -1
  172. package/node_modules/supervision-js-core/dist/utils/detection-frames.d.ts +5 -0
  173. package/node_modules/supervision-js-core/dist/utils/detection-frames.d.ts.map +1 -1
  174. package/node_modules/supervision-js-core/dist/utils/detection-masks.d.ts +9 -0
  175. package/node_modules/supervision-js-core/dist/utils/detection-masks.d.ts.map +1 -1
  176. package/node_modules/supervision-js-core/dist/utils/detection-ranges.d.ts +18 -0
  177. package/node_modules/supervision-js-core/dist/utils/detection-ranges.d.ts.map +1 -0
  178. package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts +34 -2
  179. package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts.map +1 -1
  180. package/node_modules/supervision-js-core/dist/utils/wait-bound.d.ts +7 -0
  181. package/node_modules/supervision-js-core/dist/utils/wait-bound.d.ts.map +1 -0
  182. package/package.json +24 -3
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Two-tier frame cache.
3
+ *
4
+ * The preview tier holds many downscaled frames: a long, coarse history that
5
+ * answers a scrub instantly while the crisp frame decodes. The exact tier holds
6
+ * a few full-resolution frames, bounded by a RAM budget rather than a fixed
7
+ * count so the slot count tracks frame size.
8
+ *
9
+ * A lookup prefers exact, then preview, tagging the hit with the tier that
10
+ * served it. Only an exact hit is full-resolution; a preview hit still owes the
11
+ * caller a crisp decode.
12
+ *
13
+ * The exact tier is keyed by the timeline's identity for the frame, so two
14
+ * source frames can never share a slot at any frame rate. The preview tier is
15
+ * keyed by rounded millisecond, which merges frames spaced under a millisecond;
16
+ * it is the tier whose answer is already declared approximate, and it never
17
+ * claims to be the frame at the target.
18
+ *
19
+ * Both tiers store OffscreenCanvas blits, never VideoFrames: a raw-frame cache
20
+ * pins decoder output, stalling the decoder and growing VRAM without bound. A
21
+ * frame fed as a live VideoSample is drawn into the blit and never retained, so
22
+ * the no-retention rule holds on the zero-copy path too.
23
+ */
24
+ import type { FrameId } from "./frame-timeline";
25
+ import type { VideoSampleLike } from "./scrub-cursor";
26
+ /**
27
+ * What the cache can blit into a tier: an already-decoded canvas/image, or a
28
+ * live VideoSample it draws once and never retains. The sample's draw scales to
29
+ * the tier size just like drawImage does, so the stored blit is identical either
30
+ * way.
31
+ */
32
+ export type CacheBlitSource = CanvasImageSource | VideoSampleLike;
33
+ export declare enum FrameTier {
34
+ Exact = "exact",
35
+ Preview = "preview"
36
+ }
37
+ export interface CachedFrame {
38
+ readonly canvas: OffscreenCanvas;
39
+ readonly timestampMs: number;
40
+ readonly tier: FrameTier;
41
+ }
42
+ export interface FrameCacheStats {
43
+ readonly exactHits: number;
44
+ readonly previewHits: number;
45
+ readonly misses: number;
46
+ readonly exactSize: number;
47
+ readonly previewSize: number;
48
+ readonly exactCapacity: number;
49
+ readonly previewCapacity: number;
50
+ /** True timestamps (ms) currently resident in each tier, for the diagnostics
51
+ * timeline. Bounded by capacity, so a small array per poll. */
52
+ readonly exactTimestampsMs: number[];
53
+ readonly previewTimestampsMs: number[];
54
+ /** Configured source frame interval: the visual width of each cached mark on
55
+ * the timeline. Nothing is keyed by it, so this is a display width and not
56
+ * the grid entries land on. */
57
+ readonly bucketMs: number;
58
+ /** Frames dropped to LRU pressure per tier, and puts that overwrote a live
59
+ * key: a frame decoded again on the exact tier, and on the preview tier
60
+ * either that or two frames sharing one rounded millisecond. */
61
+ readonly exactEvictions: number;
62
+ readonly previewEvictions: number;
63
+ readonly bucketCollapses: number;
64
+ /** Per-tier frame dimensions and the crisp tier's RAM ceiling, so a consumer
65
+ * can derive resident bytes (size x w x h x 4) and the budget fill. */
66
+ readonly exactFrameWidth: number;
67
+ readonly exactFrameHeight: number;
68
+ readonly previewFrameWidth: number;
69
+ readonly previewFrameHeight: number;
70
+ readonly exactBudgetBytes: number;
71
+ }
72
+ export interface FrameCacheOptions {
73
+ /** Crisp-tier frame size, the cursor's decode resolution. */
74
+ readonly exactWidth: number;
75
+ readonly exactHeight: number;
76
+ /** Coarse-tier width; height derives from the exact aspect ratio. */
77
+ readonly previewWidth: number;
78
+ /** Crisp scrub-tier RAM ceiling in bytes; slot count derives from frame size. */
79
+ readonly exactBudgetBytes: number;
80
+ /** Coarse-tier slot count. */
81
+ readonly previewCapacity: number;
82
+ /** Source frame interval in ms, reported to diagnostics as the timeline mark
83
+ * width. It keys nothing. */
84
+ readonly bucketMs: number;
85
+ /** Floor on exact-tier slots, applied even when the byte budget would yield
86
+ * fewer. Lets a caller that owns the prefetch-window width guarantee a full
87
+ * window fits regardless of frame size. The cache stays ignorant of the
88
+ * window; it only honors the number it is handed. */
89
+ readonly minExactSlots?: number;
90
+ }
91
+ export declare class FrameCache {
92
+ private readonly exact;
93
+ private readonly preview;
94
+ private exactHits;
95
+ private previewHits;
96
+ private misses;
97
+ private readonly bucketMs;
98
+ private readonly exactBudgetBytes;
99
+ constructor(options: FrameCacheOptions);
100
+ /**
101
+ * Store a crisp full-resolution frame for the exact (scrub) tier under
102
+ * `frame`, the timeline's name for it. `timestampMs` is the decoded
103
+ * timestamp, which is what lookups match on and what a hit reports back.
104
+ */
105
+ putExact(frame: FrameId, timestampMs: number, src: CacheBlitSource, srcWidth: number, srcHeight: number): void;
106
+ /** Store a downscaled frame for the coarse preview tier. */
107
+ putPreview(timestampMs: number, src: CacheBlitSource, srcWidth: number, srcHeight: number): void;
108
+ /**
109
+ * Best cached answer for a named source frame. The exact tier is looked up
110
+ * only by `frame` identity; time is used solely for the approximate preview
111
+ * fallback. This keeps a long variable-rate frame from borrowing a crisp
112
+ * neighbour merely because both timestamps fit a millisecond tolerance.
113
+ */
114
+ getForFrame(frame: FrameId, timestampMs: number, previewTolMs: number): CachedFrame | null;
115
+ /** Non-accounting form of {@link getForFrame}. */
116
+ peekForFrame(frame: FrameId, timestampMs: number, previewTolMs: number): CachedFrame | null;
117
+ /**
118
+ * Best cached frame for `timestampMs`, consulting the exact tier then the
119
+ * preview tier: a crisp hit within `exactTolMs`, else a coarse hit within
120
+ * `previewTolMs`, else null. The two tolerances differ because the exact tier
121
+ * is keyed per source frame while the preview tier may only hold sparse
122
+ * keyframes.
123
+ *
124
+ * `exactTolMs` is an upper bound, not the reach: a crisp hit is also held to
125
+ * the frame span the exact tier has observed, since a tolerance wider than
126
+ * one frame (50ms is, at every rate from 24 to 60fps) would let a neighbour
127
+ * answer as the exact frame.
128
+ */
129
+ get(timestampMs: number, exactTolMs: number, previewTolMs: number): CachedFrame | null;
130
+ /**
131
+ * Same lookup as get() but without touching the hit/miss accounting. The
132
+ * synchronous render-loop peek and the authoritative seek both hit the cache
133
+ * for one user gesture; counting both double-books every scrub. The peek
134
+ * uses this so only the seek's get() is tallied, keeping the hit-rate a
135
+ * per-lookup rate rather than two-per-gesture.
136
+ */
137
+ peek(timestampMs: number, exactTolMs: number, previewTolMs: number): CachedFrame | null;
138
+ /**
139
+ * Marks the exact entry nearest `timestampMs` as most-recently-used without
140
+ * counting a hit. Lets the scheduler protect the just-shown center frame
141
+ * from being the LRU victim of its own neighbor sweep. No-op on a miss.
142
+ */
143
+ bumpExact(timestampMs: number): void;
144
+ /** Promotes one exact frame by identity. */
145
+ bumpExactFrame(frame: FrameId): void;
146
+ clear(): void;
147
+ get stats(): FrameCacheStats;
148
+ }
149
+ interface TierHit {
150
+ readonly canvas: OffscreenCanvas;
151
+ readonly timestampMs: number;
152
+ }
153
+ /**
154
+ * One cache tier: a fixed-capacity, MRU-ordered set of OffscreenCanvas copies
155
+ * under keys its owner assigns. A put onto a live key overwrites that slot in
156
+ * place, so an owner that lets two frames share a key loses one of them
157
+ * silently; overflow past capacity evicts the least-recently-used entry
158
+ * instead. Lookups match on the stored frame's true timestamp and never on the
159
+ * key, so a cache-served frame carries the same timestamp a fresh decode would.
160
+ */
161
+ export declare class TierStore {
162
+ readonly capacity: number;
163
+ readonly width: number;
164
+ readonly height: number;
165
+ /** Width of the grid the owner's keys round onto, or 0 when a key names a
166
+ * frame outright. Two entries closer together than this are one frame
167
+ * whose two decodes rounded onto either side of a key boundary. */
168
+ private readonly keyGridMs;
169
+ /** MRU-ordered keys. Index 0 is the LRU, the last index is the MRU. */
170
+ private readonly keys;
171
+ private readonly entries;
172
+ /** Canvases released by eviction, held for the next put to fill. */
173
+ private readonly spare;
174
+ private evictionCount;
175
+ private bucketCollapseCount;
176
+ /** Smallest gap between two stored frames, which is the source frame interval
177
+ * once neighbours are resident. Learned from the timestamps the tier is
178
+ * handed, so it is what the source really did rather than a declared rate.
179
+ * Null until two frames have landed. */
180
+ private observedIntervalMs;
181
+ constructor(capacity: number, width: number, height: number,
182
+ /** Width of the grid the owner's keys round onto, or 0 when a key names a
183
+ * frame outright. Two entries closer together than this are one frame
184
+ * whose two decodes rounded onto either side of a key boundary. */
185
+ keyGridMs: number);
186
+ /** Frames dropped to the LRU policy; a cache-pressure signal for diagnostics. */
187
+ get evictions(): number;
188
+ /** Puts that landed on a key already live, collapsing both onto one slot. */
189
+ get bucketCollapses(): number;
190
+ put(key: number, timestampMs: number, src: CacheBlitSource, srcWidth: number, srcHeight: number): void;
191
+ /**
192
+ * Nearest resident frame to `timestampMs` within `tolMs`, or null.
193
+ *
194
+ * `atOrBefore` restricts it to frames at or before the target, which is the
195
+ * contract a decode answers a seek with. Without it the tier can answer with
196
+ * the frame AFTER the target, one no decode would ever return, so the same
197
+ * pointer position paints a different frame depending on whether the cache or
198
+ * the decoder served it, and the picture steps forward and back as the two
199
+ * alternate.
200
+ */
201
+ get(timestampMs: number, tolMs: number, atOrBefore?: boolean): TierHit | null;
202
+ /** Retrieves exactly one owner-assigned key and promotes it to MRU. */
203
+ getByKey(key: number): TierHit | null;
204
+ /** Promotes the entry nearest `timestampMs` to most-recently-used. Scans
205
+ * rather than keys off the timestamp: callers pass a gesture position, which
206
+ * is not a frame timestamp, so a keyed lookup would miss the very frame on
207
+ * screen. No accounting; it is not a lookup. */
208
+ touch(timestampMs: number): void;
209
+ /** Promotes an owner-assigned key without a timestamp scan. */
210
+ touchKey(key: number): void;
211
+ clear(): void;
212
+ get size(): number;
213
+ /** True timestamps (ms) of resident frames, for diagnostics. Bounded by capacity. */
214
+ timestampsSnapshot(): number[];
215
+ private bump;
216
+ /**
217
+ * Best candidate for `timestampMs`, or null when nothing qualifies.
218
+ *
219
+ * Under `atOrBefore` a stored frame stands for the span from its own
220
+ * timestamp up to the next source frame; a target past that span belongs to
221
+ * the next frame, which is what a decode for it returns. Answering it from
222
+ * this tier would paint a frame no decode for that time ever produces, so a
223
+ * candidate outside its own frame's span is not eligible however generous the
224
+ * caller's tolerance is. Until the tier has learned a frame gap it has no
225
+ * spacing to bound with and the caller's tolerance stands alone.
226
+ */
227
+ private nearest;
228
+ /** Narrows the learned frame interval to the smallest gap seen so far. A gap
229
+ * at or below the key grid is one frame that rounded onto two keys rather
230
+ * than two frames, so it is no interval at all; what survives is a gap
231
+ * between two frames, and never zero. It only ever tightens, so a tier that
232
+ * has watched an unrepresentative stretch of a variable-rate source bounds
233
+ * lookups too tightly (a decode) rather than too loosely (the wrong frame). */
234
+ private observeSpacing;
235
+ }
236
+ export {};
@@ -0,0 +1,27 @@
1
+ import { AnalysisSession, type AnalysisOptions, type ExtractedFrame } from "./analysis-session";
2
+ /**
3
+ * A second consumer of the runtime, built only on AnalysisSession's public
4
+ * surface, with no reach into the cursor, cache, worker, or render loop. Its
5
+ * existence is the proof that the analysis primitive is reusable: a thumbnail
6
+ * strip or contact sheet is just a choice of which timestamps to pull, and the
7
+ * open/close pair shows the full source lifecycle is reachable from the public
8
+ * API alone.
9
+ */
10
+ export declare class FrameExtractor {
11
+ private readonly session;
12
+ constructor(session: AnalysisSession);
13
+ /** Opens a source and returns an extractor that owns it; close() disposes it. */
14
+ static open(options: AnalysisOptions): Promise<FrameExtractor>;
15
+ /** Frames at exactly the given timestamps (seconds). */
16
+ extractAt(timestampsS: readonly number[]): Promise<ExtractedFrame[]>;
17
+ /**
18
+ * `count` frames evenly spaced across the source, each sampled at the
19
+ * middle of its slice so neither the first black frame nor the exact end
20
+ * dominates the strip.
21
+ */
22
+ evenlySpaced(count: number): Promise<ExtractedFrame[]>;
23
+ /** One frame per keyframe in the range: a contact sheet that decodes cheaply. */
24
+ atKeyframes(startS?: number, endS?: number): Promise<ExtractedFrame[]>;
25
+ /** Disposes the underlying analysis session. */
26
+ close(): Promise<void>;
27
+ }