supervision 0.1.4 → 0.1.5

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 (43) hide show
  1. package/dist/index.d.ts +5 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +432 -83
  4. package/dist/index.js.map +1 -1
  5. package/dist/mask-preparation.worker.js +67 -59
  6. package/dist/mask-preparation.worker.js.map +1 -1
  7. package/dist/post-processing/default-tracking-worker.d.ts +3 -0
  8. package/dist/post-processing/default-tracking-worker.d.ts.map +1 -0
  9. package/dist/post-processing/detection-post-processing-pipeline.d.ts +7 -0
  10. package/dist/post-processing/detection-post-processing-pipeline.d.ts.map +1 -0
  11. package/dist/post-processing/embedded-tracking-worker.d.ts +2 -0
  12. package/dist/post-processing/embedded-tracking-worker.d.ts.map +1 -0
  13. package/dist/post-processing/tracking-worker-protocol.d.ts +29 -0
  14. package/dist/post-processing/tracking-worker-protocol.d.ts.map +1 -0
  15. package/dist/post-processing/tracking.worker.d.ts +2 -0
  16. package/dist/post-processing/tracking.worker.d.ts.map +1 -0
  17. package/dist/tracking.worker.js +1485 -0
  18. package/dist/tracking.worker.js.map +1 -0
  19. package/dist/types/detection-post-processing.d.ts +62 -0
  20. package/dist/types/detection-post-processing.d.ts.map +1 -0
  21. package/dist/workers/worker-rpc-client.d.ts +2 -1
  22. package/dist/workers/worker-rpc-client.d.ts.map +1 -1
  23. package/node_modules/supervision-js-core/dist/index.d.ts +6 -0
  24. package/node_modules/supervision-js-core/dist/index.d.ts.map +1 -1
  25. package/node_modules/supervision-js-core/dist/index.js +1600 -255
  26. package/node_modules/supervision-js-core/dist/index.js.map +1 -1
  27. package/node_modules/supervision-js-core/dist/post-processing/byte-track-tracker.d.ts +4 -0
  28. package/node_modules/supervision-js-core/dist/post-processing/byte-track-tracker.d.ts.map +1 -0
  29. package/node_modules/supervision-js-core/dist/post-processing/cbiou-tracker.d.ts +4 -0
  30. package/node_modules/supervision-js-core/dist/post-processing/cbiou-tracker.d.ts.map +1 -0
  31. package/node_modules/supervision-js-core/dist/post-processing/oc-sort-tracker.d.ts +4 -0
  32. package/node_modules/supervision-js-core/dist/post-processing/oc-sort-tracker.d.ts.map +1 -0
  33. package/node_modules/supervision-js-core/dist/post-processing/sort-tracker.d.ts +4 -0
  34. package/node_modules/supervision-js-core/dist/post-processing/sort-tracker.d.ts.map +1 -0
  35. package/node_modules/supervision-js-core/dist/post-processing/tracking.d.ts +9 -0
  36. package/node_modules/supervision-js-core/dist/post-processing/tracking.d.ts.map +1 -0
  37. package/node_modules/supervision-js-core/dist/types/detections.d.ts +11 -3
  38. package/node_modules/supervision-js-core/dist/types/detections.d.ts.map +1 -1
  39. package/node_modules/supervision-js-core/dist/types/post-processing.d.ts +148 -0
  40. package/node_modules/supervision-js-core/dist/types/post-processing.d.ts.map +1 -0
  41. package/node_modules/supervision-js-core/dist/utils/detection-frames.d.ts.map +1 -1
  42. package/node_modules/supervision-js-core/package.json +12 -5
  43. package/package.json +7 -2
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { copySortedDetectionFrames, detectionFrameOverlapsRange, includeDefined, MediaSourceStatus, MediaRendererPlaybackState, MediaRendererFit, createDefaultAnnotationPresentation, createArrayDetectionFrameSource, createBufferedDetectionTimeline, resolveAnnotationRendererPresentation, createIdleDetectionBufferState, MediaInteractionMode, StrokeAlignment, BaseBoxStyle, centerRectToTopLeftRect, BoxShape, BaseFocusStyle, decodeCompressedRleMask, extractMaskRectRuns, AnnotationGestureStateKind, AnnotationHandleKind, getDetectionRect, DetectionPickTarget, createDetectionPickKey, rebaseDetectionPickToFrame, pickDetectionAtPoint, followDetectionPickAcrossFrames, haveSameDetectionPickIdentities, pickAnnotationHandle, getAnnotationHandles, createIdMaskFrame, encodeBinaryMask, rasterizePolygonToMask, LabelPlacement, BasePolygonStyle, BasePolylineStyle, BaseKeypointStyle, KeypointMarkerShape, MarkerSizeSpace, MarkerShape, ShapeInstructionKind, sampleEllipseArc, resolveEllipseSegmentCount, resolveMarkerGeometry, BaseInteractionStyle, DetectionInteractionState, MAX_ID_MASK_PALETTE_ENTRIES, DetectionBufferStatus, canReuseMaskStyleArtifacts, getBufferedDetectionTimelineFrameSnapshot, MAX_ID_MASK_STROKE_WIDTH, resolveMaskStyleOpacity, pickDetectionByMaskId, BoxStrokeAlignment, resolveStyleValue, resolveAnnotationStyleState, lightenColor, createViewportController, MediaSessionMode, DetectionFrameRetentionMode, createMemoryColdDetectionFrameStore, createWritableDetectionFrameSource, createCompositeDetectionFrameSource, MediaSessionActivityStatus, MediaSessionActivityKind, MediaSessionStatus, createSourceAwarePresentation } from 'supervision-js-core';
2
- export { BaseBoxCornerStyle, BaseBoxStyle, BaseFocusStyle, BaseInteractionStyle, BaseKeypointStyle, BaseLabelStyle, BaseMarkerStyle, BaseMaskStyle, BasePolygonStyle, BasePolylineStyle, BoxShape, BoxStrokeAlignment, DEFAULT_DETECTION_CLASS_STYLES, DEFAULT_DETECTION_COLOR_SEQUENCE, DetectionBufferStatus, DetectionFrameRetentionMode, DetectionFrameSelectionMode, DetectionInteractionState, DetectionMaskEncoding, DetectionPickTarget, FocusTargetMode, KeypointMarkerShape, KeypointVisibility, LabelPlacement, LabelVisibilityMode, MarkerShape, MarkerSizeSpace, MaskRenderMode, MediaInteractionMode, MediaRendererFit, MediaRendererPlaybackState, MediaSessionActivityKind, MediaSessionActivityStatus, MediaSessionMode, MediaSessionStatus, MediaSourceStatus, RegionRendererComposeMode, RegionRendererRegionKind, RegionRendererSourceKind, SUPERVISION_ROBOFLOW_COLOR, annotationRendererKinds, annotationRenderers, createArrayDetectionFrameSource, createBufferedDetectionTimeline, createColdDetectionFrameSource, createCompositeDetectionFrameSource, createDefaultAnnotationPresentation, createMemoryColdDetectionFrameStore, createWritableDetectionFrameSource, normalizeDetectionClassName, pickDetectionAtPoint, resolveDetectionClassColorStyle } from 'supervision-js-core';
1
+ import { copySortedDetectionFrames, detectionFrameOverlapsRange, projectDetectionFrameForTracking, createSortTracker, createOCSortTracker, createCBIoUTracker, createByteTrackTracker, includeDefined, MediaSourceStatus, MediaRendererPlaybackState, MediaRendererFit, createDefaultAnnotationPresentation, createArrayDetectionFrameSource, createBufferedDetectionTimeline, resolveAnnotationRendererPresentation, createIdleDetectionBufferState, MediaInteractionMode, StrokeAlignment, BaseBoxStyle, centerRectToTopLeftRect, BoxShape, BaseFocusStyle, decodeCompressedRleMask, extractMaskRectRuns, AnnotationGestureStateKind, AnnotationHandleKind, getDetectionRect, DetectionPickTarget, createDetectionPickKey, rebaseDetectionPickToFrame, pickDetectionAtPoint, followDetectionPickAcrossFrames, haveSameDetectionPickIdentities, pickAnnotationHandle, getAnnotationHandles, createIdMaskFrame, encodeBinaryMask, rasterizePolygonToMask, LabelPlacement, BasePolygonStyle, BasePolylineStyle, BaseKeypointStyle, KeypointMarkerShape, MarkerSizeSpace, MarkerShape, ShapeInstructionKind, sampleEllipseArc, resolveEllipseSegmentCount, resolveMarkerGeometry, BaseInteractionStyle, DetectionInteractionState, MAX_ID_MASK_PALETTE_ENTRIES, DetectionBufferStatus, canReuseMaskStyleArtifacts, getBufferedDetectionTimelineFrameSnapshot, MAX_ID_MASK_STROKE_WIDTH, resolveMaskStyleOpacity, pickDetectionByMaskId, BoxStrokeAlignment, resolveStyleValue, resolveAnnotationStyleState, lightenColor, createViewportController, MediaSessionMode, DetectionFrameRetentionMode, createMemoryColdDetectionFrameStore, createWritableDetectionFrameSource, createCompositeDetectionFrameSource, MediaSessionActivityStatus, MediaSessionActivityKind, MediaSessionStatus, createSourceAwarePresentation } from 'supervision-js-core';
2
+ export { BaseBoxCornerStyle, BaseBoxStyle, BaseFocusStyle, BaseInteractionStyle, BaseKeypointStyle, BaseLabelStyle, BaseMarkerStyle, BaseMaskStyle, BasePolygonStyle, BasePolylineStyle, BoxShape, BoxStrokeAlignment, DEFAULT_DETECTION_CLASS_STYLES, DEFAULT_DETECTION_COLOR_SEQUENCE, DetectionBufferStatus, DetectionFrameRetentionMode, DetectionFrameSelectionMode, DetectionInteractionState, DetectionMaskEncoding, DetectionPickTarget, FocusTargetMode, KeypointMarkerShape, KeypointVisibility, LabelPlacement, LabelVisibilityMode, MarkerShape, MarkerSizeSpace, MaskRenderMode, MediaInteractionMode, MediaRendererFit, MediaRendererPlaybackState, MediaSessionActivityKind, MediaSessionActivityStatus, MediaSessionMode, MediaSessionStatus, MediaSourceStatus, RegionRendererComposeMode, RegionRendererRegionKind, RegionRendererSourceKind, SUPERVISION_ROBOFLOW_COLOR, TrackingGeometry, annotationRendererKinds, annotationRenderers, createArrayDetectionFrameSource, createBufferedDetectionTimeline, createByteTrackTracker, createCBIoUTracker, createColdDetectionFrameSource, createCompositeDetectionFrameSource, createDefaultAnnotationPresentation, createMemoryColdDetectionFrameStore, createOCSortTracker, createSortTracker, createWritableDetectionFrameSource, detectionPostProcessors, normalizeDetectionClassName, pickDetectionAtPoint, projectDetectionFrameForTracking, resolveDetectionClassColorStyle } from 'supervision-js-core';
3
3
 
4
4
  const DEFAULT_DATABASE_NAME = "supervision-js-detection-frames";
5
5
  const DEFAULT_CHUNK_DURATION_SECONDS = 1;
@@ -458,6 +458,434 @@ function getDetectionFrameDedupeKey(frame) {
458
458
  : `index:${frame.frameIndex}`;
459
459
  }
460
460
 
461
+ const EMBEDDED_TRACKING_WORKER_SOURCE = "(function () {\n 'use strict';\n\n /** COCO-compatible keypoint visibility values. */\n var KeypointVisibility;\n (function (KeypointVisibility) {\n KeypointVisibility[KeypointVisibility[\"NotLabeled\"] = 0] = \"NotLabeled\";\n KeypointVisibility[KeypointVisibility[\"Occluded\"] = 1] = \"Occluded\";\n KeypointVisibility[KeypointVisibility[\"Visible\"] = 2] = \"Visible\";\n })(KeypointVisibility || (KeypointVisibility = {}));\n var DetectionMaskEncoding;\n (function (DetectionMaskEncoding) {\n DetectionMaskEncoding[\"CompressedRle\"] = \"compressedRle\";\n })(DetectionMaskEncoding || (DetectionMaskEncoding = {}));\n\n var DetectionBufferStatus;\n (function (DetectionBufferStatus) {\n DetectionBufferStatus[\"Idle\"] = \"idle\";\n DetectionBufferStatus[\"Loading\"] = \"loading\";\n DetectionBufferStatus[\"Ready\"] = \"ready\";\n DetectionBufferStatus[\"Error\"] = \"error\";\n DetectionBufferStatus[\"Destroyed\"] = \"destroyed\";\n })(DetectionBufferStatus || (DetectionBufferStatus = {}));\n /**\n * How the renderer selects the active detection frame for a media timestamp.\n */\n var DetectionFrameSelectionMode;\n (function (DetectionFrameSelectionMode) {\n /**\n * Select the frame whose `[mediaTime, endTime)` interval contains the media\n * time. This is the default for interval annotations and timestamped sources.\n */\n DetectionFrameSelectionMode[\"Interval\"] = \"interval\";\n /**\n * Select from a known inference frame grid using `frameIndex`, `frameRate`,\n * and optional `frameIndexOriginTime`. This is useful when inference was run\n * on normalized frames and playback should snap detections to that grid.\n */\n DetectionFrameSelectionMode[\"NearestFrameIndex\"] = \"nearestFrameIndex\";\n })(DetectionFrameSelectionMode || (DetectionFrameSelectionMode = {}));\n var DetectionFrameRetentionMode;\n (function (DetectionFrameRetentionMode) {\n /**\n * Keep writable detections only in an in-memory store. Useful for ephemeral\n * live streams where old predictions should disappear when evicted.\n */\n DetectionFrameRetentionMode[\"MemoryOnly\"] = \"memoryOnly\";\n /**\n * Persist every written detection frame. Useful for finite media where seek\n * and replay should not require recomputing detections.\n */\n DetectionFrameRetentionMode[\"PersistAll\"] = \"persistAll\";\n /**\n * Persist only the most recent retention window. Useful for long-running\n * streams where replay is bounded to a recent time horizon.\n */\n DetectionFrameRetentionMode[\"PersistWindow\"] = \"persistWindow\";\n })(DetectionFrameRetentionMode || (DetectionFrameRetentionMode = {}));\n\n var AnnotationFrameMutationKind;\n (function (AnnotationFrameMutationKind) {\n AnnotationFrameMutationKind[\"Add\"] = \"add\";\n AnnotationFrameMutationKind[\"Remove\"] = \"remove\";\n AnnotationFrameMutationKind[\"Replace\"] = \"replace\";\n AnnotationFrameMutationKind[\"Transact\"] = \"transact\";\n AnnotationFrameMutationKind[\"Update\"] = \"update\";\n })(AnnotationFrameMutationKind || (AnnotationFrameMutationKind = {}));\n\n /**\n * Creates one stateful SORT tracker for a single ordered media sequence.\n *\n * Defaults, lifecycle semantics, and observation-only output mirror\n * roboflow/trackers SORT. Motion predictions remain internal to association.\n */\n function createSortTracker$1(options = {}) {\n const lostTrackBuffer = normalizeNonNegativeInteger$1(options.lostTrackBuffer ?? 30, \"lostTrackBuffer\");\n const frameRate = options.frameRate ?? 30;\n const trackActivationThreshold = options.trackActivationThreshold ?? 0.25;\n const minimumConsecutiveFrames = normalizePositiveInteger$1(options.minimumConsecutiveFrames ?? 3, \"minimumConsecutiveFrames\");\n const minimumIouThreshold = options.minimumIouThreshold ?? 0.3;\n if (!Number.isFinite(frameRate) || frameRate <= 0) {\n throw new Error(\"frameRate must be a finite positive value.\");\n }\n normalizeUnitInterval$1(trackActivationThreshold, \"trackActivationThreshold\");\n normalizeUnitInterval$1(minimumIouThreshold, \"minimumIouThreshold\");\n const scaledLostTrackBuffer = (frameRate / 30) * lostTrackBuffer;\n if (!Number.isFinite(scaledLostTrackBuffer)) {\n throw new Error(\"Scaled lostTrackBuffer overflows: frameRate / 30 * lostTrackBuffer must be finite.\");\n }\n const maximumFramesWithoutUpdate = lostTrackBuffer === 0 ? 0 : Math.max(1, Math.ceil(scaledLostTrackBuffer));\n let tracks = [];\n let nextTrackerId = 0;\n let previousFrameIndex;\n return {\n reset() {\n tracks = [];\n nextTrackerId = 0;\n previousFrameIndex = undefined;\n },\n update(detections, frameIndex) {\n const frameStep = resolveFrameStep(frameIndex, previousFrameIndex);\n previousFrameIndex = frameIndex ?? previousFrameIndex;\n const predicted = tracks.map((track) => track.predict(frameStep, frameRate));\n const { matches, unmatchedDetections } = associateDetectionsToTracks(detections, predicted, minimumIouThreshold);\n const trackerIds = new Map();\n for (const match of matches) {\n const track = tracks[match.trackIndex];\n const detection = detections[match.detectionIndex];\n track.update(detection);\n if (track.trackerId === undefined &&\n track.successfulUpdates >= minimumConsecutiveFrames) {\n track.trackerId = nextTrackerId;\n nextTrackerId += 1;\n }\n if (track.trackerId !== undefined) {\n trackerIds.set(detection.detectionIndex, track.trackerId);\n }\n }\n for (const detectionIndex of unmatchedDetections) {\n const detection = detections[detectionIndex];\n if ((detection.confidence ?? 1) >= trackActivationThreshold) {\n tracks.push(new KalmanBoxTrack(detection));\n }\n }\n tracks = tracks.filter((track) => track.timeSinceUpdate <= maximumFramesWithoutUpdate &&\n (track.successfulUpdates >= minimumConsecutiveFrames ||\n track.timeSinceUpdate === 0));\n return {\n activeTrackCount: tracks.length,\n assignments: detections.flatMap((detection) => {\n const trackerId = trackerIds.get(detection.detectionIndex);\n return trackerId === undefined\n ? []\n : [{ detectionIndex: detection.detectionIndex, trackerId }];\n }),\n confirmedTrackCount: tracks.filter((track) => track.trackerId !== undefined).length,\n };\n },\n };\n }\n class KalmanBoxTrack {\n consecutiveUpdates;\n trackerId;\n successfulUpdates = 1;\n timeSinceUpdate = 0;\n state;\n covariance = identity(8);\n constructor(detection, consecutiveUpdates = false) {\n this.consecutiveUpdates = consecutiveUpdates;\n this.state = [...rectToXyxy(detection.rect), 0, 0, 0, 0].map((value) => [\n value,\n ]);\n }\n predict(frameStep, frameRate) {\n if (this.consecutiveUpdates && this.timeSinceUpdate > 0) {\n this.successfulUpdates = 0;\n }\n const transition = identity(8);\n for (let index = 0; index < 4; index += 1) {\n transition[index][index + 4] = frameStep;\n }\n this.state = multiply(transition, this.state);\n this.covariance = add(multiply(multiply(transition, this.covariance), transpose(transition)), createProcessNoise(frameStep, frameRate));\n // Python SORT counts update calls for the fixed-rate lost-track budget.\n this.timeSinceUpdate += 1;\n return stateToRect(this.state);\n }\n update(detection) {\n const measurement = rectToXyxy(detection.rect).map((value) => [value]);\n const observation = [\n [1, 0, 0, 0, 0, 0, 0, 0],\n [0, 1, 0, 0, 0, 0, 0, 0],\n [0, 0, 1, 0, 0, 0, 0, 0],\n [0, 0, 0, 1, 0, 0, 0, 0],\n ];\n const measurementNoise = scale(identity(4), 0.1);\n const innovation = subtract(measurement, multiply(observation, this.state));\n const covarianceObservationTranspose = multiply(this.covariance, transpose(observation));\n const innovationCovariance = add(multiply(observation, covarianceObservationTranspose), measurementNoise);\n const gain = multiply(covarianceObservationTranspose, inverse(innovationCovariance));\n this.state = add(this.state, multiply(gain, innovation));\n const identityMinusGainObservation = subtract(identity(8), multiply(gain, observation));\n // Joseph form matches the Python implementation and is more stable.\n this.covariance = add(multiply(multiply(identityMinusGainObservation, this.covariance), transpose(identityMinusGainObservation)), multiply(multiply(gain, measurementNoise), transpose(gain)));\n this.timeSinceUpdate = 0;\n this.successfulUpdates += 1;\n }\n getStateRect() {\n return stateToRect(this.state);\n }\n }\n function associateDetectionsToTracks(detections, predicted, minimumIouThreshold) {\n if (predicted.length === 0 || detections.length === 0) {\n return {\n matches: [],\n unmatchedDetections: detections.map((_, index) => index),\n };\n }\n // Python SORT associates all detections class-agnostically using standard IoU.\n const scores = predicted.map((rect) => detections.map((detection) => intersectionOverUnion(rect, detection.rect)));\n const candidateMatches = maximizeAssignment(scores);\n const matches = [];\n const matchedDetections = new Set();\n for (const [trackIndex, detectionIndex] of candidateMatches) {\n if (scores[trackIndex][detectionIndex] < minimumIouThreshold)\n continue;\n matches.push({ detectionIndex, trackIndex });\n matchedDetections.add(detectionIndex);\n }\n matches.sort((left, right) => left.trackIndex - right.trackIndex);\n return {\n matches,\n unmatchedDetections: detections.flatMap((_, index) => matchedDetections.has(index) ? [] : [index]),\n };\n }\n /** Hungarian assignment for a rectangular score matrix. */\n function maximizeAssignment(scores) {\n if (scores.length === 0 || scores[0]?.length === 0) {\n return [];\n }\n const rowCount = scores.length;\n const columnCount = scores[0].length;\n const transposed = rowCount > columnCount;\n const costs = transposed\n ? Array.from({ length: columnCount }, (_, row) => Array.from({ length: rowCount }, (_, column) => 1 - scores[column][row]))\n : scores.map((row) => row.map((score) => 1 - score));\n const rows = costs.length;\n const columns = costs[0].length;\n const u = new Array(rows + 1).fill(0);\n const v = new Array(columns + 1).fill(0);\n const p = new Array(columns + 1).fill(0);\n const way = new Array(columns + 1).fill(0);\n for (let row = 1; row <= rows; row += 1) {\n p[0] = row;\n let column0 = 0;\n const minValue = new Array(columns + 1).fill(Number.POSITIVE_INFINITY);\n const used = new Array(columns + 1).fill(false);\n do {\n used[column0] = true;\n const row0 = p[column0];\n let delta = Number.POSITIVE_INFINITY;\n let column1 = 0;\n for (let column = 1; column <= columns; column += 1) {\n if (used[column])\n continue;\n const current = costs[row0 - 1][column - 1] - u[row0] - v[column];\n if (current < minValue[column]) {\n minValue[column] = current;\n way[column] = column0;\n }\n if (minValue[column] < delta) {\n delta = minValue[column];\n column1 = column;\n }\n }\n for (let column = 0; column <= columns; column += 1) {\n if (used[column]) {\n u[p[column]] += delta;\n v[column] -= delta;\n }\n else {\n minValue[column] -= delta;\n }\n }\n column0 = column1;\n } while (p[column0] !== 0);\n do {\n const column1 = way[column0];\n p[column0] = p[column1];\n column0 = column1;\n } while (column0 !== 0);\n }\n const assignments = [];\n for (let column = 1; column <= columns; column += 1) {\n if (p[column] === 0)\n continue;\n const row = p[column] - 1;\n assignments.push(transposed ? [column - 1, row] : [row, column - 1]);\n }\n return assignments;\n }\n function rectToXyxy(rect) {\n return [\n rect.x - rect.width / 2,\n rect.y - rect.height / 2,\n rect.x + rect.width / 2,\n rect.y + rect.height / 2,\n ];\n }\n function stateToRect(state) {\n // The Python XYXY estimator intentionally leaves corner velocities\n // unconstrained. Normalize only at the browser Rect boundary so a crossing\n // prediction cannot violate the positive-width/height storage contract.\n const x1 = Math.min(state[0][0], state[2][0]);\n const y1 = Math.min(state[1][0], state[3][0]);\n const x2 = Math.max(state[0][0], state[2][0]);\n const y2 = Math.max(state[1][0], state[3][0]);\n return {\n height: Math.max(Number.EPSILON, y2 - y1),\n width: Math.max(Number.EPSILON, x2 - x1),\n x: (x1 + x2) / 2,\n y: (y1 + y2) / 2,\n };\n }\n function createProcessNoise(frameStep, frameRate) {\n if (Math.abs(frameStep - 1) <= 0.004 * frameRate) {\n return scale(identity(8), 0.01);\n }\n const result = Array.from({ length: 8 }, () => new Array(8).fill(0));\n const dt2 = frameStep * frameStep;\n const dt3 = dt2 * frameStep;\n const dt4 = dt2 * dt2;\n for (let index = 0; index < 4; index += 1) {\n const velocityIndex = index + 4;\n result[index][index] = (0.01 * dt4) / 4;\n result[index][velocityIndex] = (0.01 * dt3) / 2;\n result[velocityIndex][index] = (0.01 * dt3) / 2;\n result[velocityIndex][velocityIndex] = 0.01 * dt2;\n }\n return result;\n }\n function intersectionOverUnion(left, right) {\n const leftX = left.x - left.width / 2;\n const leftY = left.y - left.height / 2;\n const rightX = right.x - right.width / 2;\n const rightY = right.y - right.height / 2;\n const intersectionWidth = Math.max(0, Math.min(leftX + left.width, rightX + right.width) -\n Math.max(leftX, rightX));\n const intersectionHeight = Math.max(0, Math.min(leftY + left.height, rightY + right.height) -\n Math.max(leftY, rightY));\n const intersection = intersectionWidth * intersectionHeight;\n const union = left.width * left.height + right.width * right.height - intersection;\n return union <= 0 ? 0 : intersection / union;\n }\n function resolveFrameStep(current, previous) {\n if (current === undefined || previous === undefined)\n return 1;\n return Math.max(1, current - previous);\n }\n function normalizePositiveInteger$1(value, label) {\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`${label} must be a positive integer.`);\n }\n return value;\n }\n function normalizeNonNegativeInteger$1(value, label) {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`${label} must be a non-negative integer.`);\n }\n return value;\n }\n function normalizeUnitInterval$1(value, label) {\n if (!Number.isFinite(value) || value < 0 || value > 1) {\n throw new Error(`${label} must be between 0 and 1.`);\n }\n }\n function identity(size) {\n return Array.from({ length: size }, (_, row) => Array.from({ length: size }, (_, column) => (row === column ? 1 : 0)));\n }\n function scale(matrix, factor) {\n return matrix.map((row) => row.map((value) => value * factor));\n }\n function transpose(matrix) {\n return matrix[0].map((_, column) => matrix.map((row) => row[column]));\n }\n function add(left, right) {\n return left.map((row, rowIndex) => row.map((value, columnIndex) => value + right[rowIndex][columnIndex]));\n }\n function subtract(left, right) {\n return left.map((row, rowIndex) => row.map((value, columnIndex) => value - right[rowIndex][columnIndex]));\n }\n function multiply(left, right) {\n return left.map((row) => right[0].map((_, column) => row.reduce((sum, value, index) => sum + value * right[index][column], 0)));\n }\n function inverse(matrix) {\n const size = matrix.length;\n const augmented = matrix.map((row, index) => [\n ...row,\n ...identity(size)[index],\n ]);\n for (let column = 0; column < size; column += 1) {\n let pivot = column;\n for (let row = column + 1; row < size; row += 1) {\n if (Math.abs(augmented[row][column]) >\n Math.abs(augmented[pivot][column])) {\n pivot = row;\n }\n }\n if (Math.abs(augmented[pivot][column]) < 1e-12) {\n throw new Error(\"SORT Kalman covariance is singular.\");\n }\n [augmented[column], augmented[pivot]] = [\n augmented[pivot],\n augmented[column],\n ];\n const divisor = augmented[column][column];\n augmented[column] = augmented[column].map((value) => value / divisor);\n for (let row = 0; row < size; row += 1) {\n if (row === column)\n continue;\n const factor = augmented[row][column];\n augmented[row] = augmented[row].map((value, index) => value - factor * augmented[column][index]);\n }\n }\n return augmented.map((row) => row.slice(size));\n }\n\n /**\n * Creates one stateful ByteTrack tracker for a single ordered media sequence.\n *\n * Defaults and two-stage association mirror roboflow/trackers ByteTrack at\n * source commit 60b21c8a48676784085fbee455559f16b75a7c9a.\n * Motion predictions remain internal; only observed detections receive IDs.\n */\n function createByteTrackTracker$1(options = {}) {\n const lostTrackBuffer = normalizeNonNegativeInteger$1(options.lostTrackBuffer ?? 30, \"lostTrackBuffer\");\n const frameRate = options.frameRate ?? 30;\n const trackActivationThreshold = options.trackActivationThreshold ?? 0.7;\n const minimumConsecutiveFrames = normalizePositiveInteger$1(options.minimumConsecutiveFrames ?? 2, \"minimumConsecutiveFrames\");\n const minimumIouThreshold = options.minimumIouThreshold ?? 0.1;\n const highConfidenceDetectionThreshold = options.highConfidenceDetectionThreshold ?? 0.6;\n if (!Number.isFinite(frameRate) || frameRate <= 0) {\n throw new Error(\"frameRate must be a finite positive value.\");\n }\n normalizeUnitInterval$1(trackActivationThreshold, \"trackActivationThreshold\");\n normalizeUnitInterval$1(minimumIouThreshold, \"minimumIouThreshold\");\n normalizeUnitInterval$1(highConfidenceDetectionThreshold, \"highConfidenceDetectionThreshold\");\n const scaledLostTrackBuffer = (frameRate / 30) * lostTrackBuffer;\n if (!Number.isFinite(scaledLostTrackBuffer)) {\n throw new Error(\"Scaled lostTrackBuffer overflows: frameRate / 30 * lostTrackBuffer must be finite.\");\n }\n const maximumFramesWithoutUpdate = lostTrackBuffer === 0 ? 0 : Math.max(1, Math.ceil(scaledLostTrackBuffer));\n let tracks = [];\n let nextTrackerId = 0;\n let previousFrameIndex;\n return {\n reset() {\n tracks = [];\n nextTrackerId = 0;\n previousFrameIndex = undefined;\n },\n update(detections, frameIndex) {\n const frameStep = resolveFrameStep(frameIndex, previousFrameIndex);\n previousFrameIndex = frameIndex ?? previousFrameIndex;\n tracks.forEach((track) => track.predict(frameStep, frameRate));\n const highDetectionIndexes = [];\n const lowDetectionIndexes = [];\n detections.forEach((detection, index) => {\n if ((detection.confidence ?? 1) >= highConfidenceDetectionThreshold) {\n highDetectionIndexes.push(index);\n }\n else {\n lowDetectionIndexes.push(index);\n }\n });\n const assignments = new Map();\n const firstStage = associate(tracks, detections, highDetectionIndexes, minimumIouThreshold);\n for (const match of firstStage.matches) {\n updateMatchedTrack(tracks[match.trackIndex], detections[match.detectionIndex], assignments);\n }\n const remainingTracks = firstStage.unmatchedTrackIndexes.map((index) => tracks[index]);\n const secondStage = associate(remainingTracks, detections, lowDetectionIndexes, minimumIouThreshold);\n for (const match of secondStage.matches) {\n updateMatchedTrack(remainingTracks[match.trackIndex], detections[match.detectionIndex], assignments);\n }\n // Only unmatched high-confidence observations can start a track.\n for (const detectionIndex of firstStage.unmatchedDetectionIndexes) {\n const detection = detections[detectionIndex];\n if ((detection.confidence ?? 1) >= trackActivationThreshold) {\n tracks.push(new KalmanBoxTrack(detection, true));\n }\n }\n // Confirmation is sticky once an ID has been allocated. An unmatched\n // unconfirmed track is discarded immediately, as in Python ByteTrack.\n tracks = tracks.filter((track) => track.timeSinceUpdate <= maximumFramesWithoutUpdate &&\n (track.trackerId !== undefined ||\n track.successfulUpdates >= minimumConsecutiveFrames ||\n track.timeSinceUpdate === 0));\n return {\n activeTrackCount: tracks.length,\n assignments: detections.flatMap((detection) => {\n const trackerId = assignments.get(detection.detectionIndex);\n return trackerId === undefined\n ? []\n : [{ detectionIndex: detection.detectionIndex, trackerId }];\n }),\n confirmedTrackCount: tracks.filter((track) => track.trackerId !== undefined).length,\n };\n },\n };\n function updateMatchedTrack(track, detection, assignments) {\n track.update(detection);\n if (track.trackerId === undefined &&\n track.successfulUpdates >= minimumConsecutiveFrames) {\n track.trackerId = nextTrackerId;\n nextTrackerId += 1;\n }\n if (track.trackerId !== undefined) {\n assignments.set(detection.detectionIndex, track.trackerId);\n }\n }\n }\n function associate(tracks, detections, detectionIndexes, minimumIouThreshold) {\n if (tracks.length === 0 || detectionIndexes.length === 0) {\n return {\n matches: [],\n unmatchedDetectionIndexes: [...detectionIndexes],\n unmatchedTrackIndexes: tracks.map((_, index) => index),\n };\n }\n const scores = tracks.map((track) => {\n const predictedRect = track.getStateRect();\n return detectionIndexes.map((detectionIndex) => intersectionOverUnion(predictedRect, detections[detectionIndex].rect));\n });\n const matches = [];\n const matchedTracks = new Set();\n const matchedDetections = new Set();\n for (const [trackIndex, localDetectionIndex] of maximizeAssignment(scores)) {\n if (scores[trackIndex][localDetectionIndex] < minimumIouThreshold) {\n continue;\n }\n const detectionIndex = detectionIndexes[localDetectionIndex];\n matches.push({ detectionIndex, trackIndex });\n matchedTracks.add(trackIndex);\n matchedDetections.add(detectionIndex);\n }\n matches.sort((left, right) => left.trackIndex - right.trackIndex);\n return {\n matches,\n unmatchedDetectionIndexes: detectionIndexes.filter((index) => !matchedDetections.has(index)),\n unmatchedTrackIndexes: tracks.flatMap((_, index) => matchedTracks.has(index) ? [] : [index]),\n };\n }\n\n function associateTrackingScores(scores, trackCount, detectionCount, minimumScore, acceptanceScores = scores) {\n const matches = [];\n const matchedTracks = new Set();\n const matchedDetections = new Set();\n for (const [trackIndex, detectionIndex] of maximizeAssignment(scores)) {\n if (acceptanceScores[trackIndex][detectionIndex] < minimumScore)\n continue;\n matches.push({ detectionIndex, trackIndex });\n matchedTracks.add(trackIndex);\n matchedDetections.add(detectionIndex);\n }\n matches.sort((left, right) => left.trackIndex - right.trackIndex);\n return {\n matches,\n unmatchedDetectionIndexes: Array.from({ length: detectionCount }, (_, index) => index).filter((index) => !matchedDetections.has(index)),\n unmatchedTrackIndexes: Array.from({ length: trackCount }, (_, index) => index).filter((index) => !matchedTracks.has(index)),\n };\n }\n function pairwiseIou(tracks, detections, bufferRatio = 0) {\n return tracks.map((track) => detections.map((detection) => bufferedIntersectionOverUnion(track, detection, bufferRatio)));\n }\n function bufferedIntersectionOverUnion(left, right, bufferRatio) {\n const leftWidth = left.width * (1 + 2 * bufferRatio);\n const leftHeight = left.height * (1 + 2 * bufferRatio);\n const rightWidth = right.width * (1 + 2 * bufferRatio);\n const rightHeight = right.height * (1 + 2 * bufferRatio);\n const leftX = left.x - leftWidth / 2;\n const leftY = left.y - leftHeight / 2;\n const rightX = right.x - rightWidth / 2;\n const rightY = right.y - rightHeight / 2;\n const intersectionWidth = Math.max(0, Math.min(leftX + leftWidth, rightX + rightWidth) - Math.max(leftX, rightX));\n const intersectionHeight = Math.max(0, Math.min(leftY + leftHeight, rightY + rightHeight) -\n Math.max(leftY, rightY));\n const intersection = intersectionWidth * intersectionHeight;\n const union = leftWidth * leftHeight + rightWidth * rightHeight - intersection;\n return union <= 0 ? 0 : intersection / union;\n }\n\n /**\n * Kalman state estimator shared by the browser C-BIoU and OC-SORT ports.\n * Its layouts, covariance update, and gap-scaled constant-velocity model\n * mirror roboflow/trackers at 60b21c8.\n */\n class TrackingKalmanEstimator {\n representation;\n dimension;\n measurementDimension = 4;\n covariance;\n measurementNoise = identity(4);\n processNoise;\n state;\n baselineProcessNoise;\n positionIndexes;\n velocityIndexes;\n constructor(initialRect, representation) {\n this.representation = representation;\n const measurement = rectToMeasurement(initialRect, representation);\n this.dimension = representation === \"xcycsr\" ? 7 : 8;\n this.positionIndexes =\n representation === \"xcycsr\" ? [0, 1, 2] : [0, 1, 2, 3];\n this.velocityIndexes =\n representation === \"xcycsr\" ? [4, 5, 6] : [4, 5, 6, 7];\n this.state = Array.from({ length: this.dimension }, (_, index) => [\n measurement[index] ?? 0,\n ]);\n this.covariance = identity(this.dimension);\n this.processNoise = identity(this.dimension);\n this.baselineProcessNoise = identity(this.dimension);\n }\n predict(frameStep, frameRate) {\n if (this.representation === \"xcycsr\" &&\n this.state[2][0] + frameStep * this.state[6][0] <= 0) {\n this.state[6][0] = 0;\n }\n const transition = identity(this.dimension);\n this.positionIndexes.forEach((positionIndex, index) => {\n transition[positionIndex][this.velocityIndexes[index]] = frameStep;\n });\n this.processNoise = this.createProcessNoise(frameStep, frameRate);\n this.state = multiply(transition, this.state);\n this.covariance = add(multiply(multiply(transition, this.covariance), transpose(transition)), this.processNoise);\n }\n update(rect) {\n this.updateMeasurement(rectToMeasurement(rect, this.representation));\n }\n updateMeasurement(measurement) {\n const observation = Array.from({ length: 4 }, (_, row) => Array.from({ length: this.dimension }, (_, column) => row === column ? 1 : 0));\n const measurementColumn = measurement.map((value) => [value]);\n const innovation = subtract(measurementColumn, multiply(observation, this.state));\n const covarianceObservationTranspose = multiply(this.covariance, transpose(observation));\n const innovationCovariance = add(multiply(observation, covarianceObservationTranspose), this.measurementNoise);\n const gain = multiply(covarianceObservationTranspose, inverse(innovationCovariance));\n this.state = add(this.state, multiply(gain, innovation));\n const identityMinusGainObservation = subtract(identity(this.dimension), multiply(gain, observation));\n this.covariance = add(multiply(multiply(identityMinusGainObservation, this.covariance), transpose(identityMinusGainObservation)), multiply(multiply(gain, this.measurementNoise), transpose(gain)));\n }\n getRect() {\n return measurementToRect(this.state.slice(0, 4).map((row) => row[0]), this.representation);\n }\n setCovariances(options) {\n if (options.covariance)\n this.covariance = clone(options.covariance);\n if (options.measurementNoise) {\n this.measurementNoise = clone(options.measurementNoise);\n }\n if (options.processNoise) {\n this.processNoise = clone(options.processNoise);\n this.baselineProcessNoise = clone(options.processNoise);\n }\n }\n snapshot() {\n return {\n covariance: clone(this.covariance),\n measurementNoise: clone(this.measurementNoise),\n processNoise: clone(this.processNoise),\n state: clone(this.state),\n };\n }\n restore(snapshot) {\n this.covariance = clone(snapshot.covariance);\n this.measurementNoise = clone(snapshot.measurementNoise);\n this.processNoise = clone(snapshot.processNoise);\n this.state = clone(snapshot.state);\n }\n createProcessNoise(frameStep, frameRate) {\n if (Math.abs(frameStep - 1) <= 0.004 * frameRate) {\n return clone(this.baselineProcessNoise);\n }\n const result = Array.from({ length: this.dimension }, () => new Array(this.dimension).fill(0));\n const dt2 = frameStep * frameStep;\n const dt3 = dt2 * frameStep;\n const dt4 = dt2 * dt2;\n const kinematicIndexes = new Set([\n ...this.positionIndexes,\n ...this.velocityIndexes,\n ]);\n this.positionIndexes.forEach((positionIndex, index) => {\n const velocityIndex = this.velocityIndexes[index];\n const accelerationVariance = this.baselineProcessNoise[velocityIndex][velocityIndex];\n result[positionIndex][positionIndex] = (accelerationVariance * dt4) / 4;\n result[positionIndex][velocityIndex] = (accelerationVariance * dt3) / 2;\n result[velocityIndex][positionIndex] = (accelerationVariance * dt3) / 2;\n result[velocityIndex][velocityIndex] = accelerationVariance * dt2;\n });\n for (let index = 0; index < this.dimension; index += 1) {\n if (!kinematicIndexes.has(index)) {\n result[index][index] = this.baselineProcessNoise[index][index];\n }\n }\n return result;\n }\n }\n function rectToMeasurement(rect, representation) {\n if (representation === \"xcycwh\") {\n return [rect.x, rect.y, rect.width, rect.height];\n }\n return [\n rect.x,\n rect.y,\n rect.width * rect.height,\n rect.width / (rect.height + 1e-6),\n ];\n }\n function measurementToRect(measurement, representation) {\n const [x, y, third, fourth] = measurement;\n if (representation === \"xcycwh\") {\n return {\n height: Math.max(1e-3, fourth),\n width: Math.max(1e-3, third),\n x,\n y,\n };\n }\n const width = Math.sqrt(third * fourth);\n const height = width === 0 ? 0 : third / width;\n return {\n height: Math.max(Number.EPSILON, height),\n width: Math.max(Number.EPSILON, width),\n x,\n y,\n };\n }\n function diagonal(values) {\n return values.map((value, row) => values.map((_, column) => (row === column ? value : 0)));\n }\n function scaleMatrix(matrix, factor) {\n return scale(matrix, factor);\n }\n function clone(matrix) {\n return matrix.map((row) => [...row]);\n }\n\n const MINIMUM_DETECTION_CONFIDENCE = 0.1;\n class CBIoUTrack {\n trackerId;\n successfulUpdates = 1;\n timeSinceUpdate = 0;\n estimator;\n constructor(initial) {\n this.estimator = new TrackingKalmanEstimator(initial.rect, \"xcycwh\");\n this.setInitialNoise(initial.rect.width, initial.rect.height);\n }\n predict(frameStep, frameRate) {\n const current = this.estimator.getRect();\n this.estimator.setCovariances({\n processNoise: this.buildProcessNoise(Math.max(current.width, 1e-3), Math.max(current.height, 1e-3)),\n });\n this.estimator.predict(frameStep, frameRate);\n this.clampState();\n this.timeSinceUpdate += 1;\n }\n update(detection) {\n const current = this.estimator.getRect();\n this.estimator.setCovariances({\n measurementNoise: this.buildMeasurementNoise(Math.max(current.width, 1e-3), Math.max(current.height, 1e-3)),\n });\n this.estimator.update(detection.rect);\n this.clampState();\n this.timeSinceUpdate = 0;\n this.successfulUpdates += 1;\n }\n getRect() {\n return this.estimator.getRect();\n }\n setInitialNoise(width, height) {\n const sigmaPosition = 0.05;\n const sigmaVelocity = 0.00625;\n this.estimator.setCovariances({\n covariance: diagonal([\n (2 * sigmaPosition * width) ** 2,\n (2 * sigmaPosition * height) ** 2,\n (2 * sigmaPosition * width) ** 2,\n (2 * sigmaPosition * height) ** 2,\n (10 * sigmaVelocity * width) ** 2,\n (10 * sigmaVelocity * height) ** 2,\n (10 * sigmaVelocity * width) ** 2,\n (10 * sigmaVelocity * height) ** 2,\n ]),\n measurementNoise: this.buildMeasurementNoise(width, height),\n processNoise: this.buildProcessNoise(width, height),\n });\n }\n buildProcessNoise(width, height) {\n const sigmaPosition = 0.05;\n const sigmaVelocity = 0.00625;\n return diagonal([\n (sigmaPosition * width) ** 2,\n (sigmaPosition * height) ** 2,\n (sigmaPosition * width) ** 2,\n (sigmaPosition * height) ** 2,\n (sigmaVelocity * width) ** 2,\n (sigmaVelocity * height) ** 2,\n (sigmaVelocity * width) ** 2,\n (sigmaVelocity * height) ** 2,\n ]);\n }\n buildMeasurementNoise(width, height) {\n const sigmaMeasurement = 0.05;\n return diagonal([\n (sigmaMeasurement * width) ** 2,\n (sigmaMeasurement * height) ** 2,\n (sigmaMeasurement * width) ** 2,\n (sigmaMeasurement * height) ** 2,\n ]);\n }\n clampState() {\n this.estimator.state[2][0] = Math.max(this.estimator.state[2][0], 1e-3);\n this.estimator.state[3][0] = Math.max(this.estimator.state[3][0], 1e-3);\n }\n }\n /** Creates the detection-only C-BIoU implementation from roboflow/trackers. */\n function createCBIoUTracker$1(options = {}) {\n const lostTrackBuffer = normalizeNonNegativeInteger$1(options.lostTrackBuffer ?? 30, \"lostTrackBuffer\");\n const frameRate = options.frameRate ?? 30;\n const trackActivationThreshold = options.trackActivationThreshold ?? 0.7;\n const minimumConsecutiveFrames = normalizePositiveInteger$1(options.minimumConsecutiveFrames ?? 2, \"minimumConsecutiveFrames\");\n const minimumIouThresholdFirstAssociation = options.minimumIouThresholdFirstAssociation ?? 0.2;\n const minimumIouThresholdSecondAssociation = options.minimumIouThresholdSecondAssociation ?? 0.5;\n const minimumIouThresholdUnconfirmedAssociation = options.minimumIouThresholdUnconfirmedAssociation ?? 0.3;\n const highConfidenceDetectionThreshold = options.highConfidenceDetectionThreshold ?? 0.6;\n const instantFirstFrameActivation = options.instantFirstFrameActivation ?? true;\n const bufferRatioFirst = options.bufferRatioFirst ?? 0.3;\n const bufferRatioSecond = options.bufferRatioSecond ?? 0.5;\n if (!Number.isFinite(frameRate) || frameRate <= 0) {\n throw new Error(\"frameRate must be a finite positive value.\");\n }\n normalizeUnitInterval$1(trackActivationThreshold, \"trackActivationThreshold\");\n normalizeUnitInterval$1(minimumIouThresholdFirstAssociation, \"minimumIouThresholdFirstAssociation\");\n normalizeUnitInterval$1(minimumIouThresholdSecondAssociation, \"minimumIouThresholdSecondAssociation\");\n normalizeUnitInterval$1(minimumIouThresholdUnconfirmedAssociation, \"minimumIouThresholdUnconfirmedAssociation\");\n normalizeUnitInterval$1(highConfidenceDetectionThreshold, \"highConfidenceDetectionThreshold\");\n if (!Number.isFinite(bufferRatioFirst) || bufferRatioFirst < 0) {\n throw new Error(\"bufferRatioFirst must be a finite non-negative value.\");\n }\n if (!Number.isFinite(bufferRatioSecond) || bufferRatioSecond < 0) {\n throw new Error(\"bufferRatioSecond must be a finite non-negative value.\");\n }\n const scaledLostTrackBuffer = (frameRate / 30) * lostTrackBuffer;\n if (!Number.isFinite(scaledLostTrackBuffer)) {\n throw new Error(\"Scaled lostTrackBuffer overflows: frameRate / 30 * lostTrackBuffer must be finite.\");\n }\n const maximumFramesWithoutUpdate = lostTrackBuffer === 0 ? 0 : Math.max(1, Math.ceil(scaledLostTrackBuffer));\n let tracks = [];\n let nextTrackerId = 0;\n let frameId = 0;\n let previousFrameIndex;\n return {\n reset() {\n tracks = [];\n nextTrackerId = 0;\n frameId = 0;\n previousFrameIndex = undefined;\n },\n update(detections, frameIndex) {\n const frameStep = resolveFrameStep(frameIndex, previousFrameIndex);\n previousFrameIndex = frameIndex ?? previousFrameIndex;\n frameId += 1;\n tracks.forEach((track) => track.predict(frameStep, frameRate));\n const highDetectionIndexes = [];\n const lowDetectionIndexes = [];\n detections.forEach((detection, index) => {\n const confidence = detection.confidence ?? 1;\n if (confidence >= highConfidenceDetectionThreshold) {\n highDetectionIndexes.push(index);\n }\n else if (confidence > MINIMUM_DETECTION_CONFIDENCE) {\n lowDetectionIndexes.push(index);\n }\n });\n const confirmed = [];\n const unconfirmed = [];\n const lost = [];\n for (const track of tracks) {\n if (track.timeSinceUpdate > 1)\n lost.push(track);\n else if (track.trackerId !== undefined ||\n track.successfulUpdates >= minimumConsecutiveFrames) {\n confirmed.push(track);\n }\n else\n unconfirmed.push(track);\n }\n const assignments = new Map();\n const pool = [...confirmed, ...lost];\n const highDetections = highDetectionIndexes.map((index) => detections[index]);\n const firstScores = pairwiseIou(pool.map((track) => track.getRect()), highDetections.map((detection) => detection.rect), bufferRatioFirst).map((row) => row.map((score, index) => score * (highDetections[index].confidence ?? 1)));\n const firstAssociation = associateTrackingScores(firstScores, pool.length, highDetections.length, minimumIouThresholdFirstAssociation);\n for (const match of firstAssociation.matches) {\n updateMatchedTrack(pool[match.trackIndex], highDetections[match.detectionIndex], assignments);\n }\n const remainingTracked = firstAssociation.unmatchedTrackIndexes\n .map((index) => pool[index])\n .filter((track) => track.timeSinceUpdate === 1);\n const lowDetections = lowDetectionIndexes.map((index) => detections[index]);\n const secondScores = pairwiseIou(remainingTracked.map((track) => track.getRect()), lowDetections.map((detection) => detection.rect), bufferRatioSecond);\n const secondAssociation = associateTrackingScores(secondScores, remainingTracked.length, lowDetections.length, minimumIouThresholdSecondAssociation);\n for (const match of secondAssociation.matches) {\n updateMatchedTrack(remainingTracked[match.trackIndex], lowDetections[match.detectionIndex], assignments);\n }\n let unmatchedHighLocal = [...firstAssociation.unmatchedDetectionIndexes];\n let unmatchedUnconfirmed = unconfirmed.map((_, index) => index);\n if (unconfirmed.length > 0 && unmatchedHighLocal.length > 0) {\n const remainingHigh = unmatchedHighLocal.map((index) => highDetections[index]);\n const unconfirmedScores = pairwiseIou(unconfirmed.map((track) => track.getRect()), remainingHigh.map((detection) => detection.rect), bufferRatioFirst).map((row) => row.map((score, index) => score * (remainingHigh[index].confidence ?? 1)));\n const unconfirmedAssociation = associateTrackingScores(unconfirmedScores, unconfirmed.length, remainingHigh.length, minimumIouThresholdUnconfirmedAssociation);\n unmatchedUnconfirmed = unconfirmedAssociation.unmatchedTrackIndexes;\n for (const match of unconfirmedAssociation.matches) {\n updateMatchedTrack(unconfirmed[match.trackIndex], remainingHigh[match.detectionIndex], assignments);\n }\n unmatchedHighLocal =\n unconfirmedAssociation.unmatchedDetectionIndexes.map((index) => unmatchedHighLocal[index]);\n }\n const unmatchedUnconfirmedTracks = new Set(unmatchedUnconfirmed.map((index) => unconfirmed[index]));\n tracks = tracks.filter((track) => !unmatchedUnconfirmedTracks.has(track));\n for (const localIndex of unmatchedHighLocal) {\n const detection = highDetections[localIndex];\n if ((detection.confidence ?? 1) < trackActivationThreshold)\n continue;\n const track = new CBIoUTrack(detection);\n if (frameId === 1 && instantFirstFrameActivation) {\n track.trackerId = nextTrackerId++;\n assignments.set(detection.detectionIndex, track.trackerId);\n }\n tracks.push(track);\n }\n tracks = tracks.filter((track) => track.timeSinceUpdate <= maximumFramesWithoutUpdate &&\n (track.timeSinceUpdate === 0 ||\n track.trackerId !== undefined ||\n track.successfulUpdates >= minimumConsecutiveFrames));\n return createUpdate(detections, assignments, tracks);\n },\n };\n function updateMatchedTrack(track, detection, assignments) {\n track.update(detection);\n if (track.trackerId === undefined &&\n track.successfulUpdates >= minimumConsecutiveFrames) {\n track.trackerId = nextTrackerId++;\n }\n if (track.trackerId !== undefined) {\n assignments.set(detection.detectionIndex, track.trackerId);\n }\n }\n }\n function createUpdate(detections, assignments, tracks) {\n const resolvedAssignments = detections.flatMap((detection) => {\n const trackerId = assignments.get(detection.detectionIndex);\n return trackerId === undefined\n ? []\n : [{ detectionIndex: detection.detectionIndex, trackerId }];\n });\n return {\n activeTrackCount: tracks.length,\n assignments: resolvedAssignments,\n confirmedTrackCount: tracks.filter((track) => track.trackerId !== undefined)\n .length,\n };\n }\n\n class OCSortTrack {\n deltaT;\n age = 0;\n lastObservation;\n trackerId;\n successfulConsecutiveUpdates = 0;\n timeSinceUpdate = 0;\n velocity;\n frozenState;\n observed = true;\n observations = new Map();\n estimator;\n constructor(initial, deltaT) {\n this.deltaT = deltaT;\n this.lastObservation = initial;\n this.estimator = new TrackingKalmanEstimator(initial.rect, \"xcycsr\");\n this.configureNoise();\n }\n predict(frameStep, frameRate) {\n if (this.observed && this.timeSinceUpdate > 0) {\n this.frozenState = this.estimator.snapshot();\n this.observed = false;\n }\n this.estimator.predict(frameStep, frameRate);\n if (this.timeSinceUpdate > 0) {\n this.successfulConsecutiveUpdates = 0;\n }\n this.timeSinceUpdate += 1;\n this.age += 1;\n }\n update(detection, frameStep, frameRate) {\n const previous = this.getPreviousObservation();\n if (previous) {\n this.velocity = computeVelocity(previous, detection);\n }\n if (!this.observed && this.frozenState) {\n this.unfreeze(detection, frameStep, frameRate);\n }\n this.estimator.update(detection.rect);\n this.observed = true;\n this.timeSinceUpdate = 0;\n this.successfulConsecutiveUpdates += 1;\n this.lastObservation = detection;\n this.observations.set(this.age, detection);\n const cutoff = this.age - this.deltaT;\n for (const age of this.observations.keys()) {\n if (age < cutoff)\n this.observations.delete(age);\n }\n }\n getRect() {\n return this.estimator.getRect();\n }\n getPreviousObservation() {\n if (this.observations.size === 0)\n return undefined;\n for (let index = 0; index < this.deltaT; index += 1) {\n const delta = this.deltaT - index;\n const observation = this.observations.get(this.age - delta);\n if (observation)\n return observation;\n }\n const latestAge = Math.max(...this.observations.keys());\n return this.observations.get(latestAge);\n }\n configureNoise() {\n const measurementNoise = identity(4);\n for (let index = 2; index < 4; index += 1) {\n measurementNoise[index][index] *= 10;\n }\n const covariance = scaleMatrix(identity(7), 10);\n for (let index = 4; index < 7; index += 1) {\n covariance[index][index] *= 1000;\n }\n const processNoise = identity(7);\n processNoise[6][6] *= 0.01;\n for (let index = 4; index < 7; index += 1) {\n processNoise[index][index] *= 0.01;\n }\n this.estimator.setCovariances({\n covariance,\n measurementNoise,\n processNoise,\n });\n }\n unfreeze(detection, frameStep, frameRate) {\n if (!this.frozenState || this.timeSinceUpdate === 0)\n return;\n this.estimator.restore(this.frozenState);\n const timeGap = this.timeSinceUpdate;\n const start = rectToMeasurement(this.lastObservation.rect, \"xcycsr\");\n const end = rectToMeasurement(detection.rect, \"xcycsr\");\n const startWidth = Math.sqrt(start[2] * start[3]);\n const startHeight = start[3] === 0 ? 0 : Math.sqrt(start[2] / start[3]);\n const endWidth = Math.sqrt(end[2] * end[3]);\n const endHeight = end[3] === 0 ? 0 : Math.sqrt(end[2] / end[3]);\n for (let index = 0; index < timeGap; index += 1) {\n const progress = (index + 1) / timeGap;\n const x = start[0] + progress * (end[0] - start[0]);\n const y = start[1] + progress * (end[1] - start[1]);\n const width = startWidth + progress * (endWidth - startWidth);\n const height = startHeight + progress * (endHeight - startHeight);\n this.estimator.updateMeasurement([x, y, width * height, width / height]);\n if (index < timeGap - 1) {\n this.estimator.predict(frameStep, frameRate);\n }\n }\n this.frozenState = undefined;\n }\n }\n /** Creates the observation-centric SORT implementation from roboflow/trackers. */\n function createOCSortTracker$1(options = {}) {\n const lostTrackBuffer = normalizeNonNegativeInteger$1(options.lostTrackBuffer ?? 30, \"lostTrackBuffer\");\n const frameRate = options.frameRate ?? 30;\n const minimumConsecutiveFrames = normalizePositiveInteger$1(options.minimumConsecutiveFrames ?? 3, \"minimumConsecutiveFrames\");\n const minimumIouThreshold = options.minimumIouThreshold ?? 0.3;\n const directionConsistencyWeight = options.directionConsistencyWeight ?? 0.2;\n const highConfidenceDetectionThreshold = options.highConfidenceDetectionThreshold ?? 0.6;\n const deltaT = normalizePositiveInteger$1(options.deltaT ?? 3, \"deltaT\");\n if (!Number.isFinite(frameRate) || frameRate <= 0) {\n throw new Error(\"frameRate must be a finite positive value.\");\n }\n normalizeUnitInterval$1(minimumIouThreshold, \"minimumIouThreshold\");\n normalizeUnitInterval$1(directionConsistencyWeight, \"directionConsistencyWeight\");\n normalizeUnitInterval$1(highConfidenceDetectionThreshold, \"highConfidenceDetectionThreshold\");\n const scaledLostTrackBuffer = (frameRate / 30) * lostTrackBuffer;\n if (!Number.isFinite(scaledLostTrackBuffer)) {\n throw new Error(\"Scaled lostTrackBuffer overflows: frameRate / 30 * lostTrackBuffer must be finite.\");\n }\n const maximumFramesWithoutUpdate = lostTrackBuffer === 0 ? 0 : Math.max(1, Math.ceil(scaledLostTrackBuffer));\n let tracks = [];\n let frameCount = 0;\n let nextTrackerId = 0;\n let previousFrameIndex;\n return {\n reset() {\n tracks = [];\n frameCount = 0;\n nextTrackerId = 0;\n previousFrameIndex = undefined;\n },\n update(detections, frameIndex) {\n const frameStep = resolveFrameStep(frameIndex, previousFrameIndex);\n previousFrameIndex = frameIndex ?? previousFrameIndex;\n // Match roboflow/trackers: an empty stream before any track exists is\n // not part of OC-SORT's early-sequence activation window.\n if (tracks.length === 0 && detections.length === 0) {\n return {\n activeTrackCount: 0,\n assignments: [],\n confirmedTrackCount: 0,\n };\n }\n tracks.forEach((track) => track.predict(frameStep, frameRate));\n const highDetectionIndexes = detections.flatMap((detection, index) => detection.confidence === undefined ||\n detection.confidence >= highConfidenceDetectionThreshold\n ? [index]\n : []);\n const highDetections = highDetectionIndexes.map((index) => detections[index]);\n const iouScores = pairwiseIou(tracks.map((track) => track.getRect()), highDetections.map((detection) => detection.rect));\n const combinedScores = iouScores.map((row, trackIndex) => row.map((iou, detectionIndex) => {\n if (directionConsistencyWeight === 0)\n return iou;\n return (iou +\n directionConsistencyWeight *\n directionConsistency(tracks[trackIndex], highDetections[detectionIndex]) *\n (highDetections[detectionIndex].confidence ?? 1));\n }));\n const primary = associateTrackingScores(combinedScores, tracks.length, highDetections.length, minimumIouThreshold, iouScores);\n const assignments = new Map();\n for (const match of primary.matches) {\n updateMatchedTrack(tracks[match.trackIndex], highDetections[match.detectionIndex], assignments, frameStep);\n }\n let remainingHigh = [...primary.unmatchedDetectionIndexes];\n if (primary.unmatchedTrackIndexes.length > 0 &&\n remainingHigh.length > 0) {\n const unmatchedTracks = primary.unmatchedTrackIndexes.map((index) => tracks[index]);\n const unmatchedDetections = remainingHigh.map((index) => highDetections[index]);\n const recoveryScores = pairwiseIou(unmatchedTracks.map((track) => track.lastObservation.rect), unmatchedDetections.map((detection) => detection.rect));\n const recovery = associateTrackingScores(recoveryScores, unmatchedTracks.length, unmatchedDetections.length, minimumIouThreshold);\n for (const match of recovery.matches) {\n updateMatchedTrack(unmatchedTracks[match.trackIndex], unmatchedDetections[match.detectionIndex], assignments, frameStep);\n }\n remainingHigh = recovery.unmatchedDetectionIndexes.map((index) => remainingHigh[index]);\n }\n for (const localIndex of remainingHigh) {\n tracks.push(new OCSortTrack(highDetections[localIndex], deltaT));\n }\n tracks = tracks.filter((track) => track.timeSinceUpdate <= maximumFramesWithoutUpdate);\n frameCount += 1;\n const resolvedAssignments = detections.flatMap((detection) => {\n const trackerId = assignments.get(detection.detectionIndex);\n return trackerId === undefined\n ? []\n : [{ detectionIndex: detection.detectionIndex, trackerId }];\n });\n return {\n activeTrackCount: tracks.length,\n assignments: resolvedAssignments,\n confirmedTrackCount: tracks.filter((track) => track.trackerId !== undefined).length,\n };\n },\n };\n function updateMatchedTrack(track, detection, assignments, frameStep) {\n track.update(detection, frameStep, frameRate);\n const earlySequence = frameCount <= minimumConsecutiveFrames;\n const shouldEmit = (earlySequence && track.timeSinceUpdate === 0) ||\n track.successfulConsecutiveUpdates >= minimumConsecutiveFrames;\n if (shouldEmit) {\n if (track.trackerId === undefined) {\n track.trackerId = nextTrackerId++;\n }\n assignments.set(detection.detectionIndex, track.trackerId);\n }\n }\n }\n function computeVelocity(previous, current) {\n const deltaX = current.rect.x - previous.rect.x;\n const deltaY = current.rect.y - previous.rect.y;\n const norm = Math.sqrt(deltaX * deltaX + deltaY * deltaY) + 1e-6;\n return { x: deltaX / norm, y: deltaY / norm };\n }\n function directionConsistency(track, detection) {\n if (!track.velocity)\n return 0;\n const reference = track.getPreviousObservation() ?? track.lastObservation;\n const deltaX = detection.rect.x - reference.rect.x;\n const deltaY = detection.rect.y - reference.rect.y;\n const norm = Math.sqrt(deltaX * deltaX + deltaY * deltaY) + 1e-6;\n const cosine = Math.max(-1, Math.min(1, track.velocity.x * (deltaX / norm) + track.velocity.y * (deltaY / norm)));\n const angle = Math.acos(cosine);\n return (Math.PI / 2 - Math.abs(angle)) / Math.PI;\n }\n\n /** Public core facade for the internal tracker engine workspace. */\n function createSortTracker(options = {}) {\n return createSortTracker$1(options);\n }\n\n /** Public core facade for the internal tracker engine workspace. */\n function createByteTrackTracker(options = {}) {\n return createByteTrackTracker$1(options);\n }\n\n /** Public core facade for the internal tracker engine workspace. */\n function createCBIoUTracker(options = {}) {\n return createCBIoUTracker$1(options);\n }\n\n /** Public core facade for the internal tracker engine workspace. */\n function createOCSortTracker(options = {}) {\n return createOCSortTracker$1(options);\n }\n\n /** Geometry projected into a tracker. The original detection payload is retained. */\n var TrackingGeometry;\n (function (TrackingGeometry) {\n TrackingGeometry[\"Box\"] = \"box\";\n TrackingGeometry[\"Mask\"] = \"mask\";\n TrackingGeometry[\"Keypoints\"] = \"keypoints\";\n })(TrackingGeometry || (TrackingGeometry = {}));\n\n var DetectionMaskPayloadFormat;\n (function (DetectionMaskPayloadFormat) {\n DetectionMaskPayloadFormat[\"RawCocoRle\"] = \"rawCocoRle\";\n DetectionMaskPayloadFormat[\"DeflatedBase64\"] = \"deflatedBase64\";\n })(DetectionMaskPayloadFormat || (DetectionMaskPayloadFormat = {}));\n\n var DetectionPickTarget;\n (function (DetectionPickTarget) {\n DetectionPickTarget[\"Box\"] = \"box\";\n DetectionPickTarget[\"Edge\"] = \"edge\";\n DetectionPickTarget[\"Keypoint\"] = \"keypoint\";\n DetectionPickTarget[\"Label\"] = \"label\";\n DetectionPickTarget[\"Mask\"] = \"mask\";\n DetectionPickTarget[\"Polygon\"] = \"polygon\";\n DetectionPickTarget[\"Polyline\"] = \"polyline\";\n })(DetectionPickTarget || (DetectionPickTarget = {}));\n var MediaInteractionMode;\n (function (MediaInteractionMode) {\n MediaInteractionMode[\"Always\"] = \"always\";\n MediaInteractionMode[\"Disabled\"] = \"disabled\";\n MediaInteractionMode[\"PausedOnly\"] = \"pausedOnly\";\n })(MediaInteractionMode || (MediaInteractionMode = {}));\n\n var AnnotationGeometryKind;\n (function (AnnotationGeometryKind) {\n AnnotationGeometryKind[\"Box\"] = \"box\";\n AnnotationGeometryKind[\"Polygon\"] = \"polygon\";\n AnnotationGeometryKind[\"Polyline\"] = \"polyline\";\n AnnotationGeometryKind[\"Keypoints\"] = \"keypoints\";\n AnnotationGeometryKind[\"Mask\"] = \"mask\";\n })(AnnotationGeometryKind || (AnnotationGeometryKind = {}));\n var AnnotationGestureStateKind;\n (function (AnnotationGestureStateKind) {\n AnnotationGestureStateKind[\"Idle\"] = \"idle\";\n AnnotationGestureStateKind[\"Creating\"] = \"creating\";\n AnnotationGestureStateKind[\"Moving\"] = \"moving\";\n AnnotationGestureStateKind[\"Resizing\"] = \"resizing\";\n AnnotationGestureStateKind[\"DragSelecting\"] = \"dragSelecting\";\n })(AnnotationGestureStateKind || (AnnotationGestureStateKind = {}));\n var AnnotationHandleKind;\n (function (AnnotationHandleKind) {\n AnnotationHandleKind[\"Resize\"] = \"resize\";\n AnnotationHandleKind[\"Vertex\"] = \"vertex\";\n AnnotationHandleKind[\"AddVertex\"] = \"addVertex\";\n AnnotationHandleKind[\"Keypoint\"] = \"keypoint\";\n })(AnnotationHandleKind || (AnnotationHandleKind = {}));\n\n /** Alignment for strokes applied to closed rendered geometry. */\n var StrokeAlignment;\n (function (StrokeAlignment) {\n StrokeAlignment[\"Inside\"] = \"inside\";\n StrokeAlignment[\"Center\"] = \"center\";\n StrokeAlignment[\"Outside\"] = \"outside\";\n })(StrokeAlignment || (StrokeAlignment = {}));\n\n var BoxShape;\n (function (BoxShape) {\n BoxShape[\"Rect\"] = \"rect\";\n BoxShape[\"RoundedRect\"] = \"roundedRect\";\n })(BoxShape || (BoxShape = {}));\n\n var FocusTargetMode;\n (function (FocusTargetMode) {\n FocusTargetMode[\"Hovered\"] = \"hovered\";\n FocusTargetMode[\"Selected\"] = \"selected\";\n FocusTargetMode[\"HoveredAndSelected\"] = \"hoveredAndSelected\";\n FocusTargetMode[\"Ambient\"] = \"ambient\";\n })(FocusTargetMode || (FocusTargetMode = {}));\n\n var DetectionInteractionState;\n (function (DetectionInteractionState) {\n DetectionInteractionState[\"Hovered\"] = \"hovered\";\n DetectionInteractionState[\"Selected\"] = \"selected\";\n })(DetectionInteractionState || (DetectionInteractionState = {}));\n\n var LabelPlacement;\n (function (LabelPlacement) {\n LabelPlacement[\"Top\"] = \"top\";\n LabelPlacement[\"Bottom\"] = \"bottom\";\n LabelPlacement[\"InsideTop\"] = \"insideTop\";\n LabelPlacement[\"InsideBottom\"] = \"insideBottom\";\n LabelPlacement[\"Center\"] = \"center\";\n })(LabelPlacement || (LabelPlacement = {}));\n var LabelVisibilityMode;\n (function (LabelVisibilityMode) {\n LabelVisibilityMode[\"Always\"] = \"always\";\n LabelVisibilityMode[\"HoveredOnly\"] = \"hoveredOnly\";\n })(LabelVisibilityMode || (LabelVisibilityMode = {}));\n\n var MaskRenderMode;\n (function (MaskRenderMode) {\n MaskRenderMode[\"FillAndStroke\"] = \"fillAndStroke\";\n MaskRenderMode[\"FillOnly\"] = \"fillOnly\";\n MaskRenderMode[\"StrokeOnly\"] = \"strokeOnly\";\n })(MaskRenderMode || (MaskRenderMode = {}));\n\n /**\n * Discriminator for renderer-neutral shape draw instructions.\n */\n var ShapeInstructionKind;\n (function (ShapeInstructionKind) {\n ShapeInstructionKind[\"Ellipse\"] = \"ellipse\";\n ShapeInstructionKind[\"Marker\"] = \"marker\";\n ShapeInstructionKind[\"Path\"] = \"path\";\n })(ShapeInstructionKind || (ShapeInstructionKind = {}));\n var MarkerShape;\n (function (MarkerShape) {\n MarkerShape[\"Circle\"] = \"circle\";\n MarkerShape[\"Cross\"] = \"cross\";\n MarkerShape[\"Square\"] = \"square\";\n MarkerShape[\"Triangle\"] = \"triangle\";\n })(MarkerShape || (MarkerShape = {}));\n /**\n * Coordinate space for marker sizing. Media sizes scale with the viewport;\n * screen sizes stay constant on screen, matching stroke-width semantics.\n */\n var MarkerSizeSpace;\n (function (MarkerSizeSpace) {\n MarkerSizeSpace[\"Media\"] = \"media\";\n MarkerSizeSpace[\"Screen\"] = \"screen\";\n })(MarkerSizeSpace || (MarkerSizeSpace = {}));\n\n var KeypointMarkerShape;\n (function (KeypointMarkerShape) {\n KeypointMarkerShape[\"Circle\"] = \"circle\";\n KeypointMarkerShape[\"Cross\"] = \"cross\";\n })(KeypointMarkerShape || (KeypointMarkerShape = {}));\n\n var MediaRendererFit;\n (function (MediaRendererFit) {\n /**\n * Preserve media aspect ratio and fit the full frame inside the canvas.\n */\n MediaRendererFit[\"Contain\"] = \"contain\";\n /**\n * Preserve media aspect ratio and fill the canvas, cropping if necessary.\n */\n MediaRendererFit[\"Cover\"] = \"cover\";\n })(MediaRendererFit || (MediaRendererFit = {}));\n /**\n * Playback lifecycle state reported by a platform renderer.\n */\n var MediaRendererPlaybackState;\n (function (MediaRendererPlaybackState) {\n MediaRendererPlaybackState[\"Loading\"] = \"loading\";\n MediaRendererPlaybackState[\"Ready\"] = \"ready\";\n MediaRendererPlaybackState[\"Playing\"] = \"playing\";\n MediaRendererPlaybackState[\"Buffering\"] = \"buffering\";\n MediaRendererPlaybackState[\"Paused\"] = \"paused\";\n MediaRendererPlaybackState[\"Error\"] = \"error\";\n MediaRendererPlaybackState[\"Destroyed\"] = \"destroyed\";\n })(MediaRendererPlaybackState || (MediaRendererPlaybackState = {}));\n /**\n * Lower-level media source readiness.\n */\n var MediaSourceStatus;\n (function (MediaSourceStatus) {\n MediaSourceStatus[\"Loading\"] = \"loading\";\n MediaSourceStatus[\"Ready\"] = \"ready\";\n MediaSourceStatus[\"Error\"] = \"error\";\n MediaSourceStatus[\"Destroyed\"] = \"destroyed\";\n })(MediaSourceStatus || (MediaSourceStatus = {}));\n\n /**\n * Media-session operating mode.\n *\n * Core owns the names because file-like and stream-like lifecycle choices are\n * platform-neutral. Platform packages decide how these modes tune media,\n * storage, and renderer defaults.\n */\n var MediaSessionMode;\n (function (MediaSessionMode) {\n /**\n * Finite media. Defaults usually favor seek/replay and persistent detection\n * storage.\n */\n MediaSessionMode[\"File\"] = \"file\";\n /**\n * Live or append-only media. Defaults usually favor rolling windows and\n * bounded retention.\n */\n MediaSessionMode[\"Stream\"] = \"stream\";\n })(MediaSessionMode || (MediaSessionMode = {}));\n /**\n * Aggregate lifecycle state for a media session.\n */\n var MediaSessionStatus;\n (function (MediaSessionStatus) {\n MediaSessionStatus[\"Buffering\"] = \"buffering\";\n MediaSessionStatus[\"Destroyed\"] = \"destroyed\";\n MediaSessionStatus[\"Error\"] = \"error\";\n MediaSessionStatus[\"Loading\"] = \"loading\";\n MediaSessionStatus[\"Paused\"] = \"paused\";\n MediaSessionStatus[\"Playing\"] = \"playing\";\n MediaSessionStatus[\"Processing\"] = \"processing\";\n MediaSessionStatus[\"Ready\"] = \"ready\";\n })(MediaSessionStatus || (MediaSessionStatus = {}));\n /**\n * Subsystem currently affecting session readiness or presentation.\n */\n var MediaSessionActivityKind;\n (function (MediaSessionActivityKind) {\n MediaSessionActivityKind[\"DetectionsBuffering\"] = \"detectionsBuffering\";\n MediaSessionActivityKind[\"DetectionsLoading\"] = \"detectionsLoading\";\n MediaSessionActivityKind[\"Error\"] = \"error\";\n MediaSessionActivityKind[\"MediaNormalizing\"] = \"mediaNormalizing\";\n MediaSessionActivityKind[\"MediaOpening\"] = \"mediaOpening\";\n MediaSessionActivityKind[\"PlaybackBuffering\"] = \"playbackBuffering\";\n MediaSessionActivityKind[\"RenderPreparing\"] = \"renderPreparing\";\n })(MediaSessionActivityKind || (MediaSessionActivityKind = {}));\n /**\n * State of one session activity.\n */\n var MediaSessionActivityStatus;\n (function (MediaSessionActivityStatus) {\n MediaSessionActivityStatus[\"Error\"] = \"error\";\n MediaSessionActivityStatus[\"Running\"] = \"running\";\n MediaSessionActivityStatus[\"Waiting\"] = \"waiting\";\n })(MediaSessionActivityStatus || (MediaSessionActivityStatus = {}));\n\n let tracker;\n self.addEventListener(\"message\", (event) => {\n const request = event.data;\n try {\n let response;\n if (request.type === \"configure\") {\n switch (request.processor.algorithm) {\n case \"bytetrack\":\n tracker = createByteTrackTracker(request.processor.options);\n break;\n case \"cbiou\":\n tracker = createCBIoUTracker(request.processor.options);\n break;\n case \"ocsort\":\n tracker = createOCSortTracker(request.processor.options);\n break;\n default:\n tracker = createSortTracker(request.processor.options);\n }\n response = { requestId: request.requestId, type: \"success\" };\n }\n else if (request.type === \"reset\") {\n tracker?.reset();\n response = { requestId: request.requestId, type: \"success\" };\n }\n else {\n if (!tracker) {\n throw new Error(\"Tracking worker is not configured.\");\n }\n const startedAt = performance.now();\n const update = tracker.update(request.detections, request.frameIndex);\n response = {\n ...update,\n durationMs: performance.now() - startedAt,\n requestId: request.requestId,\n type: \"success\",\n };\n }\n self.postMessage(response);\n }\n catch (error) {\n self.postMessage({\n message: error instanceof Error ? error.message : \"Tracking worker failed.\",\n requestId: request.requestId,\n type: \"error\",\n });\n }\n });\n\n})();";
462
+
463
+ const DEFAULT_WORKER_NAME$1 = "supervision-detection-post-processing";
464
+ let defaultWorkerUrl$1;
465
+ function createDefaultDetectionPostProcessingWorkerFactory() {
466
+ return {
467
+ createWorker() {
468
+ defaultWorkerUrl$1 ??= URL.createObjectURL(new Blob([EMBEDDED_TRACKING_WORKER_SOURCE], {
469
+ type: "text/javascript",
470
+ }));
471
+ return new Worker(defaultWorkerUrl$1, { name: DEFAULT_WORKER_NAME$1 });
472
+ },
473
+ };
474
+ }
475
+
476
+ function isTrackingWorkerResponse(value) {
477
+ if (!value || typeof value !== "object")
478
+ return false;
479
+ const candidate = value;
480
+ return (typeof candidate.requestId === "number" &&
481
+ (candidate.type === "success" ||
482
+ (candidate.type === "error" && typeof candidate.message === "string")));
483
+ }
484
+
485
+ var DetectionPostProcessingMode;
486
+ (function (DetectionPostProcessingMode) {
487
+ DetectionPostProcessingMode["Auto"] = "auto";
488
+ DetectionPostProcessingMode["Worker"] = "worker";
489
+ DetectionPostProcessingMode["MainThread"] = "mainThread";
490
+ })(DetectionPostProcessingMode || (DetectionPostProcessingMode = {}));
491
+
492
+ function createWorkerRpcClient(options) {
493
+ let failureMessage = null;
494
+ let isDestroyed = false;
495
+ let nextRequestId = 1;
496
+ const pendingRequests = new Map();
497
+ options.worker.addEventListener("message", (event) => {
498
+ handleWorkerMessage(event.data);
499
+ });
500
+ options.worker.addEventListener("error", (event) => {
501
+ rejectPendingRequests(event.message || options.defaultErrorMessage);
502
+ });
503
+ options.worker.addEventListener("messageerror", () => {
504
+ rejectPendingRequests(`${options.defaultErrorMessage}: message error.`);
505
+ });
506
+ return {
507
+ destroy() {
508
+ if (isDestroyed) {
509
+ return;
510
+ }
511
+ isDestroyed = true;
512
+ rejectPendingRequests("Worker RPC client has been destroyed.", {
513
+ markFailure: false,
514
+ });
515
+ options.worker.terminate();
516
+ },
517
+ getFailureMessage() {
518
+ return failureMessage;
519
+ },
520
+ request(message) {
521
+ if (isDestroyed) {
522
+ return Promise.reject(new Error("Worker RPC client has been destroyed."));
523
+ }
524
+ if (failureMessage) {
525
+ return Promise.reject(new Error(failureMessage));
526
+ }
527
+ const request = {
528
+ ...message,
529
+ requestId: nextRequestId,
530
+ };
531
+ nextRequestId += 1;
532
+ return new Promise((resolve, reject) => {
533
+ pendingRequests.set(request.requestId, { reject, resolve });
534
+ try {
535
+ options.worker.postMessage(request);
536
+ }
537
+ catch (error) {
538
+ pendingRequests.delete(request.requestId);
539
+ failureMessage = getErrorMessage$2(error, options.defaultErrorMessage);
540
+ reject(new Error(failureMessage));
541
+ }
542
+ });
543
+ },
544
+ };
545
+ function handleWorkerMessage(message) {
546
+ if (!options.isResponse(message)) {
547
+ return;
548
+ }
549
+ const pendingRequest = pendingRequests.get(message.requestId);
550
+ if (!pendingRequest) {
551
+ options.onOrphanedResponse?.(message);
552
+ return;
553
+ }
554
+ pendingRequests.delete(message.requestId);
555
+ pendingRequest.resolve(message);
556
+ }
557
+ function rejectPendingRequests(message, options = { markFailure: true }) {
558
+ if (options.markFailure) {
559
+ failureMessage = message;
560
+ }
561
+ for (const pendingRequest of pendingRequests.values()) {
562
+ pendingRequest.reject(new Error(message));
563
+ }
564
+ pendingRequests.clear();
565
+ }
566
+ }
567
+ function getErrorMessage$2(error, fallback) {
568
+ return error instanceof Error ? error.message : fallback;
569
+ }
570
+
571
+ const DEFAULT_MAX_PENDING_FRAMES = 90;
572
+ /**
573
+ * Creates an ordered, bounded stream processor for detections arriving out of
574
+ * order. Stateful processors run serially; the renderer remains independent.
575
+ */
576
+ function createDetectionPostProcessingPipeline(options) {
577
+ const processor = validateProcessors(options.processors);
578
+ const maxPendingFrames = normalizePositiveInteger(options.maxPendingFrames ?? DEFAULT_MAX_PENDING_FRAMES, "maxPendingFrames");
579
+ let nextFrameIndex = normalizeFrameIndex(options.startFrameIndex ?? 0, "startFrameIndex");
580
+ let execution;
581
+ let destroyed = false;
582
+ let failedError;
583
+ let inFlightFrameIndex;
584
+ let processing = Promise.resolve({
585
+ acceptedFrameCount: 0,
586
+ processedFrameCount: 0,
587
+ processedFrames: [],
588
+ });
589
+ const pendingFrames = new Map();
590
+ let diagnostics = {
591
+ activeTrackCount: 0,
592
+ confirmedTrackCount: 0,
593
+ errorMessage: null,
594
+ executionMode: null,
595
+ lastFrameDurationMs: null,
596
+ nextFrameIndex,
597
+ pendingFrameCount: 0,
598
+ processedFrameCount: 0,
599
+ trackedDetectionCount: 0,
600
+ };
601
+ publishDiagnostics();
602
+ return {
603
+ async appendFrames(frames) {
604
+ assertActive();
605
+ assertHealthy();
606
+ const acceptedFrameCount = enqueueFrames(frames);
607
+ processing = processing.then(() => drainPendingFrames(acceptedFrameCount));
608
+ return processing;
609
+ },
610
+ destroy() {
611
+ if (destroyed)
612
+ return;
613
+ destroyed = true;
614
+ pendingFrames.clear();
615
+ execution?.destroy();
616
+ execution = undefined;
617
+ },
618
+ getDiagnostics() {
619
+ return { ...diagnostics };
620
+ },
621
+ async reset(resetOptions = {}) {
622
+ assertActive();
623
+ await processing.catch(() => undefined);
624
+ pendingFrames.clear();
625
+ inFlightFrameIndex = undefined;
626
+ nextFrameIndex = normalizeFrameIndex(resetOptions.startFrameIndex ?? options.startFrameIndex ?? 0, "startFrameIndex");
627
+ await execution?.reset();
628
+ failedError = undefined;
629
+ processing = Promise.resolve({
630
+ acceptedFrameCount: 0,
631
+ processedFrameCount: 0,
632
+ processedFrames: [],
633
+ });
634
+ diagnostics = {
635
+ ...diagnostics,
636
+ activeTrackCount: 0,
637
+ confirmedTrackCount: 0,
638
+ errorMessage: null,
639
+ lastFrameDurationMs: null,
640
+ nextFrameIndex,
641
+ pendingFrameCount: 0,
642
+ processedFrameCount: 0,
643
+ trackedDetectionCount: 0,
644
+ };
645
+ publishDiagnostics();
646
+ },
647
+ };
648
+ function enqueueFrames(frames) {
649
+ let acceptedFrameCount = 0;
650
+ const additions = new Map();
651
+ for (const frame of frames) {
652
+ const frameIndex = normalizeFrameIndex(frame.frameIndex, "frameIndex");
653
+ if (frameIndex < nextFrameIndex) {
654
+ throw new Error(`Frame ${frameIndex} is behind the processed frontier ${nextFrameIndex}. Reset before revising causal history.`);
655
+ }
656
+ if (frameIndex === inFlightFrameIndex) {
657
+ throw new Error(`Frame ${frameIndex} is already being processed. Reset before revising causal history.`);
658
+ }
659
+ if (!pendingFrames.has(frameIndex) && !additions.has(frameIndex)) {
660
+ acceptedFrameCount += 1;
661
+ }
662
+ additions.set(frameIndex, frame);
663
+ }
664
+ const nextPendingCount = pendingFrames.size + acceptedFrameCount;
665
+ if (nextPendingCount > maxPendingFrames) {
666
+ throw new Error(`Out-of-order buffer limit exceeded (${nextPendingCount}/${maxPendingFrames}). Apply upstream backpressure or increase maxPendingFrames.`);
667
+ }
668
+ for (const [frameIndex, frame] of additions) {
669
+ pendingFrames.set(frameIndex, frame);
670
+ }
671
+ diagnostics = {
672
+ ...diagnostics,
673
+ nextFrameIndex,
674
+ pendingFrameCount: pendingFrames.size,
675
+ };
676
+ publishDiagnostics();
677
+ return acceptedFrameCount;
678
+ }
679
+ async function drainPendingFrames(acceptedFrameCount) {
680
+ const processedFrames = [];
681
+ try {
682
+ execution ??= await createTrackingExecution(processor, options);
683
+ diagnostics = { ...diagnostics, executionMode: execution.mode };
684
+ while (!destroyed) {
685
+ const frame = pendingFrames.get(nextFrameIndex);
686
+ if (!frame)
687
+ break;
688
+ pendingFrames.delete(nextFrameIndex);
689
+ inFlightFrameIndex = nextFrameIndex;
690
+ const projections = projectDetectionFrameForTracking(frame, processor.geometry);
691
+ const result = await execution.process(projections, nextFrameIndex);
692
+ const processedFrame = attachTrackerIds(frame, result.assignments, options.mutateInput ?? true);
693
+ if (destroyed)
694
+ break;
695
+ await options.output?.appendFrames([processedFrame]);
696
+ options.onFrame?.(processedFrame);
697
+ processedFrames.push(processedFrame);
698
+ nextFrameIndex += 1;
699
+ inFlightFrameIndex = undefined;
700
+ diagnostics = {
701
+ ...diagnostics,
702
+ activeTrackCount: result.activeTrackCount,
703
+ confirmedTrackCount: result.confirmedTrackCount,
704
+ errorMessage: null,
705
+ lastFrameDurationMs: result.durationMs,
706
+ nextFrameIndex,
707
+ pendingFrameCount: pendingFrames.size,
708
+ processedFrameCount: diagnostics.processedFrameCount + 1,
709
+ trackedDetectionCount: diagnostics.trackedDetectionCount + result.assignments.length,
710
+ };
711
+ publishDiagnostics();
712
+ }
713
+ return {
714
+ acceptedFrameCount,
715
+ processedFrameCount: processedFrames.length,
716
+ processedFrames,
717
+ };
718
+ }
719
+ catch (error) {
720
+ failedError =
721
+ error instanceof Error ? error : new Error("Post-processing failed.");
722
+ diagnostics = {
723
+ ...diagnostics,
724
+ errorMessage: failedError.message,
725
+ pendingFrameCount: pendingFrames.size,
726
+ };
727
+ publishDiagnostics();
728
+ throw failedError;
729
+ }
730
+ }
731
+ function publishDiagnostics() {
732
+ options.onDiagnostics?.({ ...diagnostics });
733
+ }
734
+ function assertActive() {
735
+ if (destroyed) {
736
+ throw new Error("Detection post-processing pipeline has been destroyed.");
737
+ }
738
+ }
739
+ function assertHealthy() {
740
+ if (failedError) {
741
+ throw new Error(`Detection post-processing pipeline failed and must be reset: ${failedError.message}`);
742
+ }
743
+ }
744
+ }
745
+ async function createTrackingExecution(processor, options) {
746
+ const mode = options.mode ?? DetectionPostProcessingMode.Auto;
747
+ if (mode === DetectionPostProcessingMode.MainThread) {
748
+ return createMainThreadExecution(processor);
749
+ }
750
+ let workerExecution;
751
+ try {
752
+ const workerFactory = options.workerFactory ??
753
+ createDefaultDetectionPostProcessingWorkerFactory();
754
+ workerExecution = createWorkerExecution(workerFactory.createWorker(), processor);
755
+ await workerExecution.reset();
756
+ return workerExecution;
757
+ }
758
+ catch (error) {
759
+ workerExecution?.destroy();
760
+ if (mode === DetectionPostProcessingMode.Worker)
761
+ throw error;
762
+ return createMainThreadExecution(processor);
763
+ }
764
+ }
765
+ function createMainThreadExecution(processor) {
766
+ let tracker;
767
+ switch (processor.algorithm) {
768
+ case "bytetrack":
769
+ tracker = createByteTrackTracker(processor.options);
770
+ break;
771
+ case "cbiou":
772
+ tracker = createCBIoUTracker(processor.options);
773
+ break;
774
+ case "ocsort":
775
+ tracker = createOCSortTracker(processor.options);
776
+ break;
777
+ default:
778
+ tracker = createSortTracker(processor.options);
779
+ }
780
+ return {
781
+ destroy() { },
782
+ mode: "mainThread",
783
+ async process(detections, frameIndex) {
784
+ const startedAt = performance.now();
785
+ const update = tracker.update(detections, frameIndex);
786
+ return { ...update, durationMs: performance.now() - startedAt };
787
+ },
788
+ async reset() {
789
+ tracker.reset();
790
+ },
791
+ };
792
+ }
793
+ function createWorkerExecution(worker, processor) {
794
+ const client = createWorkerRpcClient({
795
+ defaultErrorMessage: "Detection post-processing worker failed.",
796
+ isResponse: isTrackingWorkerResponse,
797
+ worker,
798
+ });
799
+ let configured = false;
800
+ const request = async (message) => {
801
+ const response = await client.request(message);
802
+ if (response.type === "error")
803
+ throw new Error(response.message);
804
+ return response;
805
+ };
806
+ return {
807
+ destroy() {
808
+ client.destroy();
809
+ },
810
+ mode: "worker",
811
+ async process(detections, frameIndex) {
812
+ if (!configured) {
813
+ await request({ processor, type: "configure" });
814
+ configured = true;
815
+ }
816
+ const response = await request({
817
+ detections,
818
+ frameIndex,
819
+ type: "process",
820
+ });
821
+ return {
822
+ activeTrackCount: response.activeTrackCount ?? 0,
823
+ assignments: response.assignments ?? [],
824
+ confirmedTrackCount: response.confirmedTrackCount ?? 0,
825
+ durationMs: response.durationMs ?? 0,
826
+ };
827
+ },
828
+ async reset() {
829
+ if (!configured) {
830
+ await request({ processor, type: "configure" });
831
+ configured = true;
832
+ }
833
+ else {
834
+ await request({ type: "reset" });
835
+ }
836
+ },
837
+ };
838
+ }
839
+ function attachTrackerIds(frame, assignments, mutateInput) {
840
+ const trackerIds = new Map(assignments.map(({ detectionIndex, trackerId }) => [
841
+ detectionIndex,
842
+ trackerId,
843
+ ]));
844
+ for (const [detectionIndex, detection] of frame.detections.entries()) {
845
+ if (mutateInput) {
846
+ const trackerId = trackerIds.get(detectionIndex);
847
+ if (trackerId === undefined) {
848
+ Reflect.deleteProperty(detection, "trackerId");
849
+ }
850
+ else {
851
+ detection.trackerId = trackerId;
852
+ }
853
+ }
854
+ }
855
+ if (mutateInput) {
856
+ return frame;
857
+ }
858
+ return {
859
+ ...frame,
860
+ detections: frame.detections.map((detection, detectionIndex) => {
861
+ const semanticDetection = { ...detection };
862
+ Reflect.deleteProperty(semanticDetection, "trackerId");
863
+ const trackerId = trackerIds.get(detectionIndex);
864
+ return trackerId === undefined
865
+ ? semanticDetection
866
+ : { ...semanticDetection, trackerId };
867
+ }),
868
+ };
869
+ }
870
+ function validateProcessors(processors) {
871
+ if (processors.length !== 1 || processors[0]?.kind !== "tracking") {
872
+ throw new Error("The first post-processing release requires exactly one tracking processor.");
873
+ }
874
+ return processors[0];
875
+ }
876
+ function normalizePositiveInteger(value, label) {
877
+ if (!Number.isInteger(value) || value < 1) {
878
+ throw new Error(`${label} must be a positive integer.`);
879
+ }
880
+ return value;
881
+ }
882
+ function normalizeFrameIndex(value, label) {
883
+ if (!Number.isInteger(value) || value === undefined || value < 0) {
884
+ throw new Error(`${label} must be a non-negative integer.`);
885
+ }
886
+ return value;
887
+ }
888
+
461
889
  async function collectInputMetadata(input, source) {
462
890
  const [format, detectedMimeType, duration, primaryVideoTrack] = await Promise.all([
463
891
  input.getFormat(),
@@ -5473,7 +5901,7 @@ void main(void) {
5473
5901
  }
5474
5902
  `;
5475
5903
 
5476
- const EMBEDDED_MASK_PREPARATION_WORKER_SOURCE = "(function () {\n 'use strict';\n\n /** COCO-compatible keypoint visibility values. */\n var KeypointVisibility;\n (function (KeypointVisibility) {\n KeypointVisibility[KeypointVisibility[\"NotLabeled\"] = 0] = \"NotLabeled\";\n KeypointVisibility[KeypointVisibility[\"Occluded\"] = 1] = \"Occluded\";\n KeypointVisibility[KeypointVisibility[\"Visible\"] = 2] = \"Visible\";\n })(KeypointVisibility || (KeypointVisibility = {}));\n var DetectionMaskEncoding;\n (function (DetectionMaskEncoding) {\n DetectionMaskEncoding[\"CompressedRle\"] = \"compressedRle\";\n })(DetectionMaskEncoding || (DetectionMaskEncoding = {}));\n\n var DetectionBufferStatus;\n (function (DetectionBufferStatus) {\n DetectionBufferStatus[\"Idle\"] = \"idle\";\n DetectionBufferStatus[\"Loading\"] = \"loading\";\n DetectionBufferStatus[\"Ready\"] = \"ready\";\n DetectionBufferStatus[\"Error\"] = \"error\";\n DetectionBufferStatus[\"Destroyed\"] = \"destroyed\";\n })(DetectionBufferStatus || (DetectionBufferStatus = {}));\n /**\n * How the renderer selects the active detection frame for a media timestamp.\n */\n var DetectionFrameSelectionMode;\n (function (DetectionFrameSelectionMode) {\n /**\n * Select the frame whose `[mediaTime, endTime)` interval contains the media\n * time. This is the default for interval annotations and timestamped sources.\n */\n DetectionFrameSelectionMode[\"Interval\"] = \"interval\";\n /**\n * Select from a known inference frame grid using `frameIndex`, `frameRate`,\n * and optional `frameIndexOriginTime`. This is useful when inference was run\n * on normalized frames and playback should snap detections to that grid.\n */\n DetectionFrameSelectionMode[\"NearestFrameIndex\"] = \"nearestFrameIndex\";\n })(DetectionFrameSelectionMode || (DetectionFrameSelectionMode = {}));\n var DetectionFrameRetentionMode;\n (function (DetectionFrameRetentionMode) {\n /**\n * Keep writable detections only in an in-memory store. Useful for ephemeral\n * live streams where old predictions should disappear when evicted.\n */\n DetectionFrameRetentionMode[\"MemoryOnly\"] = \"memoryOnly\";\n /**\n * Persist every written detection frame. Useful for finite media where seek\n * and replay should not require recomputing detections.\n */\n DetectionFrameRetentionMode[\"PersistAll\"] = \"persistAll\";\n /**\n * Persist only the most recent retention window. Useful for long-running\n * streams where replay is bounded to a recent time horizon.\n */\n DetectionFrameRetentionMode[\"PersistWindow\"] = \"persistWindow\";\n })(DetectionFrameRetentionMode || (DetectionFrameRetentionMode = {}));\n function decodeCompressedRleMask(mask) {\n if (mask.encoding !== DetectionMaskEncoding.CompressedRle) {\n throw new Error(`Unsupported detection mask encoding: ${mask.encoding}`);\n }\n const data = new Uint8Array(mask.width * mask.height);\n const counts = decodeCompressedRleCounts(mask.counts);\n let offset = 0;\n for (let index = 0; index < counts.length; index += 1) {\n const runLength = counts[index] ?? 0;\n const isForeground = index % 2 === 1;\n if (isForeground) {\n for (let runOffset = 0; runOffset < runLength; runOffset += 1) {\n const maskOffset = offset + runOffset;\n const x = Math.floor(maskOffset / mask.height);\n const y = maskOffset % mask.height;\n const rowMajorOffset = y * mask.width + x;\n if (rowMajorOffset < data.length) {\n data[rowMajorOffset] = 1;\n }\n }\n }\n offset += runLength;\n }\n return {\n data,\n height: mask.height,\n width: mask.width,\n };\n }\n function decodeCompressedRleCounts(counts) {\n const decoded = [];\n let index = 0;\n while (index < counts.length) {\n let value = 0;\n let shift = 0;\n let charCode;\n do {\n charCode = counts.charCodeAt(index) - 48;\n index += 1;\n value |= (charCode & 0x1f) << shift;\n shift += 5;\n } while (charCode & 0x20);\n if (charCode & 0x10) {\n value |= -1 << shift;\n }\n if (decoded.length > 2) {\n value += decoded[decoded.length - 2] ?? 0;\n }\n decoded.push(value);\n }\n return decoded;\n }\n function encodeCompressedRleCounts(counts) {\n return counts\n .map((count, index) => {\n let value = index > 2 ? count - counts[index - 2] : count;\n let encoded = \"\";\n let more = true;\n while (more) {\n let charCode = value & 0x1f;\n value >>= 5;\n more = !((value === 0 && (charCode & 0x10) === 0) ||\n (value === -1 && (charCode & 0x10) !== 0));\n if (more) {\n charCode |= 0x20;\n }\n encoded += String.fromCharCode(charCode + 48);\n }\n return encoded;\n })\n .join(\"\");\n }\n\n var AnnotationFrameMutationKind;\n (function (AnnotationFrameMutationKind) {\n AnnotationFrameMutationKind[\"Add\"] = \"add\";\n AnnotationFrameMutationKind[\"Remove\"] = \"remove\";\n AnnotationFrameMutationKind[\"Replace\"] = \"replace\";\n AnnotationFrameMutationKind[\"Transact\"] = \"transact\";\n AnnotationFrameMutationKind[\"Update\"] = \"update\";\n })(AnnotationFrameMutationKind || (AnnotationFrameMutationKind = {}));\n\n var DetectionPickTarget;\n (function (DetectionPickTarget) {\n DetectionPickTarget[\"Box\"] = \"box\";\n DetectionPickTarget[\"Edge\"] = \"edge\";\n DetectionPickTarget[\"Keypoint\"] = \"keypoint\";\n DetectionPickTarget[\"Label\"] = \"label\";\n DetectionPickTarget[\"Mask\"] = \"mask\";\n DetectionPickTarget[\"Polygon\"] = \"polygon\";\n DetectionPickTarget[\"Polyline\"] = \"polyline\";\n })(DetectionPickTarget || (DetectionPickTarget = {}));\n var MediaInteractionMode;\n (function (MediaInteractionMode) {\n MediaInteractionMode[\"Always\"] = \"always\";\n MediaInteractionMode[\"Disabled\"] = \"disabled\";\n MediaInteractionMode[\"PausedOnly\"] = \"pausedOnly\";\n })(MediaInteractionMode || (MediaInteractionMode = {}));\n\n function centerRectToTopLeftRect(rect) {\n return {\n height: rect.height,\n width: rect.width,\n x: rect.x - rect.width / 2,\n y: rect.y - rect.height / 2,\n };\n }\n function getPointsRect(points) {\n if (points.length === 0) {\n return undefined;\n }\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n for (const point of points) {\n minX = Math.min(minX, point.x);\n minY = Math.min(minY, point.y);\n maxX = Math.max(maxX, point.x);\n maxY = Math.max(maxY, point.y);\n }\n return {\n height: maxY - minY,\n width: maxX - minX,\n x: (minX + maxX) / 2,\n y: (minY + maxY) / 2,\n };\n }\n\n var AnnotationGeometryKind;\n (function (AnnotationGeometryKind) {\n AnnotationGeometryKind[\"Box\"] = \"box\";\n AnnotationGeometryKind[\"Polygon\"] = \"polygon\";\n AnnotationGeometryKind[\"Polyline\"] = \"polyline\";\n AnnotationGeometryKind[\"Keypoints\"] = \"keypoints\";\n AnnotationGeometryKind[\"Mask\"] = \"mask\";\n })(AnnotationGeometryKind || (AnnotationGeometryKind = {}));\n var AnnotationGestureStateKind;\n (function (AnnotationGestureStateKind) {\n AnnotationGestureStateKind[\"Idle\"] = \"idle\";\n AnnotationGestureStateKind[\"Creating\"] = \"creating\";\n AnnotationGestureStateKind[\"Moving\"] = \"moving\";\n AnnotationGestureStateKind[\"Resizing\"] = \"resizing\";\n AnnotationGestureStateKind[\"DragSelecting\"] = \"dragSelecting\";\n })(AnnotationGestureStateKind || (AnnotationGestureStateKind = {}));\n var AnnotationHandleKind;\n (function (AnnotationHandleKind) {\n AnnotationHandleKind[\"Resize\"] = \"resize\";\n AnnotationHandleKind[\"Vertex\"] = \"vertex\";\n AnnotationHandleKind[\"AddVertex\"] = \"addVertex\";\n AnnotationHandleKind[\"Keypoint\"] = \"keypoint\";\n })(AnnotationHandleKind || (AnnotationHandleKind = {}));\n\n /** Alignment for strokes applied to closed rendered geometry. */\n var StrokeAlignment;\n (function (StrokeAlignment) {\n StrokeAlignment[\"Inside\"] = \"inside\";\n StrokeAlignment[\"Center\"] = \"center\";\n StrokeAlignment[\"Outside\"] = \"outside\";\n })(StrokeAlignment || (StrokeAlignment = {}));\n\n var BoxShape;\n (function (BoxShape) {\n BoxShape[\"Rect\"] = \"rect\";\n BoxShape[\"RoundedRect\"] = \"roundedRect\";\n })(BoxShape || (BoxShape = {}));\n\n var FocusTargetMode;\n (function (FocusTargetMode) {\n FocusTargetMode[\"Hovered\"] = \"hovered\";\n FocusTargetMode[\"Selected\"] = \"selected\";\n FocusTargetMode[\"HoveredAndSelected\"] = \"hoveredAndSelected\";\n FocusTargetMode[\"Ambient\"] = \"ambient\";\n })(FocusTargetMode || (FocusTargetMode = {}));\n\n var DetectionInteractionState;\n (function (DetectionInteractionState) {\n DetectionInteractionState[\"Hovered\"] = \"hovered\";\n DetectionInteractionState[\"Selected\"] = \"selected\";\n })(DetectionInteractionState || (DetectionInteractionState = {}));\n\n var LabelPlacement;\n (function (LabelPlacement) {\n LabelPlacement[\"Top\"] = \"top\";\n LabelPlacement[\"Bottom\"] = \"bottom\";\n LabelPlacement[\"InsideTop\"] = \"insideTop\";\n LabelPlacement[\"InsideBottom\"] = \"insideBottom\";\n LabelPlacement[\"Center\"] = \"center\";\n })(LabelPlacement || (LabelPlacement = {}));\n var LabelVisibilityMode;\n (function (LabelVisibilityMode) {\n LabelVisibilityMode[\"Always\"] = \"always\";\n LabelVisibilityMode[\"HoveredOnly\"] = \"hoveredOnly\";\n })(LabelVisibilityMode || (LabelVisibilityMode = {}));\n\n var MaskRenderMode;\n (function (MaskRenderMode) {\n MaskRenderMode[\"FillAndStroke\"] = \"fillAndStroke\";\n MaskRenderMode[\"FillOnly\"] = \"fillOnly\";\n MaskRenderMode[\"StrokeOnly\"] = \"strokeOnly\";\n })(MaskRenderMode || (MaskRenderMode = {}));\n\n /**\n * Discriminator for renderer-neutral shape draw instructions.\n */\n var ShapeInstructionKind;\n (function (ShapeInstructionKind) {\n ShapeInstructionKind[\"Ellipse\"] = \"ellipse\";\n ShapeInstructionKind[\"Marker\"] = \"marker\";\n ShapeInstructionKind[\"Path\"] = \"path\";\n })(ShapeInstructionKind || (ShapeInstructionKind = {}));\n var MarkerShape;\n (function (MarkerShape) {\n MarkerShape[\"Circle\"] = \"circle\";\n MarkerShape[\"Cross\"] = \"cross\";\n MarkerShape[\"Square\"] = \"square\";\n MarkerShape[\"Triangle\"] = \"triangle\";\n })(MarkerShape || (MarkerShape = {}));\n /**\n * Coordinate space for marker sizing. Media sizes scale with the viewport;\n * screen sizes stay constant on screen, matching stroke-width semantics.\n */\n var MarkerSizeSpace;\n (function (MarkerSizeSpace) {\n MarkerSizeSpace[\"Media\"] = \"media\";\n MarkerSizeSpace[\"Screen\"] = \"screen\";\n })(MarkerSizeSpace || (MarkerSizeSpace = {}));\n\n var KeypointMarkerShape;\n (function (KeypointMarkerShape) {\n KeypointMarkerShape[\"Circle\"] = \"circle\";\n KeypointMarkerShape[\"Cross\"] = \"cross\";\n })(KeypointMarkerShape || (KeypointMarkerShape = {}));\n\n var DetectionMaskPayloadFormat;\n (function (DetectionMaskPayloadFormat) {\n DetectionMaskPayloadFormat[\"RawCocoRle\"] = \"rawCocoRle\";\n DetectionMaskPayloadFormat[\"DeflatedBase64\"] = \"deflatedBase64\";\n })(DetectionMaskPayloadFormat || (DetectionMaskPayloadFormat = {}));\n function encodeBinaryMask(data, width, height) {\n assertMaskDimensions(data, width, height);\n const runs = [];\n let currentValue = 0;\n let runLength = 0;\n for (let x = 0; x < width; x += 1) {\n for (let y = 0; y < height; y += 1) {\n const value = data[y * width + x] ? 1 : 0;\n if (value === currentValue) {\n runLength += 1;\n }\n else {\n runs.push(runLength);\n currentValue = value;\n runLength = 1;\n }\n }\n }\n runs.push(runLength);\n return {\n counts: encodeCompressedRleCounts(runs),\n encoding: DetectionMaskEncoding.CompressedRle,\n height,\n width,\n };\n }\n function assertMaskDimensions(data, width, height) {\n if (!Number.isInteger(width) || width <= 0) {\n throw new Error(\"Mask width must be a positive integer.\");\n }\n if (!Number.isInteger(height) || height <= 0) {\n throw new Error(\"Mask height must be a positive integer.\");\n }\n if (data.length !== width * height) {\n throw new Error(\"Mask data length must equal width * height.\");\n }\n }\n function rasterizePolygonToMask(points, dimensions) {\n const data = createEmptyMask(dimensions);\n if (points.length < 3) {\n return data;\n }\n const bounds = centerRectToTopLeftRect(getPointsRect(points));\n const startY = Math.max(0, Math.floor(bounds.y));\n const endY = Math.min(dimensions.height - 1, Math.ceil(bounds.y + bounds.height));\n for (let y = startY; y <= endY; y += 1) {\n const scanY = y + 0.5;\n const intersections = [];\n for (let index = 0; index < points.length; index += 1) {\n const current = points[index];\n const next = points[(index + 1) % points.length];\n if ((current.y <= scanY && next.y > scanY) ||\n (next.y <= scanY && current.y > scanY)) {\n const ratio = (scanY - current.y) / (next.y - current.y);\n intersections.push(current.x + ratio * (next.x - current.x));\n }\n }\n intersections.sort((left, right) => left - right);\n for (let index = 0; index < intersections.length - 1; index += 2) {\n const left = Math.max(0, Math.ceil(intersections[index]));\n const right = Math.min(dimensions.width - 1, Math.floor(intersections[index + 1]));\n for (let x = left; x <= right; x += 1) {\n data[y * dimensions.width + x] = 1;\n }\n }\n }\n return data;\n }\n function createEmptyMask(dimensions) {\n if (!Number.isInteger(dimensions.width) ||\n dimensions.width <= 0 ||\n !Number.isInteger(dimensions.height) ||\n dimensions.height <= 0) {\n throw new Error(\"Media dimensions must be positive integers.\");\n }\n return new Uint8Array(dimensions.width * dimensions.height);\n }\n\n const MAX_ID_MASK_PALETTE_ENTRIES = 64;\n const MAX_ID_MASK_STROKE_WIDTH = 16;\n function createIdMaskFrame(instructions) {\n if (instructions.length === 0) {\n return undefined;\n }\n const width = Math.max(...instructions.map(({ mask }) => mask.width));\n const height = Math.max(...instructions.map(({ mask }) => mask.height));\n const data = new Uint8Array(new ArrayBuffer(width * height));\n const fillPalette = new Float32Array(new ArrayBuffer(MAX_ID_MASK_PALETTE_ENTRIES * 4 * 4));\n const strokePalette = new Float32Array(new ArrayBuffer(MAX_ID_MASK_PALETTE_ENTRIES * 4 * 4));\n const strokeWidths = new Float32Array(new ArrayBuffer(MAX_ID_MASK_PALETTE_ENTRIES * 4));\n let hasStroke = false;\n let maxStrokeWidth = 0;\n for (const instruction of instructions) {\n const detectionMaskId = instruction.detectionIndex + 1;\n if (detectionMaskId <= 0 ||\n detectionMaskId >= MAX_ID_MASK_PALETTE_ENTRIES) {\n return undefined;\n }\n writePaletteEntry(fillPalette, detectionMaskId, instruction.color, instruction.alpha);\n if (instruction.stroke && instruction.stroke.width > 0) {\n const strokeWidth = Math.min(Math.max(0, instruction.stroke.width), MAX_ID_MASK_STROKE_WIDTH);\n hasStroke = true;\n strokeWidths[detectionMaskId] = strokeWidth;\n maxStrokeWidth = Math.max(maxStrokeWidth, strokeWidth);\n writePaletteEntry(strokePalette, detectionMaskId, instruction.stroke.color, instruction.stroke.alpha);\n }\n const decodedMask = decodeCompressedRleMask(instruction.mask);\n for (let y = 0; y < decodedMask.height; y += 1) {\n for (let x = 0; x < decodedMask.width; x += 1) {\n const maskOffset = y * decodedMask.width + x;\n if (decodedMask.data[maskOffset]) {\n data[y * width + x] = detectionMaskId;\n }\n }\n }\n }\n return {\n data,\n fillPalette,\n hasStroke,\n height,\n maxStrokeWidth,\n strokePalette,\n strokeWidths,\n width,\n };\n }\n function writePaletteEntry(palette, id, color, alpha) {\n const offset = id * 4;\n palette[offset] = ((color >> 16) & 0xff) / 255;\n palette[offset + 1] = ((color >> 8) & 0xff) / 255;\n palette[offset + 2] = (color & 0xff) / 255;\n palette[offset + 3] = Math.max(0, Math.min(alpha, 1));\n }\n\n var MediaRendererFit;\n (function (MediaRendererFit) {\n /**\n * Preserve media aspect ratio and fit the full frame inside the canvas.\n */\n MediaRendererFit[\"Contain\"] = \"contain\";\n /**\n * Preserve media aspect ratio and fill the canvas, cropping if necessary.\n */\n MediaRendererFit[\"Cover\"] = \"cover\";\n })(MediaRendererFit || (MediaRendererFit = {}));\n /**\n * Playback lifecycle state reported by a platform renderer.\n */\n var MediaRendererPlaybackState;\n (function (MediaRendererPlaybackState) {\n MediaRendererPlaybackState[\"Loading\"] = \"loading\";\n MediaRendererPlaybackState[\"Ready\"] = \"ready\";\n MediaRendererPlaybackState[\"Playing\"] = \"playing\";\n MediaRendererPlaybackState[\"Buffering\"] = \"buffering\";\n MediaRendererPlaybackState[\"Paused\"] = \"paused\";\n MediaRendererPlaybackState[\"Error\"] = \"error\";\n MediaRendererPlaybackState[\"Destroyed\"] = \"destroyed\";\n })(MediaRendererPlaybackState || (MediaRendererPlaybackState = {}));\n /**\n * Lower-level media source readiness.\n */\n var MediaSourceStatus;\n (function (MediaSourceStatus) {\n MediaSourceStatus[\"Loading\"] = \"loading\";\n MediaSourceStatus[\"Ready\"] = \"ready\";\n MediaSourceStatus[\"Error\"] = \"error\";\n MediaSourceStatus[\"Destroyed\"] = \"destroyed\";\n })(MediaSourceStatus || (MediaSourceStatus = {}));\n\n /**\n * Media-session operating mode.\n *\n * Core owns the names because file-like and stream-like lifecycle choices are\n * platform-neutral. Platform packages decide how these modes tune media,\n * storage, and renderer defaults.\n */\n var MediaSessionMode;\n (function (MediaSessionMode) {\n /**\n * Finite media. Defaults usually favor seek/replay and persistent detection\n * storage.\n */\n MediaSessionMode[\"File\"] = \"file\";\n /**\n * Live or append-only media. Defaults usually favor rolling windows and\n * bounded retention.\n */\n MediaSessionMode[\"Stream\"] = \"stream\";\n })(MediaSessionMode || (MediaSessionMode = {}));\n /**\n * Aggregate lifecycle state for a media session.\n */\n var MediaSessionStatus;\n (function (MediaSessionStatus) {\n MediaSessionStatus[\"Buffering\"] = \"buffering\";\n MediaSessionStatus[\"Destroyed\"] = \"destroyed\";\n MediaSessionStatus[\"Error\"] = \"error\";\n MediaSessionStatus[\"Loading\"] = \"loading\";\n MediaSessionStatus[\"Paused\"] = \"paused\";\n MediaSessionStatus[\"Playing\"] = \"playing\";\n MediaSessionStatus[\"Processing\"] = \"processing\";\n MediaSessionStatus[\"Ready\"] = \"ready\";\n })(MediaSessionStatus || (MediaSessionStatus = {}));\n /**\n * Subsystem currently affecting session readiness or presentation.\n */\n var MediaSessionActivityKind;\n (function (MediaSessionActivityKind) {\n MediaSessionActivityKind[\"DetectionsBuffering\"] = \"detectionsBuffering\";\n MediaSessionActivityKind[\"DetectionsLoading\"] = \"detectionsLoading\";\n MediaSessionActivityKind[\"Error\"] = \"error\";\n MediaSessionActivityKind[\"MediaNormalizing\"] = \"mediaNormalizing\";\n MediaSessionActivityKind[\"MediaOpening\"] = \"mediaOpening\";\n MediaSessionActivityKind[\"PlaybackBuffering\"] = \"playbackBuffering\";\n MediaSessionActivityKind[\"RenderPreparing\"] = \"renderPreparing\";\n })(MediaSessionActivityKind || (MediaSessionActivityKind = {}));\n /**\n * State of one session activity.\n */\n var MediaSessionActivityStatus;\n (function (MediaSessionActivityStatus) {\n MediaSessionActivityStatus[\"Error\"] = \"error\";\n MediaSessionActivityStatus[\"Running\"] = \"running\";\n MediaSessionActivityStatus[\"Waiting\"] = \"waiting\";\n })(MediaSessionActivityStatus || (MediaSessionActivityStatus = {}));\n\n const PNG_SIGNATURE = new Uint8Array([\n 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,\n ]);\n function compositeMaskFrame(instructions) {\n const maskInstructions = materializeMaskInstructions(instructions);\n if (maskInstructions.length === 0) {\n return undefined;\n }\n const width = Math.max(...maskInstructions.map(({ mask }) => mask.width));\n const height = Math.max(...maskInstructions.map(({ mask }) => mask.height));\n const data = new Uint8ClampedArray(new ArrayBuffer(width * height * 4));\n for (const instruction of maskInstructions) {\n compositeInstruction(data, width, instruction);\n }\n return { data, height, width };\n }\n function createMaskIdFrame(instructions) {\n return createIdMaskFrame(materializeMaskInstructions(instructions));\n }\n async function createPngIdMaskFrame(instructions) {\n const frame = createMaskIdFrame(instructions);\n if (!frame) {\n return undefined;\n }\n return {\n ...frame,\n png: await encodeGrayscalePng({\n height: frame.height,\n pixels: frame.data,\n width: frame.width,\n }),\n };\n }\n function compositeInstruction(rgba, canvasWidth, instruction) {\n const decodedMask = decodeCompressedRleMask(instruction.mask);\n const fill = resolveRgbaColor(instruction.color, instruction.alpha);\n compositeMaskFill(rgba, canvasWidth, decodedMask, fill);\n if (instruction.stroke) {\n compositeMaskStroke(rgba, canvasWidth, decodedMask, instruction.stroke);\n }\n }\n function materializeMaskInstructions(instructions) {\n return instructions.map((instruction) => {\n if (instruction.mask) {\n return instruction;\n }\n const { height, points, width } = instruction.polygon;\n return {\n alpha: instruction.alpha,\n color: instruction.color,\n detectionIndex: instruction.detectionIndex,\n mask: encodeBinaryMask(rasterizePolygonToMask(points, { height, width }), width, height),\n stroke: instruction.stroke,\n };\n });\n }\n function compositeMaskFill(rgba, canvasWidth, decodedMask, fill) {\n for (let y = 0; y < decodedMask.height; y += 1) {\n for (let x = 0; x < decodedMask.width; x += 1) {\n const maskOffset = y * decodedMask.width + x;\n if (!decodedMask.data[maskOffset]) {\n continue;\n }\n writePixel(rgba, canvasWidth, x, y, fill);\n }\n }\n }\n function compositeMaskStroke(rgba, canvasWidth, decodedMask, stroke) {\n const width = Math.round(stroke.width);\n if (width <= 0) {\n return;\n }\n const strokeColor = resolveRgbaColor(stroke.color, stroke.alpha);\n for (let y = 0; y < decodedMask.height; y += 1) {\n for (let x = 0; x < decodedMask.width; x += 1) {\n if (!isMaskPixel(decodedMask, x, y) ||\n !isBoundaryPixel(decodedMask, x, y)) {\n continue;\n }\n for (let offsetY = -width; offsetY <= width; offsetY += 1) {\n for (let offsetX = -width; offsetX <= width; offsetX += 1) {\n const strokeX = x + offsetX;\n const strokeY = y + offsetY;\n if (isOutsideMaskBounds(decodedMask, strokeX, strokeY) ||\n isMaskPixel(decodedMask, strokeX, strokeY)) {\n continue;\n }\n writePixel(rgba, canvasWidth, strokeX, strokeY, strokeColor);\n }\n }\n }\n }\n }\n function isBoundaryPixel(mask, x, y) {\n for (let offsetY = -1; offsetY <= 1; offsetY += 1) {\n for (let offsetX = -1; offsetX <= 1; offsetX += 1) {\n if (offsetX === 0 && offsetY === 0) {\n continue;\n }\n const neighborX = x + offsetX;\n const neighborY = y + offsetY;\n if (isOutsideMaskBounds(mask, neighborX, neighborY) ||\n !isMaskPixel(mask, neighborX, neighborY)) {\n return true;\n }\n }\n }\n return false;\n }\n function isMaskPixel(mask, x, y) {\n return mask.data[y * mask.width + x] === 1;\n }\n function isOutsideMaskBounds(mask, x, y) {\n return x < 0 || y < 0 || x >= mask.width || y >= mask.height;\n }\n function resolveRgbaColor(color, alpha) {\n return {\n alpha: Math.round(Math.max(0, Math.min(alpha, 1)) * 255),\n blue: color & 0xff,\n green: (color >> 8) & 0xff,\n red: (color >> 16) & 0xff,\n };\n }\n function writePixel(rgba, canvasWidth, x, y, color) {\n const rgbaOffset = (y * canvasWidth + x) * 4;\n rgba[rgbaOffset] = color.red;\n rgba[rgbaOffset + 1] = color.green;\n rgba[rgbaOffset + 2] = color.blue;\n rgba[rgbaOffset + 3] = color.alpha;\n }\n async function encodeGrayscalePng(options) {\n if (typeof CompressionStream === \"undefined\") {\n throw new Error(\"CompressionStream is required to encode PNG ID masks.\");\n }\n const rawScanlines = createFilterlessPngScanlines(options);\n const ihdr = new Uint8Array(13);\n const ihdrView = new DataView(ihdr.buffer);\n ihdrView.setUint32(0, options.width);\n ihdrView.setUint32(4, options.height);\n ihdr[8] = 8;\n ihdr[9] = 0;\n ihdr[10] = 0;\n ihdr[11] = 0;\n ihdr[12] = 0;\n const compressed = new Uint8Array(await new Response(new Blob([rawScanlines])\n .stream()\n .pipeThrough(new CompressionStream(\"deflate\"))).arrayBuffer());\n return concatUint8Arrays([\n PNG_SIGNATURE,\n createPngChunk(\"IHDR\", ihdr),\n createPngChunk(\"IDAT\", compressed),\n createPngChunk(\"IEND\", new Uint8Array(0)),\n ]);\n }\n function createFilterlessPngScanlines(options) {\n const rowStride = options.width + 1;\n const scanlines = new Uint8Array(rowStride * options.height);\n for (let y = 0; y < options.height; y += 1) {\n const sourceOffset = y * options.width;\n const targetOffset = y * rowStride;\n scanlines[targetOffset] = 0;\n scanlines.set(options.pixels.subarray(sourceOffset, sourceOffset + options.width), targetOffset + 1);\n }\n return scanlines;\n }\n function createPngChunk(type, data) {\n const typeBytes = new TextEncoder().encode(type);\n const chunk = new Uint8Array(12 + data.length);\n const view = new DataView(chunk.buffer);\n view.setUint32(0, data.length);\n chunk.set(typeBytes, 4);\n chunk.set(data, 8);\n view.setUint32(8 + data.length, crc32(concatUint8Arrays([typeBytes, data])));\n return chunk;\n }\n const crc32Table = createCrc32Table();\n function createCrc32Table() {\n const table = new Uint32Array(256);\n for (let index = 0; index < table.length; index += 1) {\n let value = index;\n for (let bit = 0; bit < 8; bit += 1) {\n value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;\n }\n table[index] = value >>> 0;\n }\n return table;\n }\n function crc32(bytes) {\n let crc = 0xffffffff;\n for (const byte of bytes) {\n crc = crc32Table[(crc ^ byte) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n }\n function concatUint8Arrays(chunks) {\n const totalLength = chunks.reduce((total, chunk) => total + chunk.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n }\n\n var PreparedMaskFrameKind;\n (function (PreparedMaskFrameKind) {\n PreparedMaskFrameKind[\"PngIdMask\"] = \"pngIdMask\";\n PreparedMaskFrameKind[\"RgbaImage\"] = \"rgbaImage\";\n })(PreparedMaskFrameKind || (PreparedMaskFrameKind = {}));\n\n var MaskPreparationWorkerMessageType;\n (function (MaskPreparationWorkerMessageType) {\n MaskPreparationWorkerMessageType[\"Complete\"] = \"complete\";\n MaskPreparationWorkerMessageType[\"Empty\"] = \"empty\";\n MaskPreparationWorkerMessageType[\"Error\"] = \"error\";\n MaskPreparationWorkerMessageType[\"Prepare\"] = \"prepare\";\n })(MaskPreparationWorkerMessageType || (MaskPreparationWorkerMessageType = {}));\n\n const workerScope = globalThis;\n workerScope.addEventListener(\"message\", (event) => {\n const message = event.data;\n if (message.type !== MaskPreparationWorkerMessageType.Prepare) {\n return;\n }\n void prepareMaskFrame(message);\n });\n async function prepareMaskFrame(message) {\n try {\n const pngIdMaskFrame = await createPngIdMaskWorkerResponse(message);\n if (pngIdMaskFrame) {\n workerScope.postMessage(pngIdMaskFrame, [\n pngIdMaskFrame.imageBitmap,\n pngIdMaskFrame.png.buffer,\n pngIdMaskFrame.fillPalette.buffer,\n pngIdMaskFrame.strokePalette.buffer,\n pngIdMaskFrame.strokeWidths.buffer,\n ]);\n return;\n }\n const compositedFrame = compositeMaskFrame(message.job.instructions);\n if (!compositedFrame) {\n workerScope.postMessage({\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Empty,\n });\n return;\n }\n const imageData = new ImageData(compositedFrame.data, compositedFrame.width, compositedFrame.height);\n const imageBitmap = createImageBitmapFromImageData(imageData);\n const idMaskData = createMaskIdFrame(message.job.instructions)?.data;\n if (imageBitmap) {\n workerScope.postMessage({\n imageBitmap,\n idMaskData,\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Complete,\n }, [...(idMaskData ? [idMaskData.buffer] : []), imageBitmap]);\n return;\n }\n workerScope.postMessage({\n idMaskData,\n imageData,\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Complete,\n }, [...(idMaskData ? [idMaskData.buffer] : []), imageData.data.buffer]);\n }\n catch (error) {\n workerScope.postMessage({\n error: error instanceof Error\n ? error.message\n : \"Unable to prepare mask frame.\",\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Error,\n });\n }\n }\n async function createPngIdMaskWorkerResponse(message) {\n if (typeof Blob === \"undefined\" ||\n typeof createImageBitmap === \"undefined\" ||\n typeof CompressionStream === \"undefined\") {\n return undefined;\n }\n let frame;\n try {\n frame = await createPngIdMaskFrame(message.job.instructions);\n }\n catch {\n return undefined;\n }\n if (!frame) {\n return undefined;\n }\n let imageBitmap;\n try {\n imageBitmap = await createImageBitmap(new Blob([frame.png], { type: \"image/png\" }));\n }\n catch {\n return undefined;\n }\n return {\n artifactKind: PreparedMaskFrameKind.PngIdMask,\n fillPalette: frame.fillPalette,\n hasStroke: frame.hasStroke,\n imageBitmap,\n key: message.job.key,\n maxStrokeWidth: frame.maxStrokeWidth,\n png: frame.png,\n requestId: message.requestId,\n strokePalette: frame.strokePalette,\n strokeWidths: frame.strokeWidths,\n type: MaskPreparationWorkerMessageType.Complete,\n };\n }\n function createImageBitmapFromImageData(imageData) {\n if (typeof OffscreenCanvas === \"undefined\") {\n return null;\n }\n const canvas = new OffscreenCanvas(imageData.width, imageData.height);\n const context = canvas.getContext(\"2d\");\n if (!context) {\n return null;\n }\n context.putImageData(imageData, 0, 0);\n return canvas.transferToImageBitmap();\n }\n\n})();";
5904
+ const EMBEDDED_MASK_PREPARATION_WORKER_SOURCE = "(function () {\n 'use strict';\n\n /** COCO-compatible keypoint visibility values. */\n var KeypointVisibility;\n (function (KeypointVisibility) {\n KeypointVisibility[KeypointVisibility[\"NotLabeled\"] = 0] = \"NotLabeled\";\n KeypointVisibility[KeypointVisibility[\"Occluded\"] = 1] = \"Occluded\";\n KeypointVisibility[KeypointVisibility[\"Visible\"] = 2] = \"Visible\";\n })(KeypointVisibility || (KeypointVisibility = {}));\n var DetectionMaskEncoding;\n (function (DetectionMaskEncoding) {\n DetectionMaskEncoding[\"CompressedRle\"] = \"compressedRle\";\n })(DetectionMaskEncoding || (DetectionMaskEncoding = {}));\n\n var DetectionBufferStatus;\n (function (DetectionBufferStatus) {\n DetectionBufferStatus[\"Idle\"] = \"idle\";\n DetectionBufferStatus[\"Loading\"] = \"loading\";\n DetectionBufferStatus[\"Ready\"] = \"ready\";\n DetectionBufferStatus[\"Error\"] = \"error\";\n DetectionBufferStatus[\"Destroyed\"] = \"destroyed\";\n })(DetectionBufferStatus || (DetectionBufferStatus = {}));\n /**\n * How the renderer selects the active detection frame for a media timestamp.\n */\n var DetectionFrameSelectionMode;\n (function (DetectionFrameSelectionMode) {\n /**\n * Select the frame whose `[mediaTime, endTime)` interval contains the media\n * time. This is the default for interval annotations and timestamped sources.\n */\n DetectionFrameSelectionMode[\"Interval\"] = \"interval\";\n /**\n * Select from a known inference frame grid using `frameIndex`, `frameRate`,\n * and optional `frameIndexOriginTime`. This is useful when inference was run\n * on normalized frames and playback should snap detections to that grid.\n */\n DetectionFrameSelectionMode[\"NearestFrameIndex\"] = \"nearestFrameIndex\";\n })(DetectionFrameSelectionMode || (DetectionFrameSelectionMode = {}));\n var DetectionFrameRetentionMode;\n (function (DetectionFrameRetentionMode) {\n /**\n * Keep writable detections only in an in-memory store. Useful for ephemeral\n * live streams where old predictions should disappear when evicted.\n */\n DetectionFrameRetentionMode[\"MemoryOnly\"] = \"memoryOnly\";\n /**\n * Persist every written detection frame. Useful for finite media where seek\n * and replay should not require recomputing detections.\n */\n DetectionFrameRetentionMode[\"PersistAll\"] = \"persistAll\";\n /**\n * Persist only the most recent retention window. Useful for long-running\n * streams where replay is bounded to a recent time horizon.\n */\n DetectionFrameRetentionMode[\"PersistWindow\"] = \"persistWindow\";\n })(DetectionFrameRetentionMode || (DetectionFrameRetentionMode = {}));\n function decodeCompressedRleMask(mask) {\n if (mask.encoding !== DetectionMaskEncoding.CompressedRle) {\n throw new Error(`Unsupported detection mask encoding: ${mask.encoding}`);\n }\n const data = new Uint8Array(mask.width * mask.height);\n const counts = decodeCompressedRleCounts(mask.counts);\n let offset = 0;\n for (let index = 0; index < counts.length; index += 1) {\n const runLength = counts[index] ?? 0;\n const isForeground = index % 2 === 1;\n if (isForeground) {\n for (let runOffset = 0; runOffset < runLength; runOffset += 1) {\n const maskOffset = offset + runOffset;\n const x = Math.floor(maskOffset / mask.height);\n const y = maskOffset % mask.height;\n const rowMajorOffset = y * mask.width + x;\n if (rowMajorOffset < data.length) {\n data[rowMajorOffset] = 1;\n }\n }\n }\n offset += runLength;\n }\n return {\n data,\n height: mask.height,\n width: mask.width,\n };\n }\n function decodeCompressedRleCounts(counts) {\n const decoded = [];\n let index = 0;\n while (index < counts.length) {\n let value = 0;\n let shift = 0;\n let charCode;\n do {\n charCode = counts.charCodeAt(index) - 48;\n index += 1;\n value |= (charCode & 0x1f) << shift;\n shift += 5;\n } while (charCode & 0x20);\n if (charCode & 0x10) {\n value |= -1 << shift;\n }\n if (decoded.length > 2) {\n value += decoded[decoded.length - 2] ?? 0;\n }\n decoded.push(value);\n }\n return decoded;\n }\n function encodeCompressedRleCounts(counts) {\n return counts\n .map((count, index) => {\n let value = index > 2 ? count - counts[index - 2] : count;\n let encoded = \"\";\n let more = true;\n while (more) {\n let charCode = value & 0x1f;\n value >>= 5;\n more = !((value === 0 && (charCode & 0x10) === 0) ||\n (value === -1 && (charCode & 0x10) !== 0));\n if (more) {\n charCode |= 0x20;\n }\n encoded += String.fromCharCode(charCode + 48);\n }\n return encoded;\n })\n .join(\"\");\n }\n\n var AnnotationFrameMutationKind;\n (function (AnnotationFrameMutationKind) {\n AnnotationFrameMutationKind[\"Add\"] = \"add\";\n AnnotationFrameMutationKind[\"Remove\"] = \"remove\";\n AnnotationFrameMutationKind[\"Replace\"] = \"replace\";\n AnnotationFrameMutationKind[\"Transact\"] = \"transact\";\n AnnotationFrameMutationKind[\"Update\"] = \"update\";\n })(AnnotationFrameMutationKind || (AnnotationFrameMutationKind = {}));\n\n /** Geometry projected into a tracker. The original detection payload is retained. */\n var TrackingGeometry;\n (function (TrackingGeometry) {\n TrackingGeometry[\"Box\"] = \"box\";\n TrackingGeometry[\"Mask\"] = \"mask\";\n TrackingGeometry[\"Keypoints\"] = \"keypoints\";\n })(TrackingGeometry || (TrackingGeometry = {}));\n\n var DetectionMaskPayloadFormat;\n (function (DetectionMaskPayloadFormat) {\n DetectionMaskPayloadFormat[\"RawCocoRle\"] = \"rawCocoRle\";\n DetectionMaskPayloadFormat[\"DeflatedBase64\"] = \"deflatedBase64\";\n })(DetectionMaskPayloadFormat || (DetectionMaskPayloadFormat = {}));\n function encodeBinaryMask(data, width, height) {\n assertMaskDimensions(data, width, height);\n const runs = [];\n let currentValue = 0;\n let runLength = 0;\n for (let x = 0; x < width; x += 1) {\n for (let y = 0; y < height; y += 1) {\n const value = data[y * width + x] ? 1 : 0;\n if (value === currentValue) {\n runLength += 1;\n }\n else {\n runs.push(runLength);\n currentValue = value;\n runLength = 1;\n }\n }\n }\n runs.push(runLength);\n return {\n counts: encodeCompressedRleCounts(runs),\n encoding: DetectionMaskEncoding.CompressedRle,\n height,\n width,\n };\n }\n function assertMaskDimensions(data, width, height) {\n if (!Number.isInteger(width) || width <= 0) {\n throw new Error(\"Mask width must be a positive integer.\");\n }\n if (!Number.isInteger(height) || height <= 0) {\n throw new Error(\"Mask height must be a positive integer.\");\n }\n if (data.length !== width * height) {\n throw new Error(\"Mask data length must equal width * height.\");\n }\n }\n\n function centerRectToTopLeftRect(rect) {\n return {\n height: rect.height,\n width: rect.width,\n x: rect.x - rect.width / 2,\n y: rect.y - rect.height / 2,\n };\n }\n function getPointsRect(points) {\n if (points.length === 0) {\n return undefined;\n }\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n for (const point of points) {\n minX = Math.min(minX, point.x);\n minY = Math.min(minY, point.y);\n maxX = Math.max(maxX, point.x);\n maxY = Math.max(maxY, point.y);\n }\n return {\n height: maxY - minY,\n width: maxX - minX,\n x: (minX + maxX) / 2,\n y: (minY + maxY) / 2,\n };\n }\n\n var DetectionPickTarget;\n (function (DetectionPickTarget) {\n DetectionPickTarget[\"Box\"] = \"box\";\n DetectionPickTarget[\"Edge\"] = \"edge\";\n DetectionPickTarget[\"Keypoint\"] = \"keypoint\";\n DetectionPickTarget[\"Label\"] = \"label\";\n DetectionPickTarget[\"Mask\"] = \"mask\";\n DetectionPickTarget[\"Polygon\"] = \"polygon\";\n DetectionPickTarget[\"Polyline\"] = \"polyline\";\n })(DetectionPickTarget || (DetectionPickTarget = {}));\n var MediaInteractionMode;\n (function (MediaInteractionMode) {\n MediaInteractionMode[\"Always\"] = \"always\";\n MediaInteractionMode[\"Disabled\"] = \"disabled\";\n MediaInteractionMode[\"PausedOnly\"] = \"pausedOnly\";\n })(MediaInteractionMode || (MediaInteractionMode = {}));\n\n var AnnotationGeometryKind;\n (function (AnnotationGeometryKind) {\n AnnotationGeometryKind[\"Box\"] = \"box\";\n AnnotationGeometryKind[\"Polygon\"] = \"polygon\";\n AnnotationGeometryKind[\"Polyline\"] = \"polyline\";\n AnnotationGeometryKind[\"Keypoints\"] = \"keypoints\";\n AnnotationGeometryKind[\"Mask\"] = \"mask\";\n })(AnnotationGeometryKind || (AnnotationGeometryKind = {}));\n var AnnotationGestureStateKind;\n (function (AnnotationGestureStateKind) {\n AnnotationGestureStateKind[\"Idle\"] = \"idle\";\n AnnotationGestureStateKind[\"Creating\"] = \"creating\";\n AnnotationGestureStateKind[\"Moving\"] = \"moving\";\n AnnotationGestureStateKind[\"Resizing\"] = \"resizing\";\n AnnotationGestureStateKind[\"DragSelecting\"] = \"dragSelecting\";\n })(AnnotationGestureStateKind || (AnnotationGestureStateKind = {}));\n var AnnotationHandleKind;\n (function (AnnotationHandleKind) {\n AnnotationHandleKind[\"Resize\"] = \"resize\";\n AnnotationHandleKind[\"Vertex\"] = \"vertex\";\n AnnotationHandleKind[\"AddVertex\"] = \"addVertex\";\n AnnotationHandleKind[\"Keypoint\"] = \"keypoint\";\n })(AnnotationHandleKind || (AnnotationHandleKind = {}));\n\n /** Alignment for strokes applied to closed rendered geometry. */\n var StrokeAlignment;\n (function (StrokeAlignment) {\n StrokeAlignment[\"Inside\"] = \"inside\";\n StrokeAlignment[\"Center\"] = \"center\";\n StrokeAlignment[\"Outside\"] = \"outside\";\n })(StrokeAlignment || (StrokeAlignment = {}));\n\n var BoxShape;\n (function (BoxShape) {\n BoxShape[\"Rect\"] = \"rect\";\n BoxShape[\"RoundedRect\"] = \"roundedRect\";\n })(BoxShape || (BoxShape = {}));\n\n var FocusTargetMode;\n (function (FocusTargetMode) {\n FocusTargetMode[\"Hovered\"] = \"hovered\";\n FocusTargetMode[\"Selected\"] = \"selected\";\n FocusTargetMode[\"HoveredAndSelected\"] = \"hoveredAndSelected\";\n FocusTargetMode[\"Ambient\"] = \"ambient\";\n })(FocusTargetMode || (FocusTargetMode = {}));\n\n var DetectionInteractionState;\n (function (DetectionInteractionState) {\n DetectionInteractionState[\"Hovered\"] = \"hovered\";\n DetectionInteractionState[\"Selected\"] = \"selected\";\n })(DetectionInteractionState || (DetectionInteractionState = {}));\n\n var LabelPlacement;\n (function (LabelPlacement) {\n LabelPlacement[\"Top\"] = \"top\";\n LabelPlacement[\"Bottom\"] = \"bottom\";\n LabelPlacement[\"InsideTop\"] = \"insideTop\";\n LabelPlacement[\"InsideBottom\"] = \"insideBottom\";\n LabelPlacement[\"Center\"] = \"center\";\n })(LabelPlacement || (LabelPlacement = {}));\n var LabelVisibilityMode;\n (function (LabelVisibilityMode) {\n LabelVisibilityMode[\"Always\"] = \"always\";\n LabelVisibilityMode[\"HoveredOnly\"] = \"hoveredOnly\";\n })(LabelVisibilityMode || (LabelVisibilityMode = {}));\n\n var MaskRenderMode;\n (function (MaskRenderMode) {\n MaskRenderMode[\"FillAndStroke\"] = \"fillAndStroke\";\n MaskRenderMode[\"FillOnly\"] = \"fillOnly\";\n MaskRenderMode[\"StrokeOnly\"] = \"strokeOnly\";\n })(MaskRenderMode || (MaskRenderMode = {}));\n\n /**\n * Discriminator for renderer-neutral shape draw instructions.\n */\n var ShapeInstructionKind;\n (function (ShapeInstructionKind) {\n ShapeInstructionKind[\"Ellipse\"] = \"ellipse\";\n ShapeInstructionKind[\"Marker\"] = \"marker\";\n ShapeInstructionKind[\"Path\"] = \"path\";\n })(ShapeInstructionKind || (ShapeInstructionKind = {}));\n var MarkerShape;\n (function (MarkerShape) {\n MarkerShape[\"Circle\"] = \"circle\";\n MarkerShape[\"Cross\"] = \"cross\";\n MarkerShape[\"Square\"] = \"square\";\n MarkerShape[\"Triangle\"] = \"triangle\";\n })(MarkerShape || (MarkerShape = {}));\n /**\n * Coordinate space for marker sizing. Media sizes scale with the viewport;\n * screen sizes stay constant on screen, matching stroke-width semantics.\n */\n var MarkerSizeSpace;\n (function (MarkerSizeSpace) {\n MarkerSizeSpace[\"Media\"] = \"media\";\n MarkerSizeSpace[\"Screen\"] = \"screen\";\n })(MarkerSizeSpace || (MarkerSizeSpace = {}));\n\n var KeypointMarkerShape;\n (function (KeypointMarkerShape) {\n KeypointMarkerShape[\"Circle\"] = \"circle\";\n KeypointMarkerShape[\"Cross\"] = \"cross\";\n })(KeypointMarkerShape || (KeypointMarkerShape = {}));\n function rasterizePolygonToMask(points, dimensions) {\n const data = createEmptyMask(dimensions);\n if (points.length < 3) {\n return data;\n }\n const bounds = centerRectToTopLeftRect(getPointsRect(points));\n const startY = Math.max(0, Math.floor(bounds.y));\n const endY = Math.min(dimensions.height - 1, Math.ceil(bounds.y + bounds.height));\n for (let y = startY; y <= endY; y += 1) {\n const scanY = y + 0.5;\n const intersections = [];\n for (let index = 0; index < points.length; index += 1) {\n const current = points[index];\n const next = points[(index + 1) % points.length];\n if ((current.y <= scanY && next.y > scanY) ||\n (next.y <= scanY && current.y > scanY)) {\n const ratio = (scanY - current.y) / (next.y - current.y);\n intersections.push(current.x + ratio * (next.x - current.x));\n }\n }\n intersections.sort((left, right) => left - right);\n for (let index = 0; index < intersections.length - 1; index += 2) {\n const left = Math.max(0, Math.ceil(intersections[index]));\n const right = Math.min(dimensions.width - 1, Math.floor(intersections[index + 1]));\n for (let x = left; x <= right; x += 1) {\n data[y * dimensions.width + x] = 1;\n }\n }\n }\n return data;\n }\n function createEmptyMask(dimensions) {\n if (!Number.isInteger(dimensions.width) ||\n dimensions.width <= 0 ||\n !Number.isInteger(dimensions.height) ||\n dimensions.height <= 0) {\n throw new Error(\"Media dimensions must be positive integers.\");\n }\n return new Uint8Array(dimensions.width * dimensions.height);\n }\n\n const MAX_ID_MASK_PALETTE_ENTRIES = 64;\n const MAX_ID_MASK_STROKE_WIDTH = 16;\n function createIdMaskFrame(instructions) {\n if (instructions.length === 0) {\n return undefined;\n }\n const width = Math.max(...instructions.map(({ mask }) => mask.width));\n const height = Math.max(...instructions.map(({ mask }) => mask.height));\n const data = new Uint8Array(new ArrayBuffer(width * height));\n const fillPalette = new Float32Array(new ArrayBuffer(MAX_ID_MASK_PALETTE_ENTRIES * 4 * 4));\n const strokePalette = new Float32Array(new ArrayBuffer(MAX_ID_MASK_PALETTE_ENTRIES * 4 * 4));\n const strokeWidths = new Float32Array(new ArrayBuffer(MAX_ID_MASK_PALETTE_ENTRIES * 4));\n let hasStroke = false;\n let maxStrokeWidth = 0;\n for (const instruction of instructions) {\n const detectionMaskId = instruction.detectionIndex + 1;\n if (detectionMaskId <= 0 ||\n detectionMaskId >= MAX_ID_MASK_PALETTE_ENTRIES) {\n return undefined;\n }\n writePaletteEntry(fillPalette, detectionMaskId, instruction.color, instruction.alpha);\n if (instruction.stroke && instruction.stroke.width > 0) {\n const strokeWidth = Math.min(Math.max(0, instruction.stroke.width), MAX_ID_MASK_STROKE_WIDTH);\n hasStroke = true;\n strokeWidths[detectionMaskId] = strokeWidth;\n maxStrokeWidth = Math.max(maxStrokeWidth, strokeWidth);\n writePaletteEntry(strokePalette, detectionMaskId, instruction.stroke.color, instruction.stroke.alpha);\n }\n const decodedMask = decodeCompressedRleMask(instruction.mask);\n for (let y = 0; y < decodedMask.height; y += 1) {\n for (let x = 0; x < decodedMask.width; x += 1) {\n const maskOffset = y * decodedMask.width + x;\n if (decodedMask.data[maskOffset]) {\n data[y * width + x] = detectionMaskId;\n }\n }\n }\n }\n return {\n data,\n fillPalette,\n hasStroke,\n height,\n maxStrokeWidth,\n strokePalette,\n strokeWidths,\n width,\n };\n }\n function writePaletteEntry(palette, id, color, alpha) {\n const offset = id * 4;\n palette[offset] = ((color >> 16) & 0xff) / 255;\n palette[offset + 1] = ((color >> 8) & 0xff) / 255;\n palette[offset + 2] = (color & 0xff) / 255;\n palette[offset + 3] = Math.max(0, Math.min(alpha, 1));\n }\n\n var MediaRendererFit;\n (function (MediaRendererFit) {\n /**\n * Preserve media aspect ratio and fit the full frame inside the canvas.\n */\n MediaRendererFit[\"Contain\"] = \"contain\";\n /**\n * Preserve media aspect ratio and fill the canvas, cropping if necessary.\n */\n MediaRendererFit[\"Cover\"] = \"cover\";\n })(MediaRendererFit || (MediaRendererFit = {}));\n /**\n * Playback lifecycle state reported by a platform renderer.\n */\n var MediaRendererPlaybackState;\n (function (MediaRendererPlaybackState) {\n MediaRendererPlaybackState[\"Loading\"] = \"loading\";\n MediaRendererPlaybackState[\"Ready\"] = \"ready\";\n MediaRendererPlaybackState[\"Playing\"] = \"playing\";\n MediaRendererPlaybackState[\"Buffering\"] = \"buffering\";\n MediaRendererPlaybackState[\"Paused\"] = \"paused\";\n MediaRendererPlaybackState[\"Error\"] = \"error\";\n MediaRendererPlaybackState[\"Destroyed\"] = \"destroyed\";\n })(MediaRendererPlaybackState || (MediaRendererPlaybackState = {}));\n /**\n * Lower-level media source readiness.\n */\n var MediaSourceStatus;\n (function (MediaSourceStatus) {\n MediaSourceStatus[\"Loading\"] = \"loading\";\n MediaSourceStatus[\"Ready\"] = \"ready\";\n MediaSourceStatus[\"Error\"] = \"error\";\n MediaSourceStatus[\"Destroyed\"] = \"destroyed\";\n })(MediaSourceStatus || (MediaSourceStatus = {}));\n\n /**\n * Media-session operating mode.\n *\n * Core owns the names because file-like and stream-like lifecycle choices are\n * platform-neutral. Platform packages decide how these modes tune media,\n * storage, and renderer defaults.\n */\n var MediaSessionMode;\n (function (MediaSessionMode) {\n /**\n * Finite media. Defaults usually favor seek/replay and persistent detection\n * storage.\n */\n MediaSessionMode[\"File\"] = \"file\";\n /**\n * Live or append-only media. Defaults usually favor rolling windows and\n * bounded retention.\n */\n MediaSessionMode[\"Stream\"] = \"stream\";\n })(MediaSessionMode || (MediaSessionMode = {}));\n /**\n * Aggregate lifecycle state for a media session.\n */\n var MediaSessionStatus;\n (function (MediaSessionStatus) {\n MediaSessionStatus[\"Buffering\"] = \"buffering\";\n MediaSessionStatus[\"Destroyed\"] = \"destroyed\";\n MediaSessionStatus[\"Error\"] = \"error\";\n MediaSessionStatus[\"Loading\"] = \"loading\";\n MediaSessionStatus[\"Paused\"] = \"paused\";\n MediaSessionStatus[\"Playing\"] = \"playing\";\n MediaSessionStatus[\"Processing\"] = \"processing\";\n MediaSessionStatus[\"Ready\"] = \"ready\";\n })(MediaSessionStatus || (MediaSessionStatus = {}));\n /**\n * Subsystem currently affecting session readiness or presentation.\n */\n var MediaSessionActivityKind;\n (function (MediaSessionActivityKind) {\n MediaSessionActivityKind[\"DetectionsBuffering\"] = \"detectionsBuffering\";\n MediaSessionActivityKind[\"DetectionsLoading\"] = \"detectionsLoading\";\n MediaSessionActivityKind[\"Error\"] = \"error\";\n MediaSessionActivityKind[\"MediaNormalizing\"] = \"mediaNormalizing\";\n MediaSessionActivityKind[\"MediaOpening\"] = \"mediaOpening\";\n MediaSessionActivityKind[\"PlaybackBuffering\"] = \"playbackBuffering\";\n MediaSessionActivityKind[\"RenderPreparing\"] = \"renderPreparing\";\n })(MediaSessionActivityKind || (MediaSessionActivityKind = {}));\n /**\n * State of one session activity.\n */\n var MediaSessionActivityStatus;\n (function (MediaSessionActivityStatus) {\n MediaSessionActivityStatus[\"Error\"] = \"error\";\n MediaSessionActivityStatus[\"Running\"] = \"running\";\n MediaSessionActivityStatus[\"Waiting\"] = \"waiting\";\n })(MediaSessionActivityStatus || (MediaSessionActivityStatus = {}));\n\n const PNG_SIGNATURE = new Uint8Array([\n 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,\n ]);\n function compositeMaskFrame(instructions) {\n const maskInstructions = materializeMaskInstructions(instructions);\n if (maskInstructions.length === 0) {\n return undefined;\n }\n const width = Math.max(...maskInstructions.map(({ mask }) => mask.width));\n const height = Math.max(...maskInstructions.map(({ mask }) => mask.height));\n const data = new Uint8ClampedArray(new ArrayBuffer(width * height * 4));\n for (const instruction of maskInstructions) {\n compositeInstruction(data, width, instruction);\n }\n return { data, height, width };\n }\n function createMaskIdFrame(instructions) {\n return createIdMaskFrame(materializeMaskInstructions(instructions));\n }\n async function createPngIdMaskFrame(instructions) {\n const frame = createMaskIdFrame(instructions);\n if (!frame) {\n return undefined;\n }\n return {\n ...frame,\n png: await encodeGrayscalePng({\n height: frame.height,\n pixels: frame.data,\n width: frame.width,\n }),\n };\n }\n function compositeInstruction(rgba, canvasWidth, instruction) {\n const decodedMask = decodeCompressedRleMask(instruction.mask);\n const fill = resolveRgbaColor(instruction.color, instruction.alpha);\n compositeMaskFill(rgba, canvasWidth, decodedMask, fill);\n if (instruction.stroke) {\n compositeMaskStroke(rgba, canvasWidth, decodedMask, instruction.stroke);\n }\n }\n function materializeMaskInstructions(instructions) {\n return instructions.map((instruction) => {\n if (instruction.mask) {\n return instruction;\n }\n const { height, points, width } = instruction.polygon;\n return {\n alpha: instruction.alpha,\n color: instruction.color,\n detectionIndex: instruction.detectionIndex,\n mask: encodeBinaryMask(rasterizePolygonToMask(points, { height, width }), width, height),\n stroke: instruction.stroke,\n };\n });\n }\n function compositeMaskFill(rgba, canvasWidth, decodedMask, fill) {\n for (let y = 0; y < decodedMask.height; y += 1) {\n for (let x = 0; x < decodedMask.width; x += 1) {\n const maskOffset = y * decodedMask.width + x;\n if (!decodedMask.data[maskOffset]) {\n continue;\n }\n writePixel(rgba, canvasWidth, x, y, fill);\n }\n }\n }\n function compositeMaskStroke(rgba, canvasWidth, decodedMask, stroke) {\n const width = Math.round(stroke.width);\n if (width <= 0) {\n return;\n }\n const strokeColor = resolveRgbaColor(stroke.color, stroke.alpha);\n for (let y = 0; y < decodedMask.height; y += 1) {\n for (let x = 0; x < decodedMask.width; x += 1) {\n if (!isMaskPixel(decodedMask, x, y) ||\n !isBoundaryPixel(decodedMask, x, y)) {\n continue;\n }\n for (let offsetY = -width; offsetY <= width; offsetY += 1) {\n for (let offsetX = -width; offsetX <= width; offsetX += 1) {\n const strokeX = x + offsetX;\n const strokeY = y + offsetY;\n if (isOutsideMaskBounds(decodedMask, strokeX, strokeY) ||\n isMaskPixel(decodedMask, strokeX, strokeY)) {\n continue;\n }\n writePixel(rgba, canvasWidth, strokeX, strokeY, strokeColor);\n }\n }\n }\n }\n }\n function isBoundaryPixel(mask, x, y) {\n for (let offsetY = -1; offsetY <= 1; offsetY += 1) {\n for (let offsetX = -1; offsetX <= 1; offsetX += 1) {\n if (offsetX === 0 && offsetY === 0) {\n continue;\n }\n const neighborX = x + offsetX;\n const neighborY = y + offsetY;\n if (isOutsideMaskBounds(mask, neighborX, neighborY) ||\n !isMaskPixel(mask, neighborX, neighborY)) {\n return true;\n }\n }\n }\n return false;\n }\n function isMaskPixel(mask, x, y) {\n return mask.data[y * mask.width + x] === 1;\n }\n function isOutsideMaskBounds(mask, x, y) {\n return x < 0 || y < 0 || x >= mask.width || y >= mask.height;\n }\n function resolveRgbaColor(color, alpha) {\n return {\n alpha: Math.round(Math.max(0, Math.min(alpha, 1)) * 255),\n blue: color & 0xff,\n green: (color >> 8) & 0xff,\n red: (color >> 16) & 0xff,\n };\n }\n function writePixel(rgba, canvasWidth, x, y, color) {\n const rgbaOffset = (y * canvasWidth + x) * 4;\n rgba[rgbaOffset] = color.red;\n rgba[rgbaOffset + 1] = color.green;\n rgba[rgbaOffset + 2] = color.blue;\n rgba[rgbaOffset + 3] = color.alpha;\n }\n async function encodeGrayscalePng(options) {\n if (typeof CompressionStream === \"undefined\") {\n throw new Error(\"CompressionStream is required to encode PNG ID masks.\");\n }\n const rawScanlines = createFilterlessPngScanlines(options);\n const ihdr = new Uint8Array(13);\n const ihdrView = new DataView(ihdr.buffer);\n ihdrView.setUint32(0, options.width);\n ihdrView.setUint32(4, options.height);\n ihdr[8] = 8;\n ihdr[9] = 0;\n ihdr[10] = 0;\n ihdr[11] = 0;\n ihdr[12] = 0;\n const compressed = new Uint8Array(await new Response(new Blob([rawScanlines])\n .stream()\n .pipeThrough(new CompressionStream(\"deflate\"))).arrayBuffer());\n return concatUint8Arrays([\n PNG_SIGNATURE,\n createPngChunk(\"IHDR\", ihdr),\n createPngChunk(\"IDAT\", compressed),\n createPngChunk(\"IEND\", new Uint8Array(0)),\n ]);\n }\n function createFilterlessPngScanlines(options) {\n const rowStride = options.width + 1;\n const scanlines = new Uint8Array(rowStride * options.height);\n for (let y = 0; y < options.height; y += 1) {\n const sourceOffset = y * options.width;\n const targetOffset = y * rowStride;\n scanlines[targetOffset] = 0;\n scanlines.set(options.pixels.subarray(sourceOffset, sourceOffset + options.width), targetOffset + 1);\n }\n return scanlines;\n }\n function createPngChunk(type, data) {\n const typeBytes = new TextEncoder().encode(type);\n const chunk = new Uint8Array(12 + data.length);\n const view = new DataView(chunk.buffer);\n view.setUint32(0, data.length);\n chunk.set(typeBytes, 4);\n chunk.set(data, 8);\n view.setUint32(8 + data.length, crc32(concatUint8Arrays([typeBytes, data])));\n return chunk;\n }\n const crc32Table = createCrc32Table();\n function createCrc32Table() {\n const table = new Uint32Array(256);\n for (let index = 0; index < table.length; index += 1) {\n let value = index;\n for (let bit = 0; bit < 8; bit += 1) {\n value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;\n }\n table[index] = value >>> 0;\n }\n return table;\n }\n function crc32(bytes) {\n let crc = 0xffffffff;\n for (const byte of bytes) {\n crc = crc32Table[(crc ^ byte) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n }\n function concatUint8Arrays(chunks) {\n const totalLength = chunks.reduce((total, chunk) => total + chunk.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n }\n\n var PreparedMaskFrameKind;\n (function (PreparedMaskFrameKind) {\n PreparedMaskFrameKind[\"PngIdMask\"] = \"pngIdMask\";\n PreparedMaskFrameKind[\"RgbaImage\"] = \"rgbaImage\";\n })(PreparedMaskFrameKind || (PreparedMaskFrameKind = {}));\n\n var MaskPreparationWorkerMessageType;\n (function (MaskPreparationWorkerMessageType) {\n MaskPreparationWorkerMessageType[\"Complete\"] = \"complete\";\n MaskPreparationWorkerMessageType[\"Empty\"] = \"empty\";\n MaskPreparationWorkerMessageType[\"Error\"] = \"error\";\n MaskPreparationWorkerMessageType[\"Prepare\"] = \"prepare\";\n })(MaskPreparationWorkerMessageType || (MaskPreparationWorkerMessageType = {}));\n\n const workerScope = globalThis;\n workerScope.addEventListener(\"message\", (event) => {\n const message = event.data;\n if (message.type !== MaskPreparationWorkerMessageType.Prepare) {\n return;\n }\n void prepareMaskFrame(message);\n });\n async function prepareMaskFrame(message) {\n try {\n const pngIdMaskFrame = await createPngIdMaskWorkerResponse(message);\n if (pngIdMaskFrame) {\n workerScope.postMessage(pngIdMaskFrame, [\n pngIdMaskFrame.imageBitmap,\n pngIdMaskFrame.png.buffer,\n pngIdMaskFrame.fillPalette.buffer,\n pngIdMaskFrame.strokePalette.buffer,\n pngIdMaskFrame.strokeWidths.buffer,\n ]);\n return;\n }\n const compositedFrame = compositeMaskFrame(message.job.instructions);\n if (!compositedFrame) {\n workerScope.postMessage({\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Empty,\n });\n return;\n }\n const imageData = new ImageData(compositedFrame.data, compositedFrame.width, compositedFrame.height);\n const imageBitmap = createImageBitmapFromImageData(imageData);\n const idMaskData = createMaskIdFrame(message.job.instructions)?.data;\n if (imageBitmap) {\n workerScope.postMessage({\n imageBitmap,\n idMaskData,\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Complete,\n }, [...(idMaskData ? [idMaskData.buffer] : []), imageBitmap]);\n return;\n }\n workerScope.postMessage({\n idMaskData,\n imageData,\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Complete,\n }, [...(idMaskData ? [idMaskData.buffer] : []), imageData.data.buffer]);\n }\n catch (error) {\n workerScope.postMessage({\n error: error instanceof Error\n ? error.message\n : \"Unable to prepare mask frame.\",\n key: message.job.key,\n requestId: message.requestId,\n type: MaskPreparationWorkerMessageType.Error,\n });\n }\n }\n async function createPngIdMaskWorkerResponse(message) {\n if (typeof Blob === \"undefined\" ||\n typeof createImageBitmap === \"undefined\" ||\n typeof CompressionStream === \"undefined\") {\n return undefined;\n }\n let frame;\n try {\n frame = await createPngIdMaskFrame(message.job.instructions);\n }\n catch {\n return undefined;\n }\n if (!frame) {\n return undefined;\n }\n let imageBitmap;\n try {\n imageBitmap = await createImageBitmap(new Blob([frame.png], { type: \"image/png\" }));\n }\n catch {\n return undefined;\n }\n return {\n artifactKind: PreparedMaskFrameKind.PngIdMask,\n fillPalette: frame.fillPalette,\n hasStroke: frame.hasStroke,\n imageBitmap,\n key: message.job.key,\n maxStrokeWidth: frame.maxStrokeWidth,\n png: frame.png,\n requestId: message.requestId,\n strokePalette: frame.strokePalette,\n strokeWidths: frame.strokeWidths,\n type: MaskPreparationWorkerMessageType.Complete,\n };\n }\n function createImageBitmapFromImageData(imageData) {\n if (typeof OffscreenCanvas === \"undefined\") {\n return null;\n }\n const canvas = new OffscreenCanvas(imageData.width, imageData.height);\n const context = canvas.getContext(\"2d\");\n if (!context) {\n return null;\n }\n context.putImageData(imageData, 0, 0);\n return canvas.transferToImageBitmap();\n }\n\n})();";
5477
5905
 
5478
5906
  const DEFAULT_WORKER_NAME = "supervision-js-render-preparation";
5479
5907
  let defaultWorkerUrl;
@@ -5536,85 +5964,6 @@ var MaskPreparationWorkerMessageType;
5536
5964
  MaskPreparationWorkerMessageType["Prepare"] = "prepare";
5537
5965
  })(MaskPreparationWorkerMessageType || (MaskPreparationWorkerMessageType = {}));
5538
5966
 
5539
- function createWorkerRpcClient(options) {
5540
- let failureMessage = null;
5541
- let isDestroyed = false;
5542
- let nextRequestId = 1;
5543
- const pendingRequests = new Map();
5544
- options.worker.addEventListener("message", (event) => {
5545
- handleWorkerMessage(event.data);
5546
- });
5547
- options.worker.addEventListener("error", (event) => {
5548
- rejectPendingRequests(event.message || options.defaultErrorMessage);
5549
- });
5550
- options.worker.addEventListener("messageerror", () => {
5551
- rejectPendingRequests(`${options.defaultErrorMessage}: message error.`);
5552
- });
5553
- return {
5554
- destroy() {
5555
- if (isDestroyed) {
5556
- return;
5557
- }
5558
- isDestroyed = true;
5559
- rejectPendingRequests("Worker RPC client has been destroyed.", {
5560
- markFailure: false,
5561
- });
5562
- options.worker.terminate();
5563
- },
5564
- getFailureMessage() {
5565
- return failureMessage;
5566
- },
5567
- request(message) {
5568
- if (isDestroyed) {
5569
- return Promise.reject(new Error("Worker RPC client has been destroyed."));
5570
- }
5571
- if (failureMessage) {
5572
- return Promise.reject(new Error(failureMessage));
5573
- }
5574
- const request = {
5575
- ...message,
5576
- requestId: nextRequestId,
5577
- };
5578
- nextRequestId += 1;
5579
- return new Promise((resolve, reject) => {
5580
- pendingRequests.set(request.requestId, { reject, resolve });
5581
- try {
5582
- options.worker.postMessage(request);
5583
- }
5584
- catch (error) {
5585
- pendingRequests.delete(request.requestId);
5586
- failureMessage = getErrorMessage$2(error, options.defaultErrorMessage);
5587
- reject(new Error(failureMessage));
5588
- }
5589
- });
5590
- },
5591
- };
5592
- function handleWorkerMessage(message) {
5593
- if (!options.isResponse(message)) {
5594
- return;
5595
- }
5596
- const pendingRequest = pendingRequests.get(message.requestId);
5597
- if (!pendingRequest) {
5598
- options.onOrphanedResponse?.(message);
5599
- return;
5600
- }
5601
- pendingRequests.delete(message.requestId);
5602
- pendingRequest.resolve(message);
5603
- }
5604
- function rejectPendingRequests(message, options = { markFailure: true }) {
5605
- if (options.markFailure) {
5606
- failureMessage = message;
5607
- }
5608
- for (const pendingRequest of pendingRequests.values()) {
5609
- pendingRequest.reject(new Error(message));
5610
- }
5611
- pendingRequests.clear();
5612
- }
5613
- }
5614
- function getErrorMessage$2(error, fallback) {
5615
- return error instanceof Error ? error.message : fallback;
5616
- }
5617
-
5618
5967
  function createMaskFramePreparer(options = {}) {
5619
5968
  const mainThreadPreparer = createMainThreadMaskFramePreparer(RenderPreparationWorkerStatus.Disabled);
5620
5969
  const mode = options.renderPreparation?.mode ?? RenderPreparationMode.Auto;
@@ -10630,5 +10979,5 @@ function getErrorMessage(error, fallback) {
10630
10979
  return error instanceof Error ? error.message : fallback;
10631
10980
  }
10632
10981
 
10633
- export { DetectionTimelineOrigin, MediaNormalizationAudioCodec, MediaNormalizationContainer, MediaNormalizationFit, MediaNormalizationVideoCodec, MediaPreparationError, MediaProbeIssueCode, MediaProbeStatus, RenderPreparationArtifactFrameStatus, RenderPreparationArtifactKind, RenderPreparationExecutionMode, RenderPreparationMode, RenderPreparationWorkerStatus, createBrowserColdDetectionFrameStore, createChunkedDetectionFrameSource, createImageUrlMediaSource, createMediaRenderer, createMediaSession, createMediaStreamRendererSource, createStaticImageMediaSource, normalizeMedia, normalizeMediaProgressively, prepareMedia, prepareMediaProgressively, probeMedia };
10982
+ export { DetectionPostProcessingMode, DetectionTimelineOrigin, MediaNormalizationAudioCodec, MediaNormalizationContainer, MediaNormalizationFit, MediaNormalizationVideoCodec, MediaPreparationError, MediaProbeIssueCode, MediaProbeStatus, RenderPreparationArtifactFrameStatus, RenderPreparationArtifactKind, RenderPreparationExecutionMode, RenderPreparationMode, RenderPreparationWorkerStatus, createBrowserColdDetectionFrameStore, createChunkedDetectionFrameSource, createDefaultDetectionPostProcessingWorkerFactory, createDetectionPostProcessingPipeline, createImageUrlMediaSource, createMediaRenderer, createMediaSession, createMediaStreamRendererSource, createStaticImageMediaSource, normalizeMedia, normalizeMediaProgressively, prepareMedia, prepareMediaProgressively, probeMedia };
10634
10983
  //# sourceMappingURL=index.js.map