supervision 0.1.2 → 0.1.3

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 (25) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +80 -16
  4. package/dist/index.js.map +1 -1
  5. package/dist/mask-preparation.worker.js.map +1 -1
  6. package/dist/renderers/media-renderer-core.d.ts.map +1 -1
  7. package/dist/renderers/pixi-focus-layer.d.ts.map +1 -1
  8. package/dist/sessions/media-session.d.ts.map +1 -1
  9. package/node_modules/supervision-js-core/dist/index.d.ts +3 -1
  10. package/node_modules/supervision-js-core/dist/index.d.ts.map +1 -1
  11. package/node_modules/supervision-js-core/dist/index.js +242 -89
  12. package/node_modules/supervision-js-core/dist/index.js.map +1 -1
  13. package/node_modules/supervision-js-core/dist/styles/annotation-renderer-presentation.d.ts +9 -0
  14. package/node_modules/supervision-js-core/dist/styles/annotation-renderer-presentation.d.ts.map +1 -0
  15. package/node_modules/supervision-js-core/dist/styles/annotation-renderer-registry.d.ts +40 -0
  16. package/node_modules/supervision-js-core/dist/styles/annotation-renderer-registry.d.ts.map +1 -0
  17. package/node_modules/supervision-js-core/dist/styles/default-annotation-presentation.d.ts +19 -0
  18. package/node_modules/supervision-js-core/dist/styles/default-annotation-presentation.d.ts.map +1 -1
  19. package/node_modules/supervision-js-core/dist/styles/source-presentation.d.ts +10 -2
  20. package/node_modules/supervision-js-core/dist/styles/source-presentation.d.ts.map +1 -1
  21. package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts +77 -0
  22. package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts.map +1 -0
  23. package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts +10 -1
  24. package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts.map +1 -1
  25. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mask-preparation.worker.js","sources":["../../core/dist/index.js","../src/render-preparation/mask-frame-compositor.ts","../src/render-preparation/mask-frame-artifact.ts","../src/render-preparation/mask-preparation-worker-protocol.ts","../src/render-preparation/mask-preparation.worker.ts"],"sourcesContent":["/** COCO-compatible keypoint visibility values. */\nvar 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 = {}));\nvar DetectionMaskEncoding;\n(function (DetectionMaskEncoding) {\n DetectionMaskEncoding[\"CompressedRle\"] = \"compressedRle\";\n})(DetectionMaskEncoding || (DetectionMaskEncoding = {}));\n\nvar 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 */\nvar 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 = {}));\nvar 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\nfunction copySortedDetectionFrames(detectionFrames) {\n validateDetectionFrames(detectionFrames ?? []);\n return (detectionFrames ?? [])\n .map((frame) => ({\n detections: frame.detections.map((detection) => ({\n ...detection,\n attributes: detection.attributes\n ? [...detection.attributes]\n : undefined,\n keypoints: detection.keypoints\n ? {\n edges: detection.keypoints.edges.map((edge) => [edge[0], edge[1]]),\n points: detection.keypoints.points.map((point) => ({ ...point })),\n visibility: detection.keypoints.visibility\n ? [...detection.keypoints.visibility]\n : undefined,\n }\n : undefined,\n mask: detection.mask ? { ...detection.mask } : undefined,\n metadata: detection.metadata\n ? copyDetectionMetadata(detection.metadata)\n : undefined,\n polygon: detection.polygon\n ? {\n points: detection.polygon.points.map((point) => ({ ...point })),\n }\n : undefined,\n polyline: detection.polyline\n ? {\n points: detection.polyline.points.map((point) => ({ ...point })),\n }\n : undefined,\n rect: detection.rect ? { ...detection.rect } : undefined,\n })),\n endTime: frame.endTime,\n frameIndex: frame.frameIndex,\n mediaTime: frame.mediaTime,\n }))\n .sort((left, right) => left.mediaTime - right.mediaTime);\n}\nfunction copyDetectionMetadata(metadata) {\n const clone = globalThis.structuredClone;\n if (clone) {\n return clone(metadata);\n }\n return copyMetadataValue(metadata);\n}\nfunction copyMetadataValue(value) {\n if (Array.isArray(value)) {\n return value.map(copyMetadataValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(Object.entries(value).map(([key, child]) => [\n key,\n copyMetadataValue(child),\n ]));\n }\n return value;\n}\nfunction validateDetectionFrames(detectionFrames) {\n for (const [frameOffset, frame] of detectionFrames.entries()) {\n validateNumber(frame.mediaTime, `frames[${frameOffset}].mediaTime`, {\n min: 0,\n });\n if (frame.endTime !== undefined) {\n validateNumber(frame.endTime, `frames[${frameOffset}].endTime`, {\n exclusiveMin: frame.mediaTime,\n });\n }\n if (frame.frameIndex !== undefined) {\n validateNumber(frame.frameIndex, `frames[${frameOffset}].frameIndex`, {\n integer: true,\n min: 0,\n });\n }\n for (const [detectionOffset, detection] of frame.detections.entries()) {\n const detectionPath = `frames[${frameOffset}].detections[${detectionOffset}]`;\n if (detection.confidence !== undefined) {\n validateNumber(detection.confidence, `${detectionPath}.confidence`, {\n max: 1,\n min: 0,\n });\n }\n if (detection.zIndex !== undefined) {\n validateNumber(detection.zIndex, `${detectionPath}.zIndex`);\n }\n if (detection.sourceId !== undefined &&\n typeof detection.sourceId !== \"string\") {\n throw new Error(`${detectionPath}.sourceId must be a string.`);\n }\n if (detection.sourceDetectionIndex !== undefined) {\n validateNumber(detection.sourceDetectionIndex, `${detectionPath}.sourceDetectionIndex`, {\n integer: true,\n min: 0,\n });\n }\n if (detection.rect) {\n validateNumber(detection.rect.x, `${detectionPath}.rect.x`);\n validateNumber(detection.rect.y, `${detectionPath}.rect.y`);\n validateNumber(detection.rect.width, `${detectionPath}.rect.width`, {\n exclusiveMin: 0,\n });\n validateNumber(detection.rect.height, `${detectionPath}.rect.height`, {\n exclusiveMin: 0,\n });\n }\n validatePoints(detection.polygon?.points, `${detectionPath}.polygon`, 3);\n validatePoints(detection.polyline?.points, `${detectionPath}.polyline`, 2);\n if (detection.keypoints) {\n validatePoints(detection.keypoints.points, `${detectionPath}.keypoints`, 1);\n if (detection.keypoints.visibility !== undefined &&\n detection.keypoints.visibility.length !==\n detection.keypoints.points.length) {\n throw new Error(`${detectionPath}.keypoints.visibility must match points length.`);\n }\n for (const [edgeOffset, edge] of detection.keypoints.edges.entries()) {\n const edgePath = `${detectionPath}.keypoints.edges[${edgeOffset}]`;\n for (const [endpointOffset, endpoint] of edge.entries()) {\n validateNumber(endpoint, `${edgePath}[${endpointOffset}]`, {\n integer: true,\n min: 0,\n });\n if (endpoint >= detection.keypoints.points.length) {\n throw new Error(`${edgePath}[${endpointOffset}] is out of range.`);\n }\n }\n }\n }\n if (detection.mask) {\n validateNumber(detection.mask.width, `${detectionPath}.mask.width`, {\n integer: true,\n exclusiveMin: 0,\n });\n validateNumber(detection.mask.height, `${detectionPath}.mask.height`, {\n integer: true,\n exclusiveMin: 0,\n });\n if (detection.mask.counts.length === 0) {\n throw new Error(`${detectionPath}.mask.counts must not be empty.`);\n }\n }\n }\n }\n}\nfunction validatePoints(points, path, minimumLength) {\n if (!points) {\n return;\n }\n if (points.length < minimumLength) {\n throw new Error(`${path}.points must contain at least ${minimumLength} points.`);\n }\n for (const [pointOffset, point] of points.entries()) {\n validateNumber(point.x, `${path}.points[${pointOffset}].x`);\n validateNumber(point.y, `${path}.points[${pointOffset}].y`);\n }\n}\nfunction validateNumber(value, path, options = {}) {\n if (!Number.isFinite(value)) {\n throw new Error(`${path} must be a finite number.`);\n }\n if (options.integer && !Number.isInteger(value)) {\n throw new Error(`${path} must be an integer.`);\n }\n if (options.min !== undefined && value < options.min) {\n throw new Error(`${path} must be greater than or equal to ${options.min}.`);\n }\n if (options.exclusiveMin !== undefined && value <= options.exclusiveMin) {\n throw new Error(`${path} must be greater than ${options.exclusiveMin}.`);\n }\n if (options.max !== undefined && value > options.max) {\n throw new Error(`${path} must be less than or equal to ${options.max}.`);\n }\n}\nfunction filterDetectionFramesForRange(detectionFrames, startTime, endTime) {\n return detectionFrames.filter((frame) => detectionFrameOverlapsRange(frame, startTime, endTime));\n}\nfunction selectDetectionFrame(detectionFrames, mediaTime, options = {}) {\n if (options.selectionMode === DetectionFrameSelectionMode.NearestFrameIndex) {\n const selection = selectNearestFrameIndexDetectionFrame(detectionFrames, mediaTime, options.frameRate, options.frameIndexOriginTime);\n if (selection.isApplicable) {\n return selection.frame;\n }\n }\n return selectIntervalDetectionFrame(detectionFrames, mediaTime);\n}\nfunction 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}\nfunction selectIntervalDetectionFrame(detectionFrames, mediaTime) {\n let selectedFrame;\n let low = 0;\n let high = detectionFrames.length - 1;\n while (low <= high) {\n const middle = Math.floor((low + high) / 2);\n const frame = detectionFrames[middle];\n if (frame.mediaTime <= mediaTime) {\n selectedFrame = frame;\n low = middle + 1;\n }\n else {\n high = middle - 1;\n }\n }\n return selectedFrame && isDetectionFrameActive(selectedFrame, mediaTime)\n ? selectedFrame\n : undefined;\n}\nfunction selectNearestFrameIndexDetectionFrame(detectionFrames, mediaTime, frameRate, frameIndexOriginTime) {\n if (!frameRate || !Number.isFinite(frameRate) || frameRate <= 0) {\n return { frame: undefined, isApplicable: false };\n }\n const firstIndexedFrame = detectionFrames.find((frame) => frame.frameIndex !== undefined);\n if (!firstIndexedFrame || firstIndexedFrame.frameIndex === undefined) {\n return { frame: undefined, isApplicable: false };\n }\n const originTime = frameIndexOriginTime !== undefined\n ? frameIndexOriginTime\n : firstIndexedFrame.mediaTime - firstIndexedFrame.frameIndex / frameRate;\n const targetFrameIndex = Math.round((mediaTime - originTime) * frameRate);\n let nearestFrame;\n let nearestDistance = Number.POSITIVE_INFINITY;\n for (const frame of detectionFrames) {\n if (frame.frameIndex === undefined) {\n continue;\n }\n const distance = Math.abs(frame.frameIndex - targetFrameIndex);\n if (distance < nearestDistance ||\n (distance === nearestDistance &&\n nearestFrame?.frameIndex !== undefined &&\n frame.frameIndex > nearestFrame.frameIndex)) {\n nearestFrame = frame;\n nearestDistance = distance;\n }\n }\n return {\n frame: nearestDistance <= 1 ? nearestFrame : undefined,\n isApplicable: true,\n };\n}\nfunction isDetectionFrameActive(frame, mediaTime) {\n return (frame.mediaTime <= mediaTime &&\n (frame.endTime === undefined || mediaTime < frame.endTime));\n}\nfunction detectionFrameOverlapsRange(frame, startTime, endTime) {\n if (frame.endTime === undefined) {\n return frame.mediaTime >= startTime && frame.mediaTime <= endTime;\n }\n return frame.mediaTime <= endTime && frame.endTime > startTime;\n}\nfunction 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}\nfunction 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\nfunction createArrayDetectionFrameSource(frames) {\n const sortedFrames = copySortedDetectionFrames(frames);\n return {\n async loadFrames(startTime, endTime) {\n return copySortedDetectionFrames(filterDetectionFramesForRange(sortedFrames, startTime, endTime));\n },\n };\n}\n\nconst DEFAULT_BUFFER_AHEAD_SECONDS = 5;\nconst DEFAULT_BUFFER_BEHIND_SECONDS = 0.5;\nconst bufferedFrameSnapshots = new WeakMap();\n/**\n * Returns the timeline-owned hot-buffer snapshot without copying it.\n *\n * This is an internal platform-adapter fast path. Public callers should use\n * `getBufferedFrames()`, which preserves the existing defensive-copy contract.\n */\nfunction getBufferedDetectionTimelineFrameSnapshot(timeline) {\n return (bufferedFrameSnapshots.get(timeline)?.() ?? timeline.getBufferedFrames());\n}\nfunction createBufferedDetectionTimeline(options) {\n const bufferAheadSeconds = options.bufferAheadSeconds ?? DEFAULT_BUFFER_AHEAD_SECONDS;\n const bufferBehindSeconds = options.bufferBehindSeconds ?? DEFAULT_BUFFER_BEHIND_SECONDS;\n const refreshIntervalSeconds = options.refreshIntervalSeconds === undefined\n ? null\n : Math.max(0, options.refreshIntervalSeconds);\n const playbackGate = options.playbackGate;\n let buffer = [];\n let state = createIdleDetectionBufferState();\n let destroyed = false;\n let loadId = 0;\n let bufferedSourceVersion = null;\n let bufferedVersionRange = null;\n let timelineContext = {\n duration: null,\n loop: false,\n };\n let inFlight;\n let incrementalRefresh;\n let pendingPrefetch;\n let prefetchPump;\n const getSourceVersion = (ranges) => {\n if (!ranges) {\n return options.source.getVersion?.() ?? 0;\n }\n return ranges.reduce((version, range) => Math.max(version, options.source.getVersion?.(range) ?? 0), 0);\n };\n const isBufferFresh = () => bufferedVersionRange !== null &&\n bufferedSourceVersion === getSourceVersion(getBufferedSourceRanges());\n const getLoadRange = (mediaTime) => {\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n const startTime = comparableMediaTime - bufferBehindSeconds;\n const endTime = comparableMediaTime + bufferAheadSeconds;\n return createLoadPlan(startTime, endTime);\n };\n const loadWindow = (mediaTime) => {\n const { endTime, sourceRanges, startTime } = getLoadRange(mediaTime);\n const versionRange = { endTime, startTime };\n const sourceVersion = getSourceVersion(sourceRanges);\n if (inFlight &&\n inFlight.sourceVersion === sourceVersion &&\n rangeContains(inFlight.startTime, inFlight.endTime, startTime, endTime)) {\n return inFlight.promise;\n }\n const currentLoadId = loadId + 1;\n loadId = currentLoadId;\n state = {\n ...state,\n errorMessage: null,\n requestedEndTime: endTime,\n requestedStartTime: startTime,\n status: DetectionBufferStatus.Loading,\n };\n const promise = Promise.all(sourceRanges.map((range) => options.source.loadFrames(range.startTime, range.endTime)))\n .then((frameRanges) => {\n if (destroyed || currentLoadId !== loadId) {\n return;\n }\n const committedSourceVersion = getSourceVersion(sourceRanges);\n const loadedBuffer = copySortedDetectionFrames(frameRanges.flat());\n buffer =\n bufferedSourceVersion !== null &&\n bufferedSourceVersion === committedSourceVersion\n ? reuseBufferedFrameSnapshots(buffer, loadedBuffer)\n : loadedBuffer;\n bufferedVersionRange = versionRange;\n bufferedSourceVersion = committedSourceVersion;\n state = {\n bufferEndTime: endTime,\n bufferStartTime: startTime,\n detectionCount: countDetections(buffer),\n errorMessage: null,\n frameCount: buffer.length,\n requestedEndTime: endTime,\n requestedStartTime: startTime,\n status: DetectionBufferStatus.Ready,\n };\n })\n .catch((error) => {\n if (!destroyed && currentLoadId === loadId) {\n state = {\n ...state,\n errorMessage: getErrorMessage(error),\n status: DetectionBufferStatus.Error,\n };\n }\n throw error;\n })\n .finally(() => {\n if (inFlight?.id === currentLoadId) {\n inFlight = undefined;\n }\n });\n inFlight = {\n endTime,\n id: currentLoadId,\n promise,\n sourceVersion,\n startTime,\n };\n return promise;\n };\n const isBuffered = (mediaTime) => {\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n return (isBufferFresh() &&\n state.bufferStartTime !== null &&\n state.bufferEndTime !== null &&\n comparableMediaTime >= state.bufferStartTime &&\n comparableMediaTime <= state.bufferEndTime);\n };\n const isInsideBufferedRange = (mediaTime) => {\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n return (bufferedVersionRange !== null &&\n state.bufferStartTime !== null &&\n state.bufferEndTime !== null &&\n comparableMediaTime >= state.bufferStartTime &&\n comparableMediaTime <= state.bufferEndTime);\n };\n const refreshBuffer = async (mediaTime) => {\n if (isBuffered(mediaTime)) {\n return;\n }\n if (isInsideBufferedRange(mediaTime) &&\n bufferedSourceVersion !== null &&\n options.source.getChangesSince) {\n if (!incrementalRefresh) {\n incrementalRefresh = applyIncrementalChanges().finally(() => {\n incrementalRefresh = undefined;\n });\n }\n await incrementalRefresh;\n if (isBuffered(mediaTime)) {\n return;\n }\n return refreshBuffer(mediaTime);\n }\n await loadWindow(mediaTime);\n };\n const shouldPrefetch = (mediaTime) => {\n if (!isBuffered(mediaTime)) {\n return true;\n }\n if (shouldRefreshRollingWindow(mediaTime)) {\n return true;\n }\n if (state.bufferEndTime === null || bufferAheadSeconds <= 0) {\n return false;\n }\n return (getComparableMediaTime(mediaTime) + bufferAheadSeconds / 2 >=\n state.bufferEndTime);\n };\n const timeline = {\n async prepare(mediaTime, prepareOptions) {\n if (destroyed) {\n return;\n }\n if (shouldWaitForPlaybackGate(prepareOptions)) {\n await waitForPlaybackGate(mediaTime, prepareOptions);\n if (destroyed) {\n return;\n }\n }\n await refreshBuffer(mediaTime);\n },\n prefetch(mediaTime) {\n if (destroyed || !shouldPrefetch(mediaTime)) {\n return;\n }\n pendingPrefetch = { loadId, mediaTime };\n pumpPrefetchQueue();\n },\n selectFrame(mediaTime) {\n if (!isBuffered(mediaTime)) {\n return undefined;\n }\n return selectDetectionFrame(buffer, getSourceMediaTime(mediaTime), options);\n },\n setTimelineContext(context) {\n timelineContext = context;\n bufferedSourceVersion = null;\n bufferedVersionRange = null;\n },\n getBufferedFrames() {\n return copySortedDetectionFrames(buffer);\n },\n getState() {\n return { ...state };\n },\n destroy() {\n if (destroyed) {\n return;\n }\n destroyed = true;\n pendingPrefetch = undefined;\n buffer = [];\n bufferedSourceVersion = null;\n bufferedVersionRange = null;\n state = {\n ...state,\n bufferEndTime: null,\n bufferStartTime: null,\n detectionCount: 0,\n frameCount: 0,\n status: DetectionBufferStatus.Destroyed,\n };\n options.source.destroy?.();\n },\n };\n bufferedFrameSnapshots.set(timeline, () => buffer);\n return timeline;\n function pumpPrefetchQueue() {\n if (destroyed || prefetchPump) {\n return;\n }\n prefetchPump = drainPrefetchQueue().finally(() => {\n prefetchPump = undefined;\n if (!destroyed && pendingPrefetch) {\n pumpPrefetchQueue();\n }\n });\n }\n async function drainPrefetchQueue() {\n while (!destroyed && pendingPrefetch) {\n if (inFlight) {\n await inFlight.promise.catch(() => undefined);\n continue;\n }\n const request = pendingPrefetch;\n pendingPrefetch = undefined;\n if (request.loadId !== loadId) {\n continue;\n }\n const { mediaTime } = request;\n if (!shouldPrefetch(mediaTime)) {\n continue;\n }\n await (shouldRefreshRollingWindow(mediaTime)\n ? loadWindow(mediaTime)\n : refreshBuffer(mediaTime)).catch(() => undefined);\n }\n }\n async function applyIncrementalChanges() {\n if (destroyed ||\n bufferedSourceVersion === null ||\n !options.source.getChangesSince) {\n return;\n }\n const sourceRanges = getBufferedSourceRanges();\n const incrementalLoadId = loadId;\n const incrementalVersionRange = bufferedVersionRange;\n const changes = options.source.getChangesSince(bufferedSourceVersion, sourceRanges);\n if (changes.requiresReload) {\n bufferedSourceVersion = null;\n return;\n }\n if (changes.ranges.length === 0) {\n bufferedSourceVersion = changes.version;\n return;\n }\n const changedRanges = getOverlappingRanges(changes.ranges, sourceRanges);\n if (changedRanges.length === 0) {\n bufferedSourceVersion = changes.version;\n return;\n }\n try {\n const changedFrameRanges = await Promise.all(changedRanges.map((range) => options.source.loadFrames(range.startTime, range.endTime)));\n if (destroyed ||\n loadId !== incrementalLoadId ||\n bufferedVersionRange !== incrementalVersionRange) {\n return;\n }\n buffer = mergeIncrementalFrames(buffer, changedFrameRanges.flat(), changedRanges);\n bufferedSourceVersion = changes.version;\n state = {\n ...state,\n detectionCount: countDetections(buffer),\n errorMessage: null,\n frameCount: buffer.length,\n status: DetectionBufferStatus.Ready,\n };\n }\n catch (error) {\n if (!destroyed) {\n state = {\n ...state,\n errorMessage: getErrorMessage(error),\n status: DetectionBufferStatus.Error,\n };\n }\n throw error;\n }\n }\n function shouldWaitForPlaybackGate(prepareOptions) {\n return (prepareOptions?.gatePlayback === true &&\n playbackGate?.enabled === true &&\n Boolean(options.source.waitForRange));\n }\n async function waitForPlaybackGate(mediaTime, prepareOptions) {\n if (!playbackGate?.enabled || !options.source.waitForRange) {\n return;\n }\n const requiredAheadSeconds = Math.max(0, playbackGate.requiredAheadSeconds ?? 0);\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n const endTime = getRequiredCoverageEndTime({\n duration: isLoopingTimeline() ? null : prepareOptions?.duration,\n firstTimestamp: prepareOptions?.firstTimestamp,\n mediaTime: comparableMediaTime,\n requiredAheadSeconds,\n });\n if (endTime <= comparableMediaTime) {\n return;\n }\n const coveragePlan = createLoadPlan(comparableMediaTime, endTime);\n state = {\n ...state,\n errorMessage: null,\n requestedEndTime: coveragePlan.endTime,\n requestedStartTime: coveragePlan.startTime,\n status: DetectionBufferStatus.Loading,\n };\n try {\n await Promise.all(coveragePlan.sourceRanges.map((range) => options.source.waitForRange?.(range)));\n }\n catch (error) {\n if (!destroyed) {\n state = {\n ...state,\n errorMessage: getErrorMessage(error),\n status: DetectionBufferStatus.Error,\n };\n }\n throw error;\n }\n }\n function shouldRefreshRollingWindow(mediaTime) {\n if (refreshIntervalSeconds === null ||\n refreshIntervalSeconds <= 0 ||\n state.bufferStartTime === null ||\n state.bufferEndTime === null) {\n return false;\n }\n const { endTime, startTime } = getLoadRange(mediaTime);\n return (Math.abs(startTime - state.bufferStartTime) >= refreshIntervalSeconds ||\n Math.abs(endTime - state.bufferEndTime) >= refreshIntervalSeconds);\n }\n function createLoadPlan(requestedStartTime, requestedEndTime) {\n const startTime = Math.min(requestedStartTime, requestedEndTime);\n const endTime = Math.max(startTime, requestedEndTime);\n if (!isLoopingTimeline()) {\n const clampedStartTime = Math.max(0, startTime);\n const clampedEndTime = Math.max(clampedStartTime, endTime);\n return {\n endTime: clampedEndTime,\n sourceRanges: [\n {\n endTime: clampedEndTime,\n startTime: clampedStartTime,\n },\n ],\n startTime: clampedStartTime,\n };\n }\n const duration = timelineContext.duration ?? 0;\n if (endTime - startTime >= duration) {\n return {\n endTime: duration,\n sourceRanges: [{ endTime: duration, startTime: 0 }],\n startTime: 0,\n };\n }\n return {\n endTime,\n sourceRanges: getLoopingSourceRanges(startTime, endTime, duration),\n startTime,\n };\n }\n function getBufferedSourceRanges() {\n if (!bufferedVersionRange) {\n return [];\n }\n return createLoadPlan(bufferedVersionRange.startTime, bufferedVersionRange.endTime).sourceRanges;\n }\n function isLoopingTimeline() {\n return (timelineContext.loop &&\n timelineContext.duration !== null &&\n timelineContext.duration > 0);\n }\n function getComparableMediaTime(mediaTime) {\n if (!isLoopingTimeline() ||\n state.bufferStartTime === null ||\n state.bufferEndTime === null ||\n timelineContext.duration === null) {\n return mediaTime;\n }\n const duration = timelineContext.duration;\n let comparableMediaTime = mediaTime;\n while (comparableMediaTime < state.bufferStartTime) {\n comparableMediaTime += duration;\n }\n while (comparableMediaTime > state.bufferEndTime) {\n comparableMediaTime -= duration;\n }\n return comparableMediaTime;\n }\n function getSourceMediaTime(mediaTime) {\n if (!isLoopingTimeline() || timelineContext.duration === null) {\n return mediaTime;\n }\n if (mediaTime >= 0 && mediaTime <= timelineContext.duration) {\n return mediaTime;\n }\n return modulo(mediaTime, timelineContext.duration);\n }\n}\nfunction createIdleDetectionBufferState() {\n return {\n bufferEndTime: null,\n bufferStartTime: null,\n detectionCount: 0,\n errorMessage: null,\n frameCount: 0,\n requestedEndTime: null,\n requestedStartTime: null,\n status: DetectionBufferStatus.Idle,\n };\n}\nfunction rangeContains(outerStart, outerEnd, innerStart, innerEnd) {\n return outerStart <= innerStart && innerEnd <= outerEnd;\n}\nfunction countDetections(frames) {\n return frames.reduce((total, frame) => total + frame.detections.length, 0);\n}\nfunction getErrorMessage(error) {\n return error instanceof Error\n ? error.message\n : \"Detection buffer load failed.\";\n}\nfunction getRequiredCoverageEndTime(options) {\n const requestedEndTime = options.mediaTime + options.requiredAheadSeconds;\n if (options.duration === null || options.duration === undefined) {\n return requestedEndTime;\n }\n return Math.min(requestedEndTime, (options.firstTimestamp ?? 0) + Math.max(options.duration, 0));\n}\nfunction getLoopingSourceRanges(startTime, endTime, duration) {\n const normalizedStartTime = modulo(startTime, duration);\n const normalizedEndTime = modulo(endTime, duration);\n const startCycle = Math.floor(startTime / duration);\n const endCycle = Math.floor(endTime / duration);\n if (startCycle === endCycle) {\n return [{ endTime: normalizedEndTime, startTime: normalizedStartTime }];\n }\n const ranges = [];\n if (normalizedStartTime < duration) {\n ranges.push({ endTime: duration, startTime: normalizedStartTime });\n }\n if (normalizedEndTime > 0) {\n ranges.push({ endTime: normalizedEndTime, startTime: 0 });\n }\n return ranges;\n}\nfunction modulo(value, modulus) {\n return ((value % modulus) + modulus) % modulus;\n}\nfunction getOverlappingRanges(changedRanges, bufferedRanges) {\n const intersections = [];\n for (const changedRange of changedRanges) {\n for (const bufferedRange of bufferedRanges) {\n const startTime = Math.max(changedRange.startTime, bufferedRange.startTime);\n const endTime = Math.min(changedRange.endTime, bufferedRange.endTime);\n if (startTime <= endTime) {\n intersections.push({ endTime, startTime });\n }\n }\n }\n return intersections;\n}\nfunction mergeIncrementalFrames(currentFrames, changedFrames, changedRanges) {\n const framesByIdentity = new Map();\n for (const frame of currentFrames) {\n if (changedRanges.some((range) => detectionFrameOverlapsRange(frame, range.startTime, range.endTime))) {\n continue;\n }\n framesByIdentity.set(getDetectionFrameIdentity(frame), frame);\n }\n for (const frame of changedFrames) {\n framesByIdentity.set(getDetectionFrameIdentity(frame), frame);\n }\n return Array.from(framesByIdentity.values()).sort(compareDetectionFrames);\n}\nfunction reuseBufferedFrameSnapshots(currentFrames, loadedFrames) {\n const currentFramesByIdentity = new Map(currentFrames.map((frame) => [getDetectionFrameIdentity(frame), frame]));\n return loadedFrames.map((frame) => currentFramesByIdentity.get(getDetectionFrameIdentity(frame)) ?? frame);\n}\nfunction getDetectionFrameIdentity(frame) {\n return frame.frameIndex === undefined\n ? `time:${frame.mediaTime}`\n : `index:${frame.frameIndex}`;\n}\nfunction compareDetectionFrames(left, right) {\n if (left.mediaTime !== right.mediaTime) {\n return left.mediaTime - right.mediaTime;\n }\n return (left.frameIndex ?? 0) - (right.frameIndex ?? 0);\n}\n\nfunction createColdDetectionFrameSource(options) {\n return {\n loadFrames(startTime, endTime) {\n return options.store.loadFrames({\n datasetId: options.datasetId,\n endTime,\n startTime,\n });\n },\n };\n}\n\nfunction createCompositeDetectionFrameSource(options) {\n const sources = normalizeCompositeSources(options.sources);\n return {\n async loadFrames(startTime, endTime) {\n const loadedSources = await Promise.all(sources.map(async (source) => ({\n ...source,\n frames: copySortedDetectionFrames(await source.source.loadFrames(startTime, endTime)),\n })));\n if (options.selectionMode === DetectionFrameSelectionMode.NearestFrameIndex) {\n const nearestFrames = composeNearestFrameIndexFrames(loadedSources, startTime, endTime, options);\n if (nearestFrames) {\n return nearestFrames;\n }\n }\n return composeIntervalFrames(loadedSources, startTime, endTime, options);\n },\n async waitForRange(range) {\n await Promise.all(sources\n .filter((source) => source.requiredForPlayback)\n .map((source) => source.source.waitForRange?.(range)));\n },\n getAvailableRanges() {\n return mergeRanges$1(sources.flatMap((source) => source.source.getAvailableRanges?.() ?? []));\n },\n getVersion(range) {\n return sources.reduce((version, source) => version + (source.source.getVersion?.(range) ?? 0), 0);\n },\n destroy() {\n for (const source of sources) {\n source.source.destroy?.();\n }\n },\n };\n}\nfunction normalizeCompositeSources(entries) {\n const sourceIds = new Set();\n return entries\n .map((entry, declarationIndex) => {\n if (sourceIds.has(entry.id)) {\n throw new Error(`Duplicate detection source id: ${entry.id}.`);\n }\n sourceIds.add(entry.id);\n const inputCount = [\n entry.frames !== undefined,\n entry.source !== undefined,\n ].filter(Boolean).length;\n if (inputCount !== 1) {\n throw new Error(`Detection source ${entry.id} must provide exactly one input: frames or source.`);\n }\n return {\n declarationIndex,\n id: entry.id,\n order: entry.order ?? 0,\n requiredForPlayback: entry.requiredForPlayback !== false,\n source: entry.source ?? createArrayDetectionFrameSource(entry.frames ?? []),\n sync: entry.sync,\n };\n })\n .sort((left, right) => left.order - right.order ||\n left.declarationIndex - right.declarationIndex);\n}\nfunction composeIntervalFrames(sources, startTime, endTime, options) {\n const boundaryTimes = new Set([startTime]);\n for (const source of sources) {\n for (const frame of source.frames) {\n if (frame.mediaTime >= startTime && frame.mediaTime < endTime) {\n boundaryTimes.add(frame.mediaTime);\n }\n if (frame.endTime !== undefined &&\n frame.endTime > startTime &&\n frame.endTime < endTime) {\n boundaryTimes.add(frame.endTime);\n }\n }\n }\n const sortedBoundaryTimes = [...boundaryTimes].sort((left, right) => left - right);\n const frames = [];\n for (const [boundaryIndex, mediaTime] of sortedBoundaryTimes.entries()) {\n if (mediaTime < startTime || mediaTime >= endTime) {\n continue;\n }\n const nextBoundaryTime = sortedBoundaryTimes[boundaryIndex + 1] ?? endTime;\n const endTimeForFrame = Math.min(nextBoundaryTime, endTime);\n const frame = composeFrameAtTime(sources, mediaTime, endTimeForFrame, {\n ...options,\n selectionMode: DetectionFrameSelectionMode.Interval,\n });\n if (frame) {\n frames.push(frame);\n }\n }\n return frames;\n}\nfunction composeNearestFrameIndexFrames(sources, startTime, endTime, options) {\n const frameRate = options.frameRate;\n if (!frameRate || !Number.isFinite(frameRate) || frameRate <= 0) {\n return null;\n }\n const indexedFrames = sources.flatMap((source) => source.frames.filter((frame) => frame.frameIndex !== undefined));\n const firstIndexedFrame = indexedFrames[0];\n if (!firstIndexedFrame || firstIndexedFrame.frameIndex === undefined) {\n return null;\n }\n const originTime = options.frameIndexOriginTime ??\n firstIndexedFrame.mediaTime - firstIndexedFrame.frameIndex / frameRate;\n const frameIndexes = [\n ...new Set(indexedFrames\n .map((frame) => frame.frameIndex)\n .filter((frameIndex) => frameIndex !== undefined)),\n ].sort((left, right) => left - right);\n const frames = [];\n for (const frameIndex of frameIndexes) {\n const mediaTime = originTime + frameIndex / frameRate;\n if (mediaTime < startTime || mediaTime >= endTime) {\n continue;\n }\n const frame = composeFrameAtTime(sources, mediaTime, Math.min(mediaTime + 1 / frameRate, endTime), {\n ...options,\n selectionMode: DetectionFrameSelectionMode.NearestFrameIndex,\n }, frameIndex);\n if (frame) {\n frames.push(frame);\n }\n }\n return frames;\n}\nfunction composeFrameAtTime(sources, mediaTime, endTime, options, frameIndex) {\n const detections = [];\n const activeFrameIndexes = [];\n for (const source of sources) {\n const activeFrame = selectDetectionFrame(source.frames, mediaTime, {\n ...options,\n ...source.sync,\n });\n if (!activeFrame) {\n continue;\n }\n if (activeFrame.frameIndex !== undefined) {\n activeFrameIndexes.push(activeFrame.frameIndex);\n }\n activeFrame.detections.forEach((detection, sourceDetectionIndex) => {\n detections.push(copyDetectionWithSource(detection, source.id, sourceDetectionIndex));\n });\n }\n if (detections.length === 0) {\n return undefined;\n }\n return {\n detections,\n endTime,\n frameIndex: frameIndex ?? resolveComposedFrameIndex(activeFrameIndexes) ?? undefined,\n mediaTime,\n };\n}\nfunction copyDetectionWithSource(detection, sourceId, sourceDetectionIndex) {\n return {\n ...detection,\n mask: detection.mask ? { ...detection.mask } : undefined,\n metadata: detection.metadata ? { ...detection.metadata } : undefined,\n rect: detection.rect ? { ...detection.rect } : undefined,\n sourceDetectionIndex,\n sourceId,\n };\n}\nfunction resolveComposedFrameIndex(frameIndexes) {\n if (frameIndexes.length === 0) {\n return undefined;\n }\n const firstFrameIndex = frameIndexes[0];\n return frameIndexes.every((frameIndex) => frameIndex === firstFrameIndex)\n ? firstFrameIndex\n : undefined;\n}\nfunction mergeRanges$1(ranges) {\n const sortedRanges = [...ranges].sort((left, right) => left.startTime - right.startTime);\n const mergedRanges = [];\n for (const range of sortedRanges) {\n const lastRange = mergedRanges.at(-1);\n if (!lastRange || range.startTime > lastRange.endTime) {\n mergedRanges.push({ ...range });\n continue;\n }\n mergedRanges[mergedRanges.length - 1] = {\n startTime: lastRange.startTime,\n endTime: Math.max(lastRange.endTime, range.endTime),\n };\n }\n return mergedRanges;\n}\n\nvar 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 = {}));\nfunction createEditableAnnotationFrameSession(initialFrame) {\n let snapshot = createSnapshot(initialFrame);\n let destroyed = false;\n const listeners = new Set();\n assertStableIds(snapshot);\n const commit = (frame, kind, detectionIds) => {\n assertActive();\n const previous = snapshot;\n const current = createSnapshot(frame);\n assertStableIds(current);\n snapshot = current;\n const mutation = Object.freeze({\n current,\n detectionIds: Object.freeze([...detectionIds]),\n kind,\n previous,\n });\n for (const listener of listeners) {\n listener(mutation);\n }\n return current;\n };\n const session = {\n getSnapshot() {\n assertActive();\n return snapshot;\n },\n add(detection, index = snapshot.detections.length) {\n assertActive();\n const id = requireDetectionId(detection);\n if (findDetectionIndex(snapshot, id) !== -1) {\n throw new Error(`Detection id ${String(id)} already exists.`);\n }\n const detections = [...snapshot.detections];\n const insertionIndex = Math.max(0, Math.min(index, detections.length));\n detections.splice(insertionIndex, 0, detection);\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Add, [id]);\n },\n update(id, update) {\n assertActive();\n const detectionIndex = findDetectionIndex(snapshot, id);\n if (detectionIndex === -1) {\n throw new Error(`Detection id ${String(id)} was not found.`);\n }\n const detections = [...snapshot.detections];\n const current = detections[detectionIndex];\n const next = typeof update === \"function\"\n ? update(current)\n : { ...current, ...update };\n if (next.id !== id) {\n throw new Error(\"Detection updates must preserve the stable id.\");\n }\n detections[detectionIndex] = next;\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Update, [id]);\n },\n remove(id) {\n assertActive();\n const detectionIndex = findDetectionIndex(snapshot, id);\n if (detectionIndex === -1) {\n return snapshot;\n }\n const detections = [...snapshot.detections];\n detections.splice(detectionIndex, 1);\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Remove, [id]);\n },\n replace(frame) {\n return commit(frame, AnnotationFrameMutationKind.Replace, frame.detections.map(requireDetectionId));\n },\n transact(mutate, detectionIds = []) {\n assertActive();\n const detections = copySortedDetectionFrames([snapshot])[0]\n .detections;\n mutate(detections);\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Transact, detectionIds);\n },\n subscribe(listener) {\n assertActive();\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n destroy() {\n destroyed = true;\n listeners.clear();\n },\n };\n return session;\n function assertActive() {\n if (destroyed) {\n throw new Error(\"Editable annotation frame session has been destroyed.\");\n }\n }\n}\nfunction findDetectionIndex(frame, id) {\n return frame.detections.findIndex((detection) => detection.id === id);\n}\nfunction requireDetectionId(detection) {\n if (detection.id === undefined) {\n throw new Error(\"Editable annotation detections require a stable id.\");\n }\n return detection.id;\n}\nfunction assertStableIds(frame) {\n const ids = new Set();\n for (const detection of frame.detections) {\n const id = requireDetectionId(detection);\n if (ids.has(id)) {\n throw new Error(`Detection id ${String(id)} is duplicated.`);\n }\n ids.add(id);\n }\n}\nfunction createSnapshot(frame) {\n const snapshot = copySortedDetectionFrames([frame])[0];\n return deepFreeze(snapshot);\n}\nfunction deepFreeze(value) {\n if (value && typeof value === \"object\" && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const nested of Object.values(value)) {\n deepFreeze(nested);\n }\n }\n return value;\n}\n\nconst DEFAULT_CHUNK_DURATION_SECONDS = 1;\nfunction createMemoryColdDetectionFrameStore() {\n const datasets = new Map();\n let destroyed = false;\n return {\n async putFrames(options) {\n assertActive();\n const dataset = createDataset(resolveChunkDurationSeconds(options));\n upsertFrames(dataset, copySortedDetectionFrames(options.frames));\n datasets.set(options.datasetId, dataset);\n return createWriteSummary(options.datasetId, dataset);\n },\n async appendFrames(options) {\n assertActive();\n const existingDataset = datasets.get(options.datasetId);\n const chunkDurationSeconds = resolveChunkDurationSeconds(options, existingDataset);\n const dataset = existingDataset ?? createDataset(chunkDurationSeconds);\n upsertFrames(dataset, copySortedDetectionFrames(options.frames));\n datasets.set(options.datasetId, dataset);\n return createWriteSummary(options.datasetId, dataset);\n },\n async loadFrames(options) {\n assertActive();\n const dataset = datasets.get(options.datasetId);\n if (!dataset) {\n return [];\n }\n const startTime = Math.max(0, options.startTime);\n const endTime = Math.max(startTime, options.endTime);\n const frameKeys = new Set();\n const startChunkIndex = getChunkIndex(startTime, dataset.chunkDurationSeconds);\n const endChunkIndex = getChunkIndex(endTime, dataset.chunkDurationSeconds);\n for (let chunkIndex = startChunkIndex; chunkIndex <= endChunkIndex; chunkIndex += 1) {\n for (const frameKey of dataset.frameKeysByChunk.get(chunkIndex) ?? []) {\n frameKeys.add(frameKey);\n }\n }\n const frames = Array.from(frameKeys)\n .map((frameKey) => dataset.framesByKey.get(frameKey)?.frame)\n .filter((frame) => frame !== undefined &&\n detectionFrameOverlapsRange(frame, startTime, endTime));\n return copySortedDetectionFrames(frames);\n },\n async clearDataset(datasetId) {\n assertActive();\n datasets.delete(datasetId);\n },\n destroy() {\n destroyed = true;\n datasets.clear();\n },\n };\n function assertActive() {\n if (destroyed) {\n throw new Error(\"Memory cold detection frame store has been destroyed.\");\n }\n }\n}\nfunction createDataset(chunkDurationSeconds) {\n return {\n chunkDurationSeconds,\n detectionCount: 0,\n endTime: null,\n frameKeysByChunk: new Map(),\n framesByKey: new Map(),\n startTime: null,\n };\n}\nfunction upsertFrames(dataset, frames) {\n let shouldRecalculateBounds = false;\n for (const frame of frames) {\n const frameKey = getDetectionFrameDedupeKey(frame);\n const existingFrame = dataset.framesByKey.get(frameKey);\n if (existingFrame) {\n removeStoredFrame(dataset, frameKey, existingFrame);\n shouldRecalculateBounds ||= replacementCanShrinkBounds(dataset, existingFrame.frame, frame);\n }\n const chunkIndexes = getFrameChunkIndexes(frame, dataset.chunkDurationSeconds);\n dataset.framesByKey.set(frameKey, { chunkIndexes, frame });\n dataset.detectionCount += frame.detections.length;\n dataset.startTime = Math.min(dataset.startTime ?? frame.mediaTime, frame.mediaTime);\n dataset.endTime = Math.max(dataset.endTime ?? getFrameEndTime(frame), getFrameEndTime(frame));\n for (const chunkIndex of chunkIndexes) {\n const frameKeys = dataset.frameKeysByChunk.get(chunkIndex) ?? new Set();\n frameKeys.add(frameKey);\n dataset.frameKeysByChunk.set(chunkIndex, frameKeys);\n }\n }\n if (shouldRecalculateBounds) {\n recalculateBounds(dataset);\n }\n}\nfunction removeStoredFrame(dataset, frameKey, storedFrame) {\n dataset.framesByKey.delete(frameKey);\n dataset.detectionCount -= storedFrame.frame.detections.length;\n for (const chunkIndex of storedFrame.chunkIndexes) {\n const frameKeys = dataset.frameKeysByChunk.get(chunkIndex);\n frameKeys?.delete(frameKey);\n if (frameKeys?.size === 0) {\n dataset.frameKeysByChunk.delete(chunkIndex);\n }\n }\n}\nfunction replacementCanShrinkBounds(dataset, previousFrame, nextFrame) {\n return ((dataset.startTime === previousFrame.mediaTime &&\n nextFrame.mediaTime > previousFrame.mediaTime) ||\n (dataset.endTime === getFrameEndTime(previousFrame) &&\n getFrameEndTime(nextFrame) < getFrameEndTime(previousFrame)));\n}\nfunction recalculateBounds(dataset) {\n let startTime = null;\n let endTime = null;\n for (const { frame } of dataset.framesByKey.values()) {\n startTime = Math.min(startTime ?? frame.mediaTime, frame.mediaTime);\n endTime = Math.max(endTime ?? getFrameEndTime(frame), getFrameEndTime(frame));\n }\n dataset.startTime = startTime;\n dataset.endTime = endTime;\n}\nfunction resolveChunkDurationSeconds(options, existingDataset) {\n const chunkDurationSeconds = options.chunkDurationSeconds ??\n existingDataset?.chunkDurationSeconds ??\n DEFAULT_CHUNK_DURATION_SECONDS;\n if (chunkDurationSeconds <= 0) {\n throw new Error(\"chunkDurationSeconds must be greater than 0.\");\n }\n if (existingDataset &&\n options.chunkDurationSeconds !== undefined &&\n options.chunkDurationSeconds !== existingDataset.chunkDurationSeconds) {\n throw new Error(\"chunkDurationSeconds must match the existing detection dataset.\");\n }\n return chunkDurationSeconds;\n}\nfunction createWriteSummary(datasetId, dataset) {\n return {\n chunkCount: dataset.frameKeysByChunk.size,\n chunkDurationSeconds: dataset.chunkDurationSeconds,\n datasetId,\n detectionCount: dataset.detectionCount,\n endTime: dataset.endTime,\n frameCount: dataset.framesByKey.size,\n startTime: dataset.startTime,\n };\n}\nfunction getFrameChunkIndexes(frame, chunkDurationSeconds) {\n const startIndex = getChunkIndex(frame.mediaTime, chunkDurationSeconds);\n const endIndex = Math.max(startIndex, Math.ceil(getFrameEndTime(frame) / chunkDurationSeconds) - 1);\n return Array.from({ length: endIndex - startIndex + 1 }, (_, offset) => startIndex + offset);\n}\nfunction getFrameEndTime(frame) {\n return frame.endTime ?? frame.mediaTime;\n}\nfunction getChunkIndex(mediaTime, chunkDurationSeconds) {\n return Math.floor(mediaTime / chunkDurationSeconds);\n}\nfunction getDetectionFrameDedupeKey(frame) {\n return frame.frameIndex === undefined\n ? `time:${frame.mediaTime}`\n : `index:${frame.frameIndex}`;\n}\n\nconst RANGE_EPSILON_SECONDS = 1e-6;\nconst MAX_CHANGED_RANGE_JOURNAL_LENGTH = 512;\nfunction createWritableDetectionFrameSource(options) {\n let summary = null;\n let version = 0;\n let allRangeVersion = 0;\n let journalFloorVersion = 0;\n let destroyed = false;\n const changedRanges = [];\n const availableRanges = [];\n const waiters = [];\n const writeOptions = (frames) => ({\n chunkDurationSeconds: options.chunkDurationSeconds,\n datasetId: options.datasetId,\n frames,\n });\n const recordRangeWrite = (nextSummary, changedSourceRanges) => {\n summary = nextSummary;\n version += 1;\n for (const changedRange of changedSourceRanges) {\n changedRanges.push({ ...changedRange, version });\n recordAvailableRange(changedRange, availableRanges);\n }\n compactChangedRangeJournal();\n resolveCoveredWaiters();\n return nextSummary;\n };\n const recordAllRangesWrite = (nextSummary) => {\n summary = nextSummary;\n version += 1;\n allRangeVersion = version;\n journalFloorVersion = version;\n changedRanges.length = 0;\n availableRanges.length = 0;\n if (nextSummary.startTime !== null && nextSummary.endTime !== null) {\n recordAvailableRange({\n endTime: nextSummary.endTime,\n startTime: nextSummary.startTime,\n }, availableRanges);\n }\n resolveCoveredWaiters();\n return nextSummary;\n };\n return {\n datasetId: options.datasetId,\n async appendFrames(frames) {\n assertActive();\n const nextSummary = await options.store.appendFrames(writeOptions(frames));\n assertActive();\n const changedSourceRanges = getDetectionFrameRanges(frames);\n const retainedSummary = await applyRetention(nextSummary);\n assertActive();\n if (retainedSummary !== nextSummary) {\n return recordAllRangesWrite(retainedSummary);\n }\n if (changedSourceRanges.length === 0) {\n summary = nextSummary;\n return nextSummary;\n }\n return recordRangeWrite(nextSummary, changedSourceRanges);\n },\n async replaceFrames(frames) {\n assertActive();\n const nextSummary = await options.store.putFrames(writeOptions(frames));\n assertActive();\n const retainedSummary = await applyRetention(nextSummary);\n assertActive();\n return recordAllRangesWrite(retainedSummary);\n },\n async clear() {\n assertActive();\n await options.store.clearDataset(options.datasetId);\n assertActive();\n summary = null;\n version += 1;\n allRangeVersion = version;\n journalFloorVersion = version;\n changedRanges.length = 0;\n availableRanges.length = 0;\n },\n async loadFrames(startTime, endTime) {\n assertActive();\n const loadedFrames = await options.store.loadFrames({\n datasetId: options.datasetId,\n endTime,\n startTime,\n });\n assertActive();\n return loadedFrames;\n },\n getSummary() {\n return summary ? { ...summary } : null;\n },\n getAvailableRanges() {\n return availableRanges.map((range) => ({ ...range }));\n },\n waitForRange(range) {\n if (destroyed) {\n return Promise.reject(createDestroyedError());\n }\n if (isRangeCovered(range, availableRanges)) {\n return Promise.resolve();\n }\n return new Promise((resolve, reject) => {\n waiters.push({ range, reject, resolve });\n });\n },\n getVersion(range) {\n if (!range) {\n return version;\n }\n return changedRanges.reduce((rangeVersion, changedRange) => rangesOverlap(range, changedRange)\n ? Math.max(rangeVersion, changedRange.version)\n : rangeVersion, Math.max(allRangeVersion, journalFloorVersion));\n },\n getChangesSince(previousVersion, ranges) {\n const relevantVersion = ranges.reduce((rangeVersion, range) => Math.max(rangeVersion, changedRanges.reduce((changedVersion, changedRange) => rangesOverlap(range, changedRange)\n ? Math.max(changedVersion, changedRange.version)\n : changedVersion, Math.max(allRangeVersion, journalFloorVersion))), Math.max(allRangeVersion, journalFloorVersion));\n if (relevantVersion <= previousVersion) {\n return {\n ranges: [],\n requiresReload: false,\n version: relevantVersion,\n };\n }\n if (previousVersion < allRangeVersion ||\n previousVersion < journalFloorVersion) {\n return {\n ranges: [],\n requiresReload: true,\n version: relevantVersion,\n };\n }\n const changedSourceRanges = changedRanges\n .filter((changedRange) => changedRange.version > previousVersion &&\n ranges.some((range) => rangesOverlap(range, changedRange)))\n .map(({ endTime, startTime }) => ({ endTime, startTime }));\n return {\n ranges: mergeRanges(changedSourceRanges),\n requiresReload: false,\n version: relevantVersion,\n };\n },\n destroy() {\n if (destroyed) {\n return;\n }\n destroyed = true;\n for (const waiter of waiters) {\n waiter.reject(new Error(\"Detection frame source has been destroyed.\"));\n }\n waiters.length = 0;\n options.store.destroy?.();\n },\n };\n function assertActive() {\n if (destroyed) {\n throw createDestroyedError();\n }\n }\n async function applyRetention(nextSummary) {\n const retention = options.retention;\n if (retention === undefined ||\n !shouldApplyWindowRetention(retention) ||\n nextSummary.endTime === null) {\n return nextSummary;\n }\n const retentionWindowSeconds = retention.windowSeconds;\n if (retentionWindowSeconds === undefined ||\n !Number.isFinite(retentionWindowSeconds) ||\n retentionWindowSeconds <= 0) {\n throw new Error(\"retention.windowSeconds must be greater than 0.\");\n }\n const retentionStartTime = Math.max(0, nextSummary.endTime - retentionWindowSeconds);\n if (nextSummary.startTime !== null &&\n nextSummary.startTime + RANGE_EPSILON_SECONDS >= retentionStartTime) {\n return nextSummary;\n }\n const retainedFrames = await options.store.loadFrames({\n datasetId: options.datasetId,\n endTime: nextSummary.endTime,\n startTime: retentionStartTime,\n });\n return options.store.putFrames(writeOptions(retainedFrames));\n }\n function resolveCoveredWaiters() {\n for (let index = waiters.length - 1; index >= 0; index -= 1) {\n const waiter = waiters[index];\n if (!waiter || !isRangeCovered(waiter.range, availableRanges)) {\n continue;\n }\n waiters.splice(index, 1);\n waiter.resolve();\n }\n }\n function compactChangedRangeJournal() {\n const overflow = changedRanges.length - MAX_CHANGED_RANGE_JOURNAL_LENGTH;\n if (overflow <= 0) {\n return;\n }\n const removedRanges = changedRanges.splice(0, overflow);\n journalFloorVersion = Math.max(journalFloorVersion, removedRanges.at(-1)?.version ?? 0);\n }\n}\nfunction createDestroyedError() {\n return new Error(\"Detection frame source has been destroyed.\");\n}\nfunction shouldApplyWindowRetention(retention) {\n return (retention?.mode === DetectionFrameRetentionMode.PersistWindow ||\n retention?.mode === DetectionFrameRetentionMode.MemoryOnly);\n}\nfunction getDetectionFrameRanges(frames) {\n return mergeRanges(frames.map((frame) => ({\n endTime: frame.endTime ?? frame.mediaTime,\n startTime: frame.mediaTime,\n })));\n}\nfunction rangesOverlap(left, right) {\n return left.startTime <= right.endTime && right.startTime <= left.endTime;\n}\nfunction mergeRanges(ranges) {\n const sortedRanges = ranges\n .map((range) => ({ ...range }))\n .sort((left, right) => left.startTime - right.startTime);\n const mergedRanges = [];\n for (const range of sortedRanges) {\n const previousRange = mergedRanges.at(-1);\n if (previousRange &&\n range.startTime <= previousRange.endTime + RANGE_EPSILON_SECONDS) {\n previousRange.endTime = Math.max(previousRange.endTime, range.endTime);\n continue;\n }\n mergedRanges.push({ ...range });\n }\n return mergedRanges;\n}\nfunction recordAvailableRange(range, availableRanges) {\n if (range.endTime < range.startTime) {\n return;\n }\n availableRanges.push({ ...range });\n availableRanges.sort((left, right) => left.startTime - right.startTime);\n let writeIndex = 0;\n for (const nextRange of availableRanges) {\n const currentRange = availableRanges[writeIndex - 1];\n if (currentRange &&\n nextRange.startTime <= currentRange.endTime + RANGE_EPSILON_SECONDS) {\n currentRange.endTime = Math.max(currentRange.endTime, nextRange.endTime);\n continue;\n }\n availableRanges[writeIndex] = { ...nextRange };\n writeIndex += 1;\n }\n availableRanges.length = writeIndex;\n}\nfunction isRangeCovered(range, availableRanges) {\n return availableRanges.some((availableRange) => availableRange.startTime <= range.startTime + RANGE_EPSILON_SECONDS &&\n availableRange.endTime + RANGE_EPSILON_SECONDS >= range.endTime);\n}\n\nvar 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 = {}));\nvar MediaInteractionMode;\n(function (MediaInteractionMode) {\n MediaInteractionMode[\"Always\"] = \"always\";\n MediaInteractionMode[\"Disabled\"] = \"disabled\";\n MediaInteractionMode[\"PausedOnly\"] = \"pausedOnly\";\n})(MediaInteractionMode || (MediaInteractionMode = {}));\n\nfunction 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}\nfunction topLeftRectToCenterRect(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}\nfunction 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}\nfunction getDetectionRect(detection) {\n return (detection.rect ??\n getPointsRect(detection.polygon?.points ?? []) ??\n getPointsRect(detection.polyline?.points ?? []) ??\n getPointsRect(detection.keypoints?.points ?? []));\n}\nfunction containsPoint(rect, point, padding = 0) {\n const halfWidth = rect.width / 2;\n const halfHeight = rect.height / 2;\n return (point.x >= rect.x - halfWidth - padding &&\n point.x <= rect.x + halfWidth + padding &&\n point.y >= rect.y - halfHeight - padding &&\n point.y <= rect.y + halfHeight + padding);\n}\nfunction pointInPolygon(point, polygon) {\n if (polygon.length < 3) {\n return false;\n }\n let inside = false;\n for (let currentIndex = 0, previousIndex = polygon.length - 1; currentIndex < polygon.length; previousIndex = currentIndex, currentIndex += 1) {\n const current = polygon[currentIndex];\n const previous = polygon[previousIndex];\n const crossesRay = current.y > point.y !== previous.y > point.y &&\n point.x <\n ((previous.x - current.x) * (point.y - current.y)) /\n (previous.y - current.y) +\n current.x;\n if (crossesRay) {\n inside = !inside;\n }\n }\n return inside;\n}\nfunction distanceToSegment(point, start, end) {\n const deltaX = end.x - start.x;\n const deltaY = end.y - start.y;\n const lengthSquared = deltaX * deltaX + deltaY * deltaY;\n if (lengthSquared === 0) {\n return Math.hypot(point.x - start.x, point.y - start.y);\n }\n const projection = Math.max(0, Math.min(1, ((point.x - start.x) * deltaX + (point.y - start.y) * deltaY) /\n lengthSquared));\n const closestX = start.x + projection * deltaX;\n const closestY = start.y + projection * deltaY;\n return Math.hypot(point.x - closestX, point.y - closestY);\n}\nfunction polygonArea(points) {\n if (points.length < 3) {\n return 0;\n }\n let twiceArea = 0;\n for (let index = 0; index < points.length; index += 1) {\n const current = points[index];\n const next = points[(index + 1) % points.length];\n twiceArea += current.x * next.y - next.x * current.y;\n }\n return Math.abs(twiceArea) / 2;\n}\nfunction rectArea(rect) {\n return rect ? Math.max(0, rect.width) * Math.max(0, rect.height) : 0;\n}\n\nconst decodedMaskCache = new WeakMap();\nfunction pickDetectionAtPoint(frame, point, options = {}) {\n if (!frame) {\n return null;\n }\n const padding = Math.max(0, options.padding ?? 0);\n const polylinePadding = Math.max(0, options.polylinePadding ?? 6);\n const keypointPadding = Math.max(0, options.keypointPadding ?? 10);\n const edgePadding = Math.max(0, options.edgePadding ?? 8);\n const candidates = [];\n for (let detectionIndex = 0; detectionIndex < frame.detections.length; detectionIndex += 1) {\n const detection = frame.detections[detectionIndex];\n if (!detection ||\n (detection.locked && options.includeLocked === false) ||\n options.filter?.(detection, detectionIndex) === false) {\n continue;\n }\n const detectionArea = Math.max(1, rectArea(getDetectionRect(detection)));\n const pushCandidate = (target, area = detectionArea, geometryIndex) => {\n candidates.push({\n area,\n priority: getPickTargetPriority(target),\n result: {\n detection,\n detectionIndex,\n frame,\n geometryIndex,\n mediaTime: frame.mediaTime,\n point,\n target,\n },\n zIndex: detection.zIndex ?? detectionIndex,\n });\n };\n if (detection.rect && containsPoint(detection.rect, point, padding)) {\n pushCandidate(DetectionPickTarget.Box, rectArea(detection.rect));\n }\n if (detection.polygon && pointInPolygon(point, detection.polygon.points)) {\n pushCandidate(DetectionPickTarget.Polygon, Math.max(1, polygonArea(detection.polygon.points)));\n }\n if (detection.polyline) {\n const segmentIndex = findHitSegment(point, detection.polyline.points, polylinePadding);\n if (segmentIndex !== -1) {\n pushCandidate(DetectionPickTarget.Polyline, detectionArea, segmentIndex);\n }\n }\n if (detection.keypoints) {\n const keypointIndex = detection.keypoints.points.findIndex((keypoint, index) => detection.keypoints?.visibility?.[index] !==\n KeypointVisibility.NotLabeled &&\n Math.hypot(point.x - keypoint.x, point.y - keypoint.y) <=\n keypointPadding);\n if (keypointIndex !== -1) {\n pushCandidate(DetectionPickTarget.Keypoint, Math.PI * keypointPadding * keypointPadding, keypointIndex);\n }\n else {\n const edgeIndex = detection.keypoints.edges.findIndex(([fromIndex, toIndex]) => {\n const from = detection.keypoints?.points[fromIndex];\n const to = detection.keypoints?.points[toIndex];\n return Boolean(from &&\n to &&\n detection.keypoints?.visibility?.[fromIndex] !==\n KeypointVisibility.NotLabeled &&\n detection.keypoints?.visibility?.[toIndex] !==\n KeypointVisibility.NotLabeled &&\n distanceToSegment(point, from, to) <= edgePadding);\n });\n if (edgeIndex !== -1) {\n const [fromIndex, toIndex] = detection.keypoints.edges[edgeIndex];\n const from = detection.keypoints.points[fromIndex];\n const to = detection.keypoints.points[toIndex];\n const edgeArea = Math.max(1, Math.hypot(to.x - from.x, to.y - from.y) * edgePadding * 2);\n pushCandidate(DetectionPickTarget.Edge, edgeArea, edgeIndex);\n }\n }\n }\n if (detection.mask && options.includeMasks !== false) {\n const decoded = getDecodedMask(detection.mask);\n const mediaDimensions = options.maskMediaDimensions;\n const x = Math.floor(mediaDimensions && mediaDimensions.width > 0\n ? (point.x / mediaDimensions.width) * decoded.width\n : point.x);\n const y = Math.floor(mediaDimensions && mediaDimensions.height > 0\n ? (point.y / mediaDimensions.height) * decoded.height\n : point.y);\n if (x >= 0 &&\n y >= 0 &&\n x < decoded.width &&\n y < decoded.height &&\n decoded.data[y * decoded.width + x]) {\n pushCandidate(DetectionPickTarget.Mask, getMaskMediaArea(decoded, mediaDimensions));\n }\n }\n }\n candidates.sort((left, right) => {\n const priorityDifference = left.priority - right.priority;\n if (priorityDifference !== 0) {\n return priorityDifference;\n }\n const areaDifference = left.area - right.area;\n if (areaDifference !== 0) {\n return areaDifference;\n }\n const zIndexDifference = right.zIndex - left.zIndex;\n return zIndexDifference === 0\n ? right.result.detectionIndex - left.result.detectionIndex\n : zIndexDifference;\n });\n return candidates[0]?.result ?? null;\n}\nfunction getPickTargetPriority(target) {\n switch (target) {\n case DetectionPickTarget.Keypoint:\n return 0;\n case DetectionPickTarget.Edge:\n case DetectionPickTarget.Polyline:\n return 1;\n default:\n return 2;\n }\n}\nfunction getDecodedMask(mask) {\n const cached = decodedMaskCache.get(mask);\n if (cached)\n return cached;\n const decoded = decodeCompressedRleMask(mask);\n const result = {\n ...decoded,\n pixelArea: countMaskPixels(decoded.data),\n };\n decodedMaskCache.set(mask, result);\n return result;\n}\nfunction getMaskMediaArea(mask, mediaDimensions) {\n if (!mediaDimensions ||\n mediaDimensions.width <= 0 ||\n mediaDimensions.height <= 0) {\n return mask.pixelArea;\n }\n return (mask.pixelArea *\n (mediaDimensions.width / mask.width) *\n (mediaDimensions.height / mask.height));\n}\nfunction createDetectionPickKey(pick) {\n if (!pick) {\n return null;\n }\n const frameKey = [pick.frame.frameIndex ?? \"time\", pick.frame.mediaTime];\n const detectionKey = detectionPickKey(pick);\n return [\n ...frameKey,\n ...detectionKey,\n pick.target,\n pick.geometryIndex ?? \"geometry\",\n ].join(\":\");\n}\nfunction rebaseDetectionPickToFrame(pick, frame) {\n if (!pick || !frame) {\n return null;\n }\n const detectionIndex = pick.detection.id === undefined ||\n !hasUniqueDetectionId(pick.frame, pick.detection.id)\n ? pick.detectionIndex\n : frame.detections.findIndex((detection) => detection.id === pick.detection.id);\n const detection = frame.detections[detectionIndex];\n if (!detection) {\n return null;\n }\n const rebasedPick = {\n detection,\n detectionIndex,\n frame,\n geometryIndex: pick.geometryIndex,\n mediaTime: frame.mediaTime,\n point: pick.point,\n target: pick.target,\n };\n return createDetectionPickKey(rebasedPick) === createDetectionPickKey(pick)\n ? rebasedPick\n : null;\n}\nfunction detectionPickKey(pick) {\n if (pick.detection.id === undefined) {\n return [\"anonymous\", pick.detectionIndex];\n }\n return hasUniqueDetectionId(pick.frame, pick.detection.id)\n ? [\"id\", String(pick.detection.id)]\n : [\"duplicate-id\", String(pick.detection.id), \"index\", pick.detectionIndex];\n}\nfunction hasUniqueDetectionId(frame, id) {\n let count = 0;\n for (const detection of frame.detections) {\n if (detection.id !== id)\n continue;\n count += 1;\n if (count > 1)\n return false;\n }\n return count === 1;\n}\nfunction pickDetectionByMaskId(frame, maskId, point) {\n if (!frame || maskId <= 0 || !Number.isInteger(maskId)) {\n return null;\n }\n const detectionIndex = maskId - 1;\n const detection = frame.detections[detectionIndex];\n if (!detection) {\n return null;\n }\n return {\n detection,\n detectionIndex,\n frame,\n mediaTime: frame.mediaTime,\n point,\n target: DetectionPickTarget.Mask,\n };\n}\nfunction findHitSegment(point, points, padding, closed) {\n const segmentCount = points.length - 1;\n for (let index = 0; index < segmentCount; index += 1) {\n const start = points[index];\n const end = points[(index + 1) % points.length];\n if (start && end && distanceToSegment(point, start, end) <= padding) {\n return index;\n }\n }\n return -1;\n}\nfunction countMaskPixels(data) {\n let count = 0;\n for (const value of data) {\n count += value ? 1 : 0;\n }\n return Math.max(1, count);\n}\n\nconst MIN_SCALE = 0.1;\nconst MAX_SCALE = 10;\nconst MAX_WHEEL_DELTA = 50;\nfunction createViewportController(initial = {}) {\n let transform = freeze({\n locked: initial.locked ?? false,\n scale: clampScale(initial.scale ?? 0.8),\n x: initial.x ?? 0,\n y: initial.y ?? 0,\n });\n const listeners = new Set();\n const update = (next) => {\n if (next.scale === transform.scale &&\n next.x === transform.x &&\n next.y === transform.y &&\n next.locked === transform.locked)\n return;\n transform = freeze(next);\n for (const listener of listeners)\n listener(transform);\n };\n const controller = {\n getTransform: () => transform,\n screenToMedia: (point) => screenToMedia(point, transform),\n mediaToScreen: (point) => mediaToScreen(point, transform),\n setTransform(next) {\n if (transform.locked)\n return;\n update({\n ...transform,\n ...(next.scale === undefined ? {} : { scale: clampScale(next.scale) }),\n ...(next.x === undefined ? {} : { x: next.x }),\n ...(next.y === undefined ? {} : { y: next.y }),\n });\n },\n setLocked(locked) {\n update({ ...transform, locked });\n },\n panBy(dx, dy) {\n if (transform.locked)\n return;\n update({ ...transform, x: transform.x + dx, y: transform.y + dy });\n },\n zoomAt(point, factor) {\n if (transform.locked || !Number.isFinite(factor) || factor <= 0)\n return;\n const mediaPoint = screenToMedia(point, transform);\n const scale = clampScale(transform.scale * factor);\n update({\n ...transform,\n scale,\n x: point.x - mediaPoint.x * scale,\n y: point.y - mediaPoint.y * scale,\n });\n },\n zoomFromWheel(point, deltaY) {\n const delta = Math.max(-MAX_WHEEL_DELTA, Math.min(MAX_WHEEL_DELTA, deltaY));\n controller.zoomAt(point, Math.exp(-delta * 0.01));\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n return controller;\n}\nfunction screenToMedia(point, transform) {\n return {\n x: (point.x - transform.x) / transform.scale,\n y: (point.y - transform.y) / transform.scale,\n };\n}\nfunction mediaToScreen(point, transform) {\n return {\n x: point.x * transform.scale + transform.x,\n y: point.y * transform.scale + transform.y,\n };\n}\nfunction clampScale(scale) {\n return Math.max(MIN_SCALE, Math.min(MAX_SCALE, Number.isFinite(scale) ? scale : 1));\n}\nfunction freeze(transform) {\n return Object.freeze(transform);\n}\n\nvar 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 = {}));\nvar 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 = {}));\nvar AnnotationHandleKind;\n(function (AnnotationHandleKind) {\n AnnotationHandleKind[\"Resize\"] = \"resize\";\n AnnotationHandleKind[\"Vertex\"] = \"vertex\";\n AnnotationHandleKind[\"AddVertex\"] = \"addVertex\";\n AnnotationHandleKind[\"Keypoint\"] = \"keypoint\";\n})(AnnotationHandleKind || (AnnotationHandleKind = {}));\n\nconst HANDLE_RADIUS = 6;\nconst ADD_HANDLE_RADIUS = 3.6;\nconst HANDLE_HIT_SIZE = 16;\nfunction getAnnotationHandles(detection, viewportScale = 1) {\n if (detection.locked || detection.mask)\n return [];\n const radius = HANDLE_RADIUS / viewportScale;\n const hitSize = HANDLE_HIT_SIZE / viewportScale;\n if (detection.polygon)\n return getPathHandles(detection.polygon.points, true, radius, hitSize);\n if (detection.polyline)\n return getPathHandles(detection.polyline.points, false, radius, hitSize);\n if (detection.keypoints) {\n return detection.keypoints.points.map((point, geometryIndex) => ({\n cursor: \"move\",\n geometryIndex,\n hitSize,\n id: `kp-${geometryIndex}`,\n kind: AnnotationHandleKind.Keypoint,\n point,\n radius,\n }));\n }\n if (detection.rect)\n return getBoxHandles(detection.rect, radius, hitSize);\n return [];\n}\nfunction pickAnnotationHandle(handles, point) {\n return [...handles]\n .reverse()\n .find((handle) => Math.abs(point.x - handle.point.x) <= handle.hitSize / 2 &&\n Math.abs(point.y - handle.point.y) <= handle.hitSize / 2);\n}\nfunction applyAnnotationHandleDrag(detection, handle, point) {\n if (detection.rect && handle.kind === AnnotationHandleKind.Resize) {\n return { ...detection, rect: resizeRect(detection.rect, handle.id, point) };\n }\n if (handle.kind === AnnotationHandleKind.AddVertex &&\n handle.edgeIndex !== undefined) {\n const key = detection.polygon ? \"polygon\" : \"polyline\";\n const geometry = detection[key];\n if (!geometry)\n return detection;\n const points = [...geometry.points];\n points.splice(handle.edgeIndex + 1, 0, point);\n return { ...detection, [key]: { points } };\n }\n if (handle.geometryIndex === undefined)\n return detection;\n if (detection.polygon)\n return replacePathPoint(detection, \"polygon\", handle.geometryIndex, point);\n if (detection.polyline)\n return replacePathPoint(detection, \"polyline\", handle.geometryIndex, point);\n if (detection.keypoints) {\n const points = [...detection.keypoints.points];\n points[handle.geometryIndex] = point;\n return { ...detection, keypoints: { ...detection.keypoints, points } };\n }\n return detection;\n}\nfunction deleteAnnotationVertex(detection, vertexIndex) {\n const geometry = detection.polygon ?? detection.polyline;\n const minimum = detection.polygon ? 3 : 2;\n if (!geometry || geometry.points.length <= minimum)\n return null;\n const points = geometry.points.filter((_, index) => index !== vertexIndex);\n return detection.polygon\n ? { ...detection, polygon: { points } }\n : { ...detection, polyline: { points } };\n}\nfunction offsetDetection(detection, dx, dy) {\n const offsetPoint = ({ x, y }) => ({ x: x + dx, y: y + dy });\n return {\n ...detection,\n ...(detection.rect\n ? {\n rect: {\n ...detection.rect,\n x: detection.rect.x + dx,\n y: detection.rect.y + dy,\n },\n }\n : {}),\n ...(detection.polygon\n ? { polygon: { points: detection.polygon.points.map(offsetPoint) } }\n : {}),\n ...(detection.polyline\n ? { polyline: { points: detection.polyline.points.map(offsetPoint) } }\n : {}),\n ...(detection.keypoints\n ? {\n keypoints: {\n ...detection.keypoints,\n points: detection.keypoints.points.map(offsetPoint),\n },\n }\n : {}),\n };\n}\nfunction getBoxHandles(rect, radius, hitSize) {\n const left = rect.x - rect.width / 2;\n const right = rect.x + rect.width / 2;\n const top = rect.y - rect.height / 2;\n const bottom = rect.y + rect.height / 2;\n const definitions = [\n [\"nw\", { x: left, y: top }, \"nwse-resize\"],\n [\"n\", { x: rect.x, y: top }, \"ns-resize\"],\n [\"ne\", { x: right, y: top }, \"nesw-resize\"],\n [\"e\", { x: right, y: rect.y }, \"ew-resize\"],\n [\"se\", { x: right, y: bottom }, \"nwse-resize\"],\n [\"s\", { x: rect.x, y: bottom }, \"ns-resize\"],\n [\"sw\", { x: left, y: bottom }, \"nesw-resize\"],\n [\"w\", { x: left, y: rect.y }, \"ew-resize\"],\n ];\n return definitions.map(([id, point, cursor]) => ({\n cursor,\n hitSize,\n id,\n kind: AnnotationHandleKind.Resize,\n point,\n radius,\n }));\n}\nfunction getPathHandles(points, closed, radius, hitSize) {\n const handles = points.map((point, geometryIndex) => ({\n cursor: \"move\",\n geometryIndex,\n hitSize,\n id: `vertex-${geometryIndex}`,\n kind: AnnotationHandleKind.Vertex,\n point,\n radius,\n }));\n const edgeCount = closed ? points.length : Math.max(0, points.length - 1);\n for (let edgeIndex = 0; edgeIndex < edgeCount; edgeIndex += 1) {\n const from = points[edgeIndex];\n const to = points[(edgeIndex + 1) % points.length];\n handles.push({\n cursor: \"copy\",\n edgeIndex,\n hitSize,\n id: `add-${edgeIndex}`,\n kind: AnnotationHandleKind.AddVertex,\n point: { x: (from.x + to.x) / 2, y: (from.y + to.y) / 2 },\n radius: ADD_HANDLE_RADIUS / (HANDLE_RADIUS / radius),\n });\n }\n return handles;\n}\nfunction resizeRect(rect, handle, point) {\n let left = rect.x - rect.width / 2;\n let right = rect.x + rect.width / 2;\n let top = rect.y - rect.height / 2;\n let bottom = rect.y + rect.height / 2;\n if (handle.includes(\"w\"))\n left = Math.min(point.x, right - 5);\n if (handle.includes(\"e\"))\n right = Math.max(point.x, left + 5);\n if (handle.includes(\"n\"))\n top = Math.min(point.y, bottom - 5);\n if (handle.includes(\"s\"))\n bottom = Math.max(point.y, top + 5);\n return {\n x: (left + right) / 2,\n y: (top + bottom) / 2,\n width: right - left,\n height: bottom - top,\n };\n}\nfunction replacePathPoint(detection, key, index, point) {\n const geometry = detection[key];\n const points = [...geometry.points];\n points[index] = point;\n return { ...detection, [key]: { points } };\n}\n/** Finds the closest path segment, useful for contextual vertex insertion. */\nfunction findClosestAnnotationSegment(points, point, closed) {\n const count = closed ? points.length : points.length - 1;\n let best;\n for (let index = 0; index < count; index += 1) {\n const distance = distanceToSegment(point, points[index], points[(index + 1) % points.length]);\n if (!best || distance < best.distance)\n best = { index, distance };\n }\n return best;\n}\n\nconst MOVE_THRESHOLD = 4;\nconst CLICK_CANCEL_MS = 250;\nconst CLICK_CANCEL_DIAGONAL = 25;\nconst CLOSE_ZONE_SCREEN_PX = 12;\nfunction createAnnotationEditingEngine(options = {}) {\n let tool = null;\n let gesture = null;\n let state = idleState();\n const stateListeners = new Set();\n const fastTranslateListeners = new Set();\n return {\n getState: () => state,\n setCreationTool(nextTool) {\n if (gesture)\n cancel();\n tool = nextTool;\n },\n pointerDown(input, pick = null) {\n if (input.button !== undefined && input.button !== 0)\n return;\n if (tool) {\n beginCreation(input);\n }\n else if (pick && !pick.detection.locked && !pick.detection.mask) {\n beginMove(pick, input);\n }\n },\n pointerMove(input) {\n if (!gesture)\n return;\n switch (gesture.kind) {\n case \"box\":\n gesture = { ...gesture, current: input };\n setPreview(resolveBoxPreview(gesture));\n break;\n case \"move\": {\n const dx = input.point.x - gesture.start.point.x;\n const dy = input.point.y - gesture.start.point.y;\n const moved = gesture.moved || Math.hypot(dx, dy) >= MOVE_THRESHOLD / scale();\n gesture = { ...gesture, current: input, moved };\n if (moved) {\n const preview = offsetDetection(gesture.detection, dx, dy);\n setPreview(preview);\n if (gesture.detection.id !== undefined) {\n options.onFastTranslate?.(gesture.detection.id, dx, dy);\n for (const listener of fastTranslateListeners) {\n listener(gesture.detection.id, dx, dy);\n }\n }\n }\n break;\n }\n case \"resize\":\n gesture = { ...gesture, current: input };\n setPreview(applyAnnotationHandleDrag(gesture.detection, gesture.handle, input.point));\n break;\n case \"path\":\n setPreview(resolvePathPreview([...gesture.points, input.point]));\n break;\n case \"freehand\": {\n const previous = gesture.points.at(-1);\n if (!previous ||\n previous.x !== input.point.x ||\n previous.y !== input.point.y) {\n gesture.points.push(input.point);\n }\n gesture = { ...gesture, current: input };\n setPreview(resolvePathPreview(gesture.points));\n break;\n }\n }\n },\n pointerUp(input) {\n if (!gesture)\n return;\n if (gesture.kind === \"path\")\n return;\n const active = gesture;\n gesture = null;\n release(active.start.pointerId);\n if (active.kind === \"box\") {\n const preview = resolveBoxPreview({ ...active, current: input });\n const duration = input.timestamp - active.start.timestamp;\n const diagonal = Math.hypot(input.point.x - active.start.point.x, input.point.y - active.start.point.y) * scale();\n const rect = preview.rect;\n if (!rect ||\n rect.width < 1 ||\n rect.height < 1 ||\n (duration < CLICK_CANCEL_MS && diagonal <= CLICK_CANCEL_DIAGONAL)) {\n cancel();\n return;\n }\n if (tool?.shouldCommit?.(rect) === false) {\n cancel();\n return;\n }\n commit(preview, null);\n return;\n }\n if (active.kind === \"freehand\") {\n const points = [...active.points, input.point];\n if (points.length < 2 || tool?.shouldCommit?.(points) === false) {\n cancel();\n return;\n }\n commit(tool.createDetection(points), null);\n return;\n }\n if (active.kind === \"move\") {\n if (!active.moved) {\n setState(idleState());\n return;\n }\n const preview = offsetDetection(active.detection, input.point.x - active.start.point.x, input.point.y - active.start.point.y);\n commit(preview, active.detection);\n return;\n }\n const preview = applyAnnotationHandleDrag(active.detection, active.handle, input.point);\n commit(preview, active.detection);\n },\n keyDown(key) {\n if (key === \"Escape\") {\n cancel();\n }\n else if (key === \"Enter\" && gesture?.kind === \"path\") {\n commitPath();\n }\n },\n beginHandleDrag(detection, handle, input) {\n if (detection.locked || detection.mask)\n return;\n capture(input.pointerId);\n gesture = {\n current: input,\n detection,\n handle,\n kind: \"resize\",\n start: input,\n };\n setState({\n activeDetectionId: detection.id ?? null,\n activeHandleId: handle.id,\n kind: AnnotationGestureStateKind.Resizing,\n pointerId: input.pointerId ?? null,\n preview: detection,\n });\n },\n deleteVertex(detection, vertexIndex) {\n const next = deleteAnnotationVertex(detection, vertexIndex);\n if (next)\n commit(next, detection);\n return next;\n },\n cancel,\n hasCreationTool: () => tool !== null,\n subscribe(listener) {\n stateListeners.add(listener);\n return () => stateListeners.delete(listener);\n },\n subscribeFastTranslate(listener) {\n fastTranslateListeners.add(listener);\n return () => fastTranslateListeners.delete(listener);\n },\n };\n function beginCreation(input) {\n if (!tool)\n return;\n const mode = tool.mode ??\n (tool.geometry === AnnotationGeometryKind.Box\n ? \"drag\"\n : tool.geometry === AnnotationGeometryKind.Mask\n ? \"freehand\"\n : \"multiClick\");\n if (mode === \"drag\") {\n capture(input.pointerId);\n gesture = { current: input, kind: \"box\", start: input };\n const preview = resolveBoxPreview(gesture);\n options.onPreview?.(preview);\n setState({\n activeDetectionId: null,\n activeHandleId: null,\n kind: AnnotationGestureStateKind.Creating,\n pointerId: input.pointerId ?? null,\n preview,\n });\n return;\n }\n if (mode === \"freehand\") {\n capture(input.pointerId);\n gesture = {\n current: input,\n kind: \"freehand\",\n points: [input.point],\n start: input,\n };\n setPreview(resolvePathPreview([input.point]));\n return;\n }\n if (tool.geometry !== AnnotationGeometryKind.Polygon &&\n tool.geometry !== AnnotationGeometryKind.Polyline &&\n tool.geometry !== AnnotationGeometryKind.Keypoints)\n return;\n if (gesture?.kind !== \"path\") {\n capture(input.pointerId);\n gesture = {\n kind: \"path\",\n lastTimestamp: input.timestamp,\n pointerId: input.pointerId ?? null,\n points: [input.point],\n };\n setPreview(resolvePathPreview([input.point, input.point]));\n return;\n }\n const minimum = tool.minVertices ??\n (tool.geometry === AnnotationGeometryKind.Polygon ? 3 : 2);\n const closeDistance = Math.hypot(input.point.x - gesture.points[0].x, input.point.y - gesture.points[0].y) * scale();\n const doubleClick = input.detail !== undefined\n ? input.detail >= 2\n : input.timestamp - gesture.lastTimestamp < CLICK_CANCEL_MS;\n if (gesture.points.length >= minimum &&\n ((tool.geometry === AnnotationGeometryKind.Polygon &&\n closeDistance <= CLOSE_ZONE_SCREEN_PX) ||\n doubleClick)) {\n commitPath();\n return;\n }\n gesture.points.push(input.point);\n gesture.lastTimestamp = input.timestamp;\n setPreview(resolvePathPreview([...gesture.points, input.point]));\n }\n function beginMove(pick, input) {\n capture(input.pointerId);\n gesture = {\n current: input,\n detection: pick.detection,\n kind: \"move\",\n moved: false,\n start: input,\n };\n setState({\n activeDetectionId: pick.detection.id ?? null,\n activeHandleId: null,\n kind: AnnotationGestureStateKind.Moving,\n pointerId: input.pointerId ?? null,\n preview: null,\n });\n }\n function resolveBoxPreview(active) {\n const left = Math.min(active.start.point.x, active.current.point.x);\n const right = Math.max(active.start.point.x, active.current.point.x);\n const top = Math.min(active.start.point.y, active.current.point.y);\n const bottom = Math.max(active.start.point.y, active.current.point.y);\n const rect = {\n x: (left + right) / 2,\n y: (top + bottom) / 2,\n width: right - left,\n height: bottom - top,\n };\n return tool.createDetection(rect);\n }\n function resolvePathPreview(points) {\n return tool.createDetection(points);\n }\n function commitPath() {\n if (!tool || gesture?.kind !== \"path\")\n return;\n const minimum = tool.minVertices ??\n (tool.geometry === AnnotationGeometryKind.Polygon ? 3 : 2);\n if (gesture.points.length < minimum) {\n cancel();\n return;\n }\n const preview = tool.createDetection(gesture.points);\n if (tool.shouldCommit?.(gesture.points) === false) {\n cancel();\n return;\n }\n release(gesture.pointerId ?? undefined);\n gesture = null;\n commit(preview, null);\n }\n function commit(detection, previous) {\n options.onCommit?.(detection, previous);\n options.onPreview?.(null);\n setState(idleState());\n }\n function setPreview(preview) {\n options.onPreview?.(preview);\n setState({\n activeDetectionId: state.activeDetectionId,\n activeHandleId: state.activeHandleId,\n kind: state.kind === AnnotationGestureStateKind.Idle\n ? AnnotationGestureStateKind.Creating\n : state.kind,\n pointerId: state.pointerId ??\n (gesture && \"pointerId\" in gesture\n ? (gesture.pointerId ?? null)\n : null),\n preview,\n });\n }\n function cancel() {\n const pointerId = gesture && \"start\" in gesture\n ? gesture.start.pointerId\n : gesture?.kind === \"path\"\n ? (gesture.pointerId ?? undefined)\n : undefined;\n release(pointerId);\n gesture = null;\n options.onPreview?.(null);\n options.onCancel?.();\n setState(idleState());\n }\n function setState(next) {\n state = Object.freeze(next);\n options.onStateChange?.(state);\n for (const listener of stateListeners)\n listener(state);\n }\n function scale() {\n return Math.max(options.viewportScale?.() ?? 1, Number.EPSILON);\n }\n function capture(pointerId) {\n if (pointerId !== undefined)\n options.capturePointer?.(pointerId);\n }\n function release(pointerId) {\n if (pointerId !== undefined)\n options.releasePointer?.(pointerId);\n }\n}\nfunction idleState() {\n return Object.freeze({\n activeDetectionId: null,\n activeHandleId: null,\n kind: AnnotationGestureStateKind.Idle,\n pointerId: null,\n preview: null,\n });\n}\n\nfunction resolveStyleValue(value, detection, context) {\n return typeof value === \"function\"\n ? value(detection, context)\n : value;\n}\n\nvar BoxShape;\n(function (BoxShape) {\n BoxShape[\"Rect\"] = \"rect\";\n BoxShape[\"RoundedRect\"] = \"roundedRect\";\n})(BoxShape || (BoxShape = {}));\nvar BoxStrokeAlignment;\n(function (BoxStrokeAlignment) {\n BoxStrokeAlignment[\"Inside\"] = \"inside\";\n BoxStrokeAlignment[\"Center\"] = \"center\";\n BoxStrokeAlignment[\"Outside\"] = \"outside\";\n})(BoxStrokeAlignment || (BoxStrokeAlignment = {}));\n\nconst DEFAULT_BOX_STROKE_ALPHA = 1;\nconst DEFAULT_BOX_STROKE_COLOR = 0x00ff66;\nconst DEFAULT_BOX_STROKE_WIDTH = 2;\n/**\n * Default configurable box style.\n *\n * This is the simplest `supervision-js` equivalent of a box annotator: it\n * converts detections with `rect` geometry into renderer-neutral box draw\n * instructions. Use options such as `shape`, `cornerRadius`, `stroke`, and\n * `fill` for static or per-detection styling.\n */\nclass BaseBoxStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (!detection.rect ||\n context.hidden ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const shape = this.resolveShape(detection, context);\n const cornerRadius = this.resolveCornerRadius(detection, context, shape);\n const instruction = {\n fill: this.resolveFill(detection, context),\n rect: detection.rect,\n shape,\n stroke: this.resolveStroke(detection, context),\n };\n if (cornerRadius !== undefined) {\n return {\n ...instruction,\n cornerRadius,\n };\n }\n return instruction;\n }\n resolveShape(detection, context) {\n return (resolveStyleValue(this.options.shape, detection, context) ?? BoxShape.Rect);\n }\n resolveCornerRadius(detection, context, shape) {\n if (shape !== BoxShape.RoundedRect) {\n return undefined;\n }\n return resolveStyleValue(this.options.cornerRadius, detection, context);\n }\n resolveStroke(detection, context) {\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n if (stroke === null) {\n return undefined;\n }\n const resolvedStroke = {\n alpha: stroke?.alpha ?? DEFAULT_BOX_STROKE_ALPHA,\n color: stroke?.color ?? DEFAULT_BOX_STROKE_COLOR,\n width: stroke?.width ?? DEFAULT_BOX_STROKE_WIDTH,\n };\n return {\n ...resolvedStroke,\n ...(stroke?.alignment === undefined\n ? {}\n : { alignment: stroke.alignment }),\n ...(stroke?.dash === undefined\n ? context.ephemeral\n ? { dash: [6, 4] }\n : {}\n : { dash: stroke.dash }),\n };\n }\n resolveFill(detection, context) {\n const fill = resolveStyleValue(this.options.fill, detection, context);\n if (fill === null || fill === undefined) {\n return undefined;\n }\n return {\n alpha: fill.alpha ?? 1,\n color: fill.color ?? DEFAULT_BOX_STROKE_COLOR,\n };\n }\n}\n\nvar FocusTargetMode;\n(function (FocusTargetMode) {\n FocusTargetMode[\"Hovered\"] = \"hovered\";\n FocusTargetMode[\"Selected\"] = \"selected\";\n FocusTargetMode[\"HoveredAndSelected\"] = \"hoveredAndSelected\";\n FocusTargetMode[\"Ambient\"] = \"ambient\";\n})(FocusTargetMode || (FocusTargetMode = {}));\n\nconst DEFAULT_FOCUS_FILL_COLOR = 0x020617;\nconst DEFAULT_FOCUS_FILL_ALPHA = 0.45;\nconst DEFAULT_FOCUS_CORNER_RADIUS = 8;\n/**\n * Default configurable focus style.\n *\n * Focus styles dim the current media frame while leaving the selected or\n * hovered detections visible. Renderers may use prepared mask artifacts for\n * shape-accurate cutouts, falling back to detection rectangles when needed.\n */\nclass BaseFocusStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(context) {\n if (this.options.shouldRender?.(context) === false) {\n return undefined;\n }\n const targetMode = this.options.targetMode ?? FocusTargetMode.Selected;\n const targets = getFocusTargets(context, targetMode);\n const ambient = targetMode === FocusTargetMode.Ambient &&\n !context.selectedPick &&\n !context.hoveredPick;\n const fill = resolveFocusStyleValue(this.options.fill, context);\n if (targets.length === 0 || fill === null) {\n return undefined;\n }\n return {\n fallback: this.resolveFallback(context),\n fill: {\n alpha: fill?.alpha ?? DEFAULT_FOCUS_FILL_ALPHA,\n color: fill?.color ?? DEFAULT_FOCUS_FILL_COLOR,\n },\n targetMode,\n targets,\n ...(ambient ? { ambient: true } : {}),\n };\n }\n resolveFallback(context) {\n const shape = resolveFocusStyleValue(this.options.shape, context) ??\n BoxShape.RoundedRect;\n const cornerRadius = shape === BoxShape.RoundedRect\n ? (resolveFocusStyleValue(this.options.cornerRadius, context) ??\n DEFAULT_FOCUS_CORNER_RADIUS)\n : undefined;\n if (cornerRadius === undefined) {\n return { shape };\n }\n return {\n cornerRadius,\n shape,\n };\n }\n}\nfunction getFocusTargets(context, targetMode) {\n const targets = [];\n if (targetMode === FocusTargetMode.Ambient) {\n if (context.selectedPick)\n return [context.selectedPick];\n if (context.hoveredPick)\n return [context.hoveredPick];\n return context.frame.detections.map((detection, detectionIndex) => ({\n detection,\n detectionIndex,\n frame: context.frame,\n mediaTime: context.mediaTime,\n point: detection.rect\n ? { x: detection.rect.x, y: detection.rect.y }\n : { x: 0, y: 0 },\n target: detection.mask\n ? DetectionPickTarget.Mask\n : detection.polygon\n ? DetectionPickTarget.Polygon\n : DetectionPickTarget.Box,\n }));\n }\n if ((targetMode === FocusTargetMode.Selected ||\n targetMode === FocusTargetMode.HoveredAndSelected) &&\n context.selectedPick) {\n targets.push(context.selectedPick);\n }\n if ((targetMode === FocusTargetMode.Hovered ||\n targetMode === FocusTargetMode.HoveredAndSelected) &&\n context.hoveredPick) {\n targets.push(context.hoveredPick);\n }\n return dedupeTargetsForFrame(targets, context.frame);\n}\nfunction dedupeTargetsForFrame(targets, frame) {\n const keys = new Set();\n const dedupedTargets = [];\n for (const target of targets) {\n if (target.frame !== frame) {\n continue;\n }\n const key = `${target.detectionIndex}:${target.target}`;\n if (keys.has(key)) {\n continue;\n }\n keys.add(key);\n dedupedTargets.push(target);\n }\n return dedupedTargets;\n}\nfunction resolveFocusStyleValue(value, context) {\n if (typeof value === \"function\") {\n return value(context);\n }\n return value;\n}\n\nvar DetectionInteractionState;\n(function (DetectionInteractionState) {\n DetectionInteractionState[\"Hovered\"] = \"hovered\";\n DetectionInteractionState[\"Selected\"] = \"selected\";\n})(DetectionInteractionState || (DetectionInteractionState = {}));\n\nconst DEFAULT_HOVER_FILL_COLOR = 0x67e8f9;\nconst DEFAULT_HOVER_FILL_ALPHA = 0.1;\nconst DEFAULT_HOVER_STROKE_COLOR = 0x67e8f9;\nconst DEFAULT_HOVER_STROKE_ALPHA = 0.95;\nconst DEFAULT_HOVER_STROKE_WIDTH = 3;\nconst DEFAULT_SELECTED_FILL_COLOR = 0xfde047;\nconst DEFAULT_SELECTED_FILL_ALPHA = 0.18;\nconst DEFAULT_SELECTED_STROKE_COLOR = 0xfde047;\nconst DEFAULT_SELECTED_STROKE_ALPHA = 1;\nconst DEFAULT_SELECTED_STROKE_WIDTH = 4;\n/**\n * Default configurable interaction style.\n *\n * It resolves hover and selected picks into state-specific presentations using\n * the same style contracts as normal boxes, masks, and labels. The older\n * rectangle options are kept as compatibility sugar and resolve to a box style.\n */\nclass BaseInteractionStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const statePresentation = context.state === DetectionInteractionState.Selected\n ? this.options.selected\n : this.options.hovered;\n if (statePresentation !== undefined) {\n return statePresentation ?? undefined;\n }\n const rect = detection.rect;\n if (!rect) {\n return undefined;\n }\n return {\n boxStyle: createResolvedBoxStyle(this.resolveBoxInstruction(detection, context, rect)),\n };\n }\n resolveBoxInstruction(detection, context, rect) {\n const shape = this.resolveShape(detection, context);\n const cornerRadius = this.resolveCornerRadius(detection, context, shape);\n const instruction = {\n fill: this.resolveFill(detection, context),\n rect,\n shape,\n stroke: this.resolveStroke(detection, context),\n };\n if (cornerRadius !== undefined) {\n return {\n ...instruction,\n cornerRadius,\n };\n }\n return instruction;\n }\n resolveShape(detection, context) {\n return (resolveStyleValue(this.options.shape, detection, context) ?? BoxShape.Rect);\n }\n resolveCornerRadius(detection, context, shape) {\n if (shape !== BoxShape.RoundedRect) {\n return undefined;\n }\n return resolveStyleValue(this.options.cornerRadius, detection, context);\n }\n resolveStroke(detection, context) {\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n if (stroke === null) {\n return undefined;\n }\n const defaults = getStateDefaults(context.state);\n const resolvedStroke = {\n alpha: stroke?.alpha ?? defaults.strokeAlpha,\n color: stroke?.color ?? defaults.strokeColor,\n width: stroke?.width ?? defaults.strokeWidth,\n };\n if (stroke?.alignment !== undefined) {\n return {\n ...resolvedStroke,\n alignment: stroke.alignment,\n };\n }\n return resolvedStroke;\n }\n resolveFill(detection, context) {\n const fill = resolveStyleValue(this.options.fill, detection, context);\n if (fill === null) {\n return undefined;\n }\n const defaults = getStateDefaults(context.state);\n return {\n alpha: fill?.alpha ?? defaults.fillAlpha,\n color: fill?.color ?? defaults.fillColor,\n };\n }\n}\nfunction createResolvedBoxStyle(instruction) {\n return {\n resolve() {\n return instruction;\n },\n };\n}\nfunction getStateDefaults(state) {\n if (state === DetectionInteractionState.Selected) {\n return {\n fillAlpha: DEFAULT_SELECTED_FILL_ALPHA,\n fillColor: DEFAULT_SELECTED_FILL_COLOR,\n strokeAlpha: DEFAULT_SELECTED_STROKE_ALPHA,\n strokeColor: DEFAULT_SELECTED_STROKE_COLOR,\n strokeWidth: DEFAULT_SELECTED_STROKE_WIDTH,\n };\n }\n return {\n fillAlpha: DEFAULT_HOVER_FILL_ALPHA,\n fillColor: DEFAULT_HOVER_FILL_COLOR,\n strokeAlpha: DEFAULT_HOVER_STROKE_ALPHA,\n strokeColor: DEFAULT_HOVER_STROKE_COLOR,\n strokeWidth: DEFAULT_HOVER_STROKE_WIDTH,\n };\n}\n\nvar 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 = {}));\nvar LabelVisibilityMode;\n(function (LabelVisibilityMode) {\n LabelVisibilityMode[\"Always\"] = \"always\";\n LabelVisibilityMode[\"HoveredOnly\"] = \"hoveredOnly\";\n})(LabelVisibilityMode || (LabelVisibilityMode = {}));\n\n/** Returns black or white for readable text over an RGB background. */\nfunction resolveContrastTextColor(color) {\n \"worklet\";\n const red = (color >> 16) & 0xff;\n const green = (color >> 8) & 0xff;\n const blue = color & 0xff;\n const luminance = (red * 299 + green * 587 + blue * 114) / 1000;\n return luminance >= 150 ? 0x111111 : 0xffffff;\n}\nfunction lightenColor(color, amount = 0.14) {\n \"worklet\";\n const mix = (value) => Math.round(value + (255 - value) * amount);\n return ((mix((color >> 16) & 0xff) << 16) |\n (mix((color >> 8) & 0xff) << 8) |\n mix(color & 0xff));\n}\n\n/**\n * Default label style.\n *\n * Resolves labels from `className`, `metadata.label`, or a custom text\n * resolver, optionally including confidence.\n */\nclass BaseLabelStyle {\n includeConfidence;\n offsetY;\n options;\n constructor(options = {}) {\n this.options = options;\n this.includeConfidence = options.includeConfidence ?? false;\n this.offsetY = options.offsetY ?? 0;\n }\n resolve(detection, context) {\n if (!getDetectionRect(detection) ||\n context.hidden ||\n (this.options.visibilityMode === LabelVisibilityMode.HoveredOnly &&\n !context.hovered) ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const text = resolveStyleValue(this.options.text, detection, context) ??\n formatDetectionLabel(detection, this.includeConfidence);\n if (!text) {\n return undefined;\n }\n const background = this.resolveBackground(detection, context);\n return {\n background,\n ...this.resolveOffset(detection, context),\n placement: this.resolvePlacement(detection, context),\n rect: getDetectionRect(detection),\n text,\n textStyle: this.resolveTextStyle(detection, context, background),\n };\n }\n resolveBackground(detection, context) {\n const background = resolveStyleValue(this.options.background, detection, context);\n return {\n alpha: background?.alpha ?? 0.72,\n color: context.hovered\n ? lightenColor(background?.color ?? 0x111827)\n : (background?.color ?? 0x111827),\n cornerRadius: background?.cornerRadius ?? 4,\n paddingX: background?.paddingX ?? 6,\n paddingY: background?.paddingY ?? 3,\n ...(background?.topCornersOnly === undefined\n ? {}\n : { topCornersOnly: background.topCornersOnly }),\n };\n }\n resolveTextStyle(detection, context, background) {\n const textStyle = resolveStyleValue(this.options.textStyle, detection, context);\n return {\n alpha: textStyle?.alpha ?? 1,\n color: textStyle?.color ?? resolveContrastTextColor(background.color),\n fontFamily: textStyle?.fontFamily ?? \"Inter, sans-serif\",\n fontSize: textStyle?.fontSize ?? 13,\n fontWeight: textStyle?.fontWeight ?? \"600\",\n };\n }\n resolveOffset(detection, context) {\n const offset = resolveStyleValue(this.options.offset, detection, context);\n if (offset === null) {\n return {};\n }\n return {\n ...(offset?.x === undefined ? {} : { offsetX: offset.x }),\n offsetY: offset?.y ?? this.offsetY,\n };\n }\n resolvePlacement(detection, context) {\n return (resolveStyleValue(this.options.placement, detection, context) ??\n LabelPlacement.Top);\n }\n}\nfunction formatDetectionLabel(detection, includeConfidence) {\n const label = detection.className ??\n (typeof detection.metadata?.label === \"string\"\n ? detection.metadata.label\n : undefined);\n if (!label) {\n return undefined;\n }\n if (!includeConfidence || detection.confidence === undefined) {\n return label;\n }\n return `${label} ${Math.round(detection.confidence * 100)}%`;\n}\n\nvar MaskRenderMode;\n(function (MaskRenderMode) {\n MaskRenderMode[\"FillAndStroke\"] = \"fillAndStroke\";\n MaskRenderMode[\"FillOnly\"] = \"fillOnly\";\n MaskRenderMode[\"StrokeOnly\"] = \"strokeOnly\";\n})(MaskRenderMode || (MaskRenderMode = {}));\n\n/**\n * Default compressed-RLE mask style.\n *\n * Static color/stroke options can reuse prepared mask artifacts by key. Dynamic\n * color or stroke resolvers intentionally do not expose an artifact key, so new\n * style objects rebuild prepared palettes instead of reusing stale ones.\n */\nclass BaseMaskStyle {\n artifactKey;\n opacity;\n options;\n constructor(options = {}) {\n this.options = options;\n this.opacity = clampOpacity(options.opacity ?? options.alpha ?? 0.35);\n this.artifactKey = createArtifactKey(options);\n }\n resolve(detection, context) {\n if (!detection.mask ||\n context.hidden ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const color = resolveStyleValue(this.options.color, detection, context) ??\n DEFAULT_MASK_COLOR;\n const mode = resolveStyleValue(this.options.mode, detection, context) ??\n MaskRenderMode.FillAndStroke;\n const stroke = resolveStroke(resolveStyleValue(this.options.stroke, detection, context), color, mode);\n return {\n alpha: mode === MaskRenderMode.StrokeOnly\n ? 0\n : clampOpacity(resolveStyleValue(this.options.fillAlpha, detection, context) ??\n 1),\n color,\n mask: detection.mask,\n stroke: mode === MaskRenderMode.FillOnly ? undefined : stroke,\n };\n }\n}\nconst DEFAULT_MASK_COLOR = 0x00ff66;\nconst DEFAULT_MASK_STROKE_ALPHA = 1;\nconst DEFAULT_MASK_STROKE_WIDTH = 1;\nfunction clampOpacity(opacity) {\n return Number.isFinite(opacity) ? Math.max(0, Math.min(opacity, 1)) : 1;\n}\nfunction serializeStroke(stroke) {\n if (!stroke) {\n return \"none\";\n }\n return `${stroke.color}:${stroke.alpha}:${stroke.width}`;\n}\nfunction normalizeStroke(stroke, fallbackColor) {\n if (!stroke) {\n return undefined;\n }\n return {\n alpha: stroke.alpha ?? DEFAULT_MASK_STROKE_ALPHA,\n color: stroke.color ?? fallbackColor,\n width: stroke.width ?? DEFAULT_MASK_STROKE_WIDTH,\n };\n}\nfunction resolveStroke(stroke, fallbackColor, mode) {\n if (mode === MaskRenderMode.FillOnly) {\n return undefined;\n }\n if (mode === MaskRenderMode.StrokeOnly && stroke === undefined) {\n return normalizeStroke({}, fallbackColor);\n }\n return normalizeStroke(stroke, fallbackColor);\n}\nfunction createArtifactKey(options) {\n if (typeof options.color === \"function\" ||\n typeof options.fillAlpha === \"function\" ||\n typeof options.mode === \"function\" ||\n typeof options.stroke === \"function\") {\n return undefined;\n }\n const color = options.color ?? DEFAULT_MASK_COLOR;\n const fillAlpha = options.fillAlpha ?? 1;\n const mode = options.mode ?? MaskRenderMode.FillAndStroke;\n return `base:${color}:${fillAlpha}:${mode}:${serializeStroke(resolveStroke(options.stroke, color, mode))}`;\n}\n\nclass BasePolygonStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (!detection.polygon ||\n context.hidden ||\n detection.polygon.points.length < 3 ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const fill = resolveStyleValue(this.options.fill, detection, context);\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n return {\n points: detection.polygon.points,\n ...(fill === null\n ? {}\n : {\n fill: {\n alpha: fill?.alpha ?? 0.16,\n color: fill?.color ?? 0x00ff66,\n },\n }),\n ...(stroke === null\n ? {}\n : {\n stroke: {\n alpha: stroke?.alpha ?? 1,\n color: stroke?.color ?? 0x00ff66,\n width: stroke?.width ?? 2,\n ...(stroke?.alignment === undefined\n ? {}\n : { alignment: stroke.alignment }),\n ...(stroke?.dash === undefined ? {} : { dash: stroke.dash }),\n },\n }),\n };\n }\n}\n\nclass BasePolylineStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (!detection.polyline ||\n context.hidden ||\n detection.polyline.points.length < 2 ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n if (stroke === null) {\n return undefined;\n }\n return {\n points: detection.polyline.points,\n stroke: {\n alpha: stroke?.alpha ?? 1,\n color: stroke?.color ?? 0x00ff66,\n width: stroke?.width ?? 2,\n ...(stroke?.alignment === undefined\n ? {}\n : { alignment: stroke.alignment }),\n ...(stroke?.dash === undefined ? {} : { dash: stroke.dash }),\n },\n };\n }\n}\n\nvar KeypointMarkerShape;\n(function (KeypointMarkerShape) {\n KeypointMarkerShape[\"Circle\"] = \"circle\";\n KeypointMarkerShape[\"Cross\"] = \"cross\";\n})(KeypointMarkerShape || (KeypointMarkerShape = {}));\n\nclass BaseKeypointStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n const geometry = detection.keypoints;\n if (!geometry ||\n context.hidden ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const definition = detection.className\n ? this.options.definitions?.[detection.className]\n : undefined;\n const markerFill = resolveStyleValue(this.options.markerFill, detection, context);\n const markerStroke = resolveStyleValue(this.options.markerStroke, detection, context);\n const edgeStroke = resolveStyleValue(this.options.edgeStroke, detection, context);\n const shadowStroke = resolveStyleValue(this.options.edgeShadowStroke, detection, context);\n const radius = resolveStyleValue(this.options.radius, detection, context) ?? 6;\n const edges = geometry.edges.map(([fromIndex, toIndex], edgeIndex) => ({\n from: geometry.points[fromIndex],\n to: geometry.points[toIndex],\n stroke: {\n alpha: edgeStroke?.alpha ?? 1,\n color: definition?.edges[edgeIndex]?.color ?? edgeStroke?.color ?? 0x00ff66,\n width: edgeStroke?.width ?? 2,\n },\n ...(shadowStroke === null\n ? {}\n : {\n shadowStroke: {\n alpha: shadowStroke?.alpha ?? 0.65,\n color: shadowStroke?.color ?? 0x000000,\n width: shadowStroke?.width ?? 4,\n },\n }),\n }));\n const markers = geometry.points.flatMap((point, index) => {\n const visibility = geometry.visibility?.[index] ?? KeypointVisibility.Visible;\n if (visibility === KeypointVisibility.NotLabeled) {\n return [];\n }\n return [\n {\n fill: {\n alpha: markerFill?.alpha ?? 1,\n color: definition?.vertices[index]?.color ??\n markerFill?.color ??\n 0x00ff66,\n },\n index,\n point,\n radius,\n shape: visibility === KeypointVisibility.Occluded\n ? KeypointMarkerShape.Cross\n : KeypointMarkerShape.Circle,\n stroke: {\n alpha: markerStroke?.alpha ?? 1,\n color: markerStroke?.color ?? 0xffffff,\n width: markerStroke?.width ?? 2,\n },\n },\n ];\n });\n return { edges, markers };\n }\n}\n\nconst SUPERVISION_ROBOFLOW_COLOR = 0xa351fb;\nconst DEFAULT_DETECTION_COLOR_SEQUENCE = [\n createClassColorStyle(0x38bdf8, 0x164e63, 0xecfeff, 0x7dd3fc),\n createClassColorStyle(0x22c55e, 0x14532d, 0xf0fdf4, 0x86efac),\n createClassColorStyle(0xa78bfa, 0x4c1d95, 0xf5f3ff, 0xc4b5fd),\n createClassColorStyle(0xfacc15, 0x713f12, 0xfffbeb, 0xfde047),\n createClassColorStyle(0xf97316, 0x7c2d12, 0xfff7ed, 0xffa23a),\n createClassColorStyle(0xf472b6, 0x831843, 0xfdf2f8, 0xf9a8d4),\n createClassColorStyle(0x60a5fa, 0x1e3a8a, 0xeff6ff, 0x93c5fd),\n createClassColorStyle(0xfb7185, 0x881337, 0xfff1f2, 0xfda4af),\n createClassColorStyle(0x34d399, 0x064e3b, 0xecfdf5, 0x6ee7b7),\n createClassColorStyle(0xe879f9, 0x701a75, 0xfdf4ff, 0xf0abfc),\n];\nconst DEFAULT_DETECTION_CLASS_STYLES = {\n basketball: DEFAULT_DETECTION_COLOR_SEQUENCE[4],\n bed: DEFAULT_DETECTION_COLOR_SEQUENCE[5],\n bottle: DEFAULT_DETECTION_COLOR_SEQUENCE[4],\n \"cell phone\": DEFAULT_DETECTION_COLOR_SEQUENCE[8],\n cow: DEFAULT_DETECTION_COLOR_SEQUENCE[2],\n cup: DEFAULT_DETECTION_COLOR_SEQUENCE[3],\n horse: DEFAULT_DETECTION_COLOR_SEQUENCE[0],\n keyboard: DEFAULT_DETECTION_COLOR_SEQUENCE[1],\n knife: DEFAULT_DETECTION_COLOR_SEQUENCE[7],\n laptop: DEFAULT_DETECTION_COLOR_SEQUENCE[6],\n person: DEFAULT_DETECTION_COLOR_SEQUENCE[1],\n \"potted plant\": DEFAULT_DETECTION_COLOR_SEQUENCE[8],\n \"sports ball\": DEFAULT_DETECTION_COLOR_SEQUENCE[4],\n tv: DEFAULT_DETECTION_COLOR_SEQUENCE[2],\n \"white team player\": createClassColorStyle(0xf8fafc, 0x334155, 0xffffff, 0xffffff),\n \"yellow team player\": DEFAULT_DETECTION_COLOR_SEQUENCE[3],\n};\n// The \"worklet\" directives below are inert everywhere except React Native:\n// browsers and Node see a no-op string, while React Native's worklets Babel\n// plugin makes these functions callable inside frame worklets, so every\n// platform resolves detection colors through this one implementation.\n// Worklet constraint on ordering: the plugin turns marked declarations into\n// non-hoisted assignments that capture each other at module-init time, so\n// helpers must be defined before the functions that call them.\nfunction normalizeDetectionClassName(className) {\n \"worklet\";\n return (className ?? \"\")\n .trim()\n .toLowerCase()\n .replace(/[_-]/g, \" \")\n .replace(/\\s+/g, \" \");\n}\nfunction hashClassName(className) {\n \"worklet\";\n let hash = 0;\n for (let index = 0; index < className.length; index += 1) {\n hash = (hash * 31 + className.charCodeAt(index)) >>> 0;\n }\n return hash;\n}\nfunction resolveDetectionClassColorStyle(className) {\n \"worklet\";\n const normalizedClassName = normalizeDetectionClassName(className);\n const knownStyle = DEFAULT_DETECTION_CLASS_STYLES[normalizedClassName];\n if (knownStyle) {\n return knownStyle;\n }\n return DEFAULT_DETECTION_COLOR_SEQUENCE[hashClassName(normalizedClassName) % DEFAULT_DETECTION_COLOR_SEQUENCE.length];\n}\nfunction createClassColorStyle(fill, labelBackground, labelText, stroke) {\n return {\n fill,\n labelBackground,\n labelText,\n stroke,\n };\n}\n\nconst DEFAULT_BOX_CORNER_RADIUS = 1;\nconst DEFAULT_OUTLINE_WIDTH = 2;\nconst DEFAULT_FILL_ALPHA = 0.08;\nconst DEFAULT_MASK_FILL_ALPHA = 0.45;\nconst DEFAULT_KEYPOINT_EDGE_WIDTH = 1.5;\nconst DEFAULT_KEYPOINT_SHADOW_WIDTH = 3;\nconst DEFAULT_KEYPOINT_SHADOW_ALPHA = 0.25;\nconst DEFAULT_KEYPOINT_RADIUS = 3.5;\nconst DEFAULT_LABEL_CORNER_RADIUS = 4;\nconst DEFAULT_LABEL_PADDING_X = 6;\nconst DEFAULT_LABEL_PADDING_Y = 3;\nconst DEFAULT_LABEL_FONT_SIZE = 12;\nconst DEFAULT_LABEL_FONT_FAMILY = \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace\";\n/**\n * Builds the canonical, unselected annotation presentation used by Roboflow's\n * Core annotation editor. It deliberately excludes host-specific interaction,\n * editing, focus, and theme behaviour so consumers can compose those layers.\n */\nfunction createDefaultAnnotationPresentation(options = {}) {\n const getClassColor = (detection) => resolveDefaultClassColor(detection, options.getClassColor);\n const shouldRenderBox = (detection) => !(detection.mask ||\n detection.polygon ||\n detection.polyline ||\n detection.keypoints);\n return {\n boxStyle: new BaseBoxStyle({\n cornerRadius: DEFAULT_BOX_CORNER_RADIUS,\n fill: (detection) => ({\n alpha: DEFAULT_FILL_ALPHA,\n color: getClassColor(detection),\n }),\n shape: BoxShape.RoundedRect,\n shouldRender: shouldRenderBox,\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n }),\n keypointStyle: new BaseKeypointStyle({\n ...(options.skeletonDefinitions === undefined\n ? {}\n : { definitions: options.skeletonDefinitions }),\n edgeShadowStroke: {\n alpha: DEFAULT_KEYPOINT_SHADOW_ALPHA,\n color: 0x000000,\n width: DEFAULT_KEYPOINT_SHADOW_WIDTH,\n },\n edgeStroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_KEYPOINT_EDGE_WIDTH,\n }),\n markerFill: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n }),\n markerStroke: { alpha: 1, color: 0xffffff, width: 1 },\n radius: DEFAULT_KEYPOINT_RADIUS,\n }),\n labelStyle: new BaseLabelStyle({\n background: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n cornerRadius: DEFAULT_LABEL_CORNER_RADIUS,\n paddingX: DEFAULT_LABEL_PADDING_X,\n paddingY: DEFAULT_LABEL_PADDING_Y,\n topCornersOnly: true,\n }),\n includeConfidence: options.includeConfidence,\n placement: LabelPlacement.Top,\n textStyle: {\n fontFamily: DEFAULT_LABEL_FONT_FAMILY,\n fontSize: DEFAULT_LABEL_FONT_SIZE,\n fontWeight: \"600\",\n },\n }),\n maskStyle: new BaseMaskStyle({\n color: (detection) => getClassColor(detection),\n fillAlpha: DEFAULT_MASK_FILL_ALPHA,\n mode: MaskRenderMode.FillAndStroke,\n opacity: 1,\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n }),\n polygonStyle: new BasePolygonStyle({\n fill: (detection) => ({\n alpha: DEFAULT_FILL_ALPHA,\n color: getClassColor(detection),\n }),\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n }),\n polylineStyle: new BasePolylineStyle({\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n }),\n };\n}\nfunction resolveDefaultClassColor(detection, getClassColor) {\n const color = getClassColor?.(detection.className);\n return typeof color === \"number\" && Number.isFinite(color)\n ? color\n : resolveDetectionClassColorStyle(detection.className).fill;\n}\n\nfunction createSourceAwarePresentation(globalPresentation = {}, sources) {\n if (!sources.some((source) => source.presentation !== undefined)) {\n return globalPresentation;\n }\n const sourcePresentations = new Map(sources.map((source) => [source.id, source.presentation]));\n return {\n ...globalPresentation,\n boxStyle: hasSourceStyle(sources, \"boxStyle\")\n ? new SourceAwareBoxStyle(normalizeGlobalBoxStyle(globalPresentation.boxStyle), sourcePresentations)\n : globalPresentation.boxStyle,\n labelStyle: hasSourceStyle(sources, \"labelStyle\")\n ? new SourceAwareLabelStyle(normalizeGlobalLabelStyle(globalPresentation.labelStyle), sourcePresentations)\n : globalPresentation.labelStyle,\n maskStyle: hasSourceStyle(sources, \"maskStyle\")\n ? new SourceAwareMaskStyle(normalizeGlobalMaskStyle(globalPresentation.maskStyle), sourcePresentations)\n : globalPresentation.maskStyle,\n polygonStyle: hasSourceStyle(sources, \"polygonStyle\")\n ? new SourceAwarePolygonStyle(normalizeGlobalPolygonStyle(globalPresentation.polygonStyle), sourcePresentations)\n : globalPresentation.polygonStyle,\n polylineStyle: hasSourceStyle(sources, \"polylineStyle\")\n ? new SourceAwarePolylineStyle(normalizeGlobalPolylineStyle(globalPresentation.polylineStyle), sourcePresentations)\n : globalPresentation.polylineStyle,\n keypointStyle: hasSourceStyle(sources, \"keypointStyle\")\n ? new SourceAwareKeypointStyle(normalizeGlobalKeypointStyle(globalPresentation.keypointStyle), sourcePresentations)\n : globalPresentation.keypointStyle,\n };\n}\nclass SourceAwareBoxStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"boxStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwareLabelStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"labelStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwareMaskStyle {\n globalStyle;\n sourcePresentations;\n artifactKey = undefined;\n opacity;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n this.opacity = globalStyle?.opacity;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"maskStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwarePolygonStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"polygonStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwarePolylineStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"polylineStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwareKeypointStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"keypointStyle\");\n return style?.resolve(detection, context);\n }\n}\nfunction hasSourceStyle(sources, key) {\n return sources.some((source) => source.presentation?.[key] !== undefined);\n}\nfunction resolveSourceStyle(detection, globalStyle, sourcePresentations, key) {\n const sourcePresentation = detection.sourceId\n ? sourcePresentations.get(detection.sourceId)\n : undefined;\n const sourceStyle = sourcePresentation?.[key];\n return sourceStyle === undefined ? globalStyle : sourceStyle;\n}\nfunction normalizeGlobalBoxStyle(style) {\n return style === undefined ? new BaseBoxStyle() : style;\n}\nfunction normalizeGlobalLabelStyle(style) {\n return style === undefined ? new BaseLabelStyle() : style;\n}\nfunction normalizeGlobalMaskStyle(style) {\n return style === undefined ? new BaseMaskStyle() : style;\n}\nfunction normalizeGlobalPolygonStyle(style) {\n return style === undefined ? new BasePolygonStyle() : style;\n}\nfunction normalizeGlobalPolylineStyle(style) {\n return style === undefined ? new BasePolylineStyle() : style;\n}\nfunction normalizeGlobalKeypointStyle(style) {\n return style === undefined ? new BaseKeypointStyle() : style;\n}\n\nvar DetectionMaskPayloadFormat;\n(function (DetectionMaskPayloadFormat) {\n DetectionMaskPayloadFormat[\"RawCocoRle\"] = \"rawCocoRle\";\n DetectionMaskPayloadFormat[\"DeflatedBase64\"] = \"deflatedBase64\";\n})(DetectionMaskPayloadFormat || (DetectionMaskPayloadFormat = {}));\nfunction 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/** Encodes a binary mask and derives its bounds in the same raster traversal. */\nfunction encodeBinaryMaskWithBounds(data, width, height) {\n assertMaskDimensions(data, width, height);\n const runs = [];\n let currentValue = 0;\n let runLength = 0;\n let minX = width;\n let minY = height;\n let maxX = -1;\n let maxY = -1;\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) {\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\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 bounds: maxX < 0\n ? null\n : {\n height: maxY - minY + 1,\n width: maxX - minX + 1,\n x: minX + (maxX - minX + 1) / 2,\n y: minY + (maxY - minY + 1) / 2,\n },\n mask: {\n counts: encodeCompressedRleCounts(runs),\n encoding: DetectionMaskEncoding.CompressedRle,\n height,\n width,\n },\n };\n}\nfunction encodeDetectionMaskPayload(mask, codec) {\n return codec ? codec.deflate(mask.counts) : mask.counts;\n}\nfunction decodeDetectionMaskPayload(payload, width, height, options = {}) {\n const format = options.format ??\n (isDeflatedBase64DetectionMaskPayload(payload)\n ? DetectionMaskPayloadFormat.DeflatedBase64\n : DetectionMaskPayloadFormat.RawCocoRle);\n if (format === DetectionMaskPayloadFormat.DeflatedBase64 && !options.codec) {\n throw new Error(\"A detection mask compression codec is required for deflated payloads.\");\n }\n return {\n counts: format === DetectionMaskPayloadFormat.DeflatedBase64\n ? options.codec.inflate(payload)\n : payload,\n encoding: DetectionMaskEncoding.CompressedRle,\n height,\n width,\n };\n}\n/** Matches the annotation editor's legacy transport-format heuristic. */\nfunction isDeflatedBase64DetectionMaskPayload(value) {\n return value.length > 100 && /^[A-Za-z0-9+/]+={0,2}$/.test(value);\n}\nfunction computeMaskBounds(data, width, height) {\n assertMaskDimensions(data, width, height);\n let minX = width;\n let minY = height;\n let maxX = -1;\n let maxY = -1;\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n if (!data[y * width + x]) {\n continue;\n }\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n }\n if (maxX < 0) {\n return null;\n }\n const boundsWidth = maxX - minX + 1;\n const boundsHeight = maxY - minY + 1;\n return {\n height: boundsHeight,\n width: boundsWidth,\n x: minX + boundsWidth / 2,\n y: minY + boundsHeight / 2,\n };\n}\nfunction computeDetectionMaskRect(mask) {\n const decoded = decodeCompressedRleMask(mask);\n const bounds = computeMaskBounds(decoded.data, decoded.width, decoded.height);\n return bounds ?? undefined;\n}\nfunction detectMaskBorders(data, width, height) {\n assertMaskDimensions(data, width, height);\n const borders = new Uint8Array(data.length);\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const offset = y * width + x;\n if (!data[offset]) {\n continue;\n }\n if (x === 0 ||\n y === 0 ||\n x === width - 1 ||\n y === height - 1 ||\n !data[offset - 1] ||\n !data[offset + 1] ||\n !data[offset - width] ||\n !data[offset + width]) {\n borders[offset] = 1;\n }\n }\n }\n return borders;\n}\nfunction extractMaskContour(data, width, height) {\n assertMaskDimensions(data, width, height);\n const stride = Math.max(1, Math.floor(height / 100));\n const leftEdge = [];\n const rightEdge = [];\n for (let y = 0; y < height; y += stride) {\n let left = -1;\n let right = -1;\n for (let x = 0; x < width; x += 1) {\n if (data[y * width + x]) {\n left = left === -1 ? x : left;\n right = x;\n }\n }\n if (left !== -1) {\n leftEdge.push({ x: left, y });\n rightEdge.push({ x: right, y });\n }\n }\n return leftEdge.length < 2\n ? undefined\n : [...leftEdge, ...rightEdge.reverse()];\n}\nfunction extractMaskRectRuns(data, width, height) {\n assertMaskDimensions(data, width, height);\n const rects = [];\n const openRects = new Map();\n for (let y = 0; y < height; y += 1) {\n const activeSpans = new Set();\n let x = 0;\n while (x < width) {\n while (x < width && !data[y * width + x]) {\n x += 1;\n }\n if (x >= width) {\n break;\n }\n const startX = x;\n while (x < width && data[y * width + x]) {\n x += 1;\n }\n const runWidth = x - startX;\n const key = `${startX}:${runWidth}`;\n const openRect = openRects.get(key);\n activeSpans.add(key);\n if (openRect && openRect.y + openRect.height === y) {\n openRects.set(key, { ...openRect, height: openRect.height + 1 });\n }\n else {\n if (openRect) {\n rects.push(openRect);\n }\n openRects.set(key, { height: 1, width: runWidth, x: startX, y });\n }\n }\n for (const [key, openRect] of openRects) {\n if (!activeSpans.has(key)) {\n rects.push(openRect);\n openRects.delete(key);\n }\n }\n }\n rects.push(...openRects.values());\n return rects.length > 0 ? rects : undefined;\n}\nfunction 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\nfunction rectToPolygon(rect) {\n const halfWidth = rect.width / 2;\n const halfHeight = rect.height / 2;\n return {\n points: [\n { x: rect.x - halfWidth, y: rect.y - halfHeight },\n { x: rect.x + halfWidth, y: rect.y - halfHeight },\n { x: rect.x + halfWidth, y: rect.y + halfHeight },\n { x: rect.x - halfWidth, y: rect.y + halfHeight },\n ],\n };\n}\nfunction polygonToRect(polygon) {\n return getPointsRect(polygon.points);\n}\nfunction rasterizeRectToMask(rect, dimensions) {\n const data = createEmptyMask(dimensions);\n const topLeft = centerRectToTopLeftRect(rect);\n const left = Math.max(0, Math.round(topLeft.x));\n const top = Math.max(0, Math.round(topLeft.y));\n const right = Math.min(dimensions.width - 1, Math.round(rect.x + rect.width / 2));\n const bottom = Math.min(dimensions.height - 1, Math.round(rect.y + rect.height / 2));\n for (let y = top; y <= bottom; y += 1) {\n for (let x = left; x <= right; x += 1) {\n data[y * dimensions.width + x] = 1;\n }\n }\n return data;\n}\nfunction 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}\nfunction convertDetectionBoxToPolygon(detection) {\n return detection.rect\n ? replaceGeometry(detection, { polygon: rectToPolygon(detection.rect) })\n : detection;\n}\nfunction convertDetectionPolygonToBox(detection) {\n const rect = detection.polygon ? polygonToRect(detection.polygon) : undefined;\n return rect ? replaceGeometry(detection, { rect }) : detection;\n}\nfunction convertDetectionMaskToBox(detection) {\n const rect = detection.mask\n ? computeDetectionMaskRect(detection.mask)\n : undefined;\n return rect ? replaceGeometry(detection, { rect }) : detection;\n}\nfunction convertDetectionMaskToPolygon(detection) {\n if (!detection.mask) {\n return detection;\n }\n const decoded = decodeCompressedRleMask(detection.mask);\n const contour = extractMaskContour(decoded.data, decoded.width, decoded.height);\n const fallbackRect = computeDetectionMaskRect(detection.mask);\n const polygon = contour && contour.length >= 3\n ? { points: contour }\n : fallbackRect\n ? rectToPolygon(fallbackRect)\n : undefined;\n return polygon ? replaceGeometry(detection, { polygon }) : detection;\n}\nfunction convertDetectionBoxToMask(detection, dimensions) {\n if (!detection.rect) {\n return detection;\n }\n const mask = encodeBinaryMask(rasterizeRectToMask(detection.rect, dimensions), dimensions.width, dimensions.height);\n return replaceGeometry(detection, { mask });\n}\nfunction convertDetectionPolygonToMask(detection, dimensions) {\n if (!detection.polygon) {\n return detection;\n }\n const mask = encodeBinaryMask(rasterizePolygonToMask(detection.polygon.points, dimensions), dimensions.width, dimensions.height);\n return replaceGeometry(detection, { mask });\n}\nfunction mergeDetectionMasks(detections) {\n if (detections.length < 2 || detections.some(({ mask }) => !mask)) {\n return null;\n }\n const first = detections[0];\n if (detections.some((detection) => detection.className !== first.className)) {\n return null;\n }\n const masks = detections.map(({ mask }) => decodeCompressedRleMask(mask));\n const width = masks[0].width;\n const height = masks[0].height;\n if (masks.some((mask) => mask.width !== width || mask.height !== height)) {\n throw new Error(\"Merged detection masks must have matching dimensions.\");\n }\n const data = new Uint8Array(width * height);\n for (const mask of masks) {\n for (let index = 0; index < data.length; index += 1) {\n data[index] ||= mask.data[index] ?? 0;\n }\n }\n return replaceGeometry(first, {\n mask: encodeBinaryMask(data, width, height),\n });\n}\n/**\n * Groups polygon detections by class and returns one union bounding-box\n * detection per class. This intentionally converts the output to rectangles.\n */\nfunction mergeDetectionPolygonsByClass(detections, options = {}) {\n const groups = new Map();\n for (const detection of detections) {\n if (!detection.polygon) {\n continue;\n }\n const group = groups.get(detection.className) ?? [];\n group.push(detection);\n groups.set(detection.className, group);\n }\n return [...groups.entries()].flatMap(([className, group], groupIndex) => {\n const points = group.flatMap((detection) => detection.polygon.points);\n const rect = getPointsRect(points);\n if (!rect) {\n return [];\n }\n const first = group[0];\n const id = options.createId?.(className, groupIndex) ?? first.id;\n return [\n replaceGeometry({\n ...first,\n id,\n }, { rect }),\n ];\n });\n}\nfunction 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}\nfunction replaceGeometry(detection, geometry) {\n return {\n ...detection,\n keypoints: undefined,\n mask: geometry.mask,\n polygon: geometry.polygon,\n polyline: undefined,\n rect: geometry.rect,\n };\n}\n\nfunction canReuseMaskStyleArtifacts(previousMaskStyle, nextMaskStyle) {\n if (previousMaskStyle === nextMaskStyle) {\n return true;\n }\n return (previousMaskStyle?.artifactKey !== undefined &&\n nextMaskStyle?.artifactKey !== undefined &&\n previousMaskStyle.artifactKey === nextMaskStyle.artifactKey);\n}\nfunction resolveMaskStyleOpacity(maskStyle) {\n const opacity = maskStyle?.opacity;\n if (opacity === undefined) {\n return 1;\n }\n return Number.isFinite(opacity) ? Math.max(0, Math.min(opacity, 1)) : 1;\n}\n\nconst MAX_ID_MASK_PALETTE_ENTRIES = 64;\nconst MAX_ID_MASK_STROKE_WIDTH = 16;\nfunction 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}\nfunction 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\nfunction includeDefined(values) {\n return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined));\n}\n\nfunction resolveAnnotationStyleState(detection, visibility) {\n const id = detection.id;\n return {\n hidden: visibility?.annotationsHidden === true ||\n (detection.className !== undefined &&\n includes(visibility?.hiddenClasses, detection.className)) ||\n (id !== undefined && includes(visibility?.hiddenDetectionIds, id)),\n loading: id !== undefined && includes(visibility?.loadingDetectionIds, id),\n ephemeral: id !== undefined && includes(visibility?.ephemeralDetectionIds, id),\n isCreating: id !== undefined && visibility?.creatingDetectionId === id,\n };\n}\nfunction includes(values, value) {\n if (!values)\n return false;\n return Array.isArray(values)\n ? values.includes(value)\n : values.has(value);\n}\n\nvar 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 */\nvar 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 */\nvar 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 */\nvar 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 */\nvar 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 */\nvar 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 */\nvar MediaSessionActivityStatus;\n(function (MediaSessionActivityStatus) {\n MediaSessionActivityStatus[\"Error\"] = \"error\";\n MediaSessionActivityStatus[\"Running\"] = \"running\";\n MediaSessionActivityStatus[\"Waiting\"] = \"waiting\";\n})(MediaSessionActivityStatus || (MediaSessionActivityStatus = {}));\n\nexport { AnnotationFrameMutationKind, AnnotationGeometryKind, AnnotationGestureStateKind, AnnotationHandleKind, BaseBoxStyle, BaseFocusStyle, BaseInteractionStyle, BaseKeypointStyle, BaseLabelStyle, BaseMaskStyle, BasePolygonStyle, BasePolylineStyle, BoxShape, BoxStrokeAlignment, DEFAULT_DETECTION_CLASS_STYLES, DEFAULT_DETECTION_COLOR_SEQUENCE, DetectionBufferStatus, DetectionFrameRetentionMode, DetectionFrameSelectionMode, DetectionInteractionState, DetectionMaskEncoding, DetectionMaskPayloadFormat, DetectionPickTarget, FocusTargetMode, KeypointMarkerShape, KeypointVisibility, LabelPlacement, LabelVisibilityMode, MAX_ID_MASK_PALETTE_ENTRIES, MAX_ID_MASK_STROKE_WIDTH, MaskRenderMode, MediaInteractionMode, MediaRendererFit, MediaRendererPlaybackState, MediaSessionActivityKind, MediaSessionActivityStatus, MediaSessionMode, MediaSessionStatus, MediaSourceStatus, SUPERVISION_ROBOFLOW_COLOR, applyAnnotationHandleDrag, canReuseMaskStyleArtifacts, centerRectToTopLeftRect, computeDetectionMaskRect, computeMaskBounds, containsPoint, convertDetectionBoxToMask, convertDetectionBoxToPolygon, convertDetectionMaskToBox, convertDetectionMaskToPolygon, convertDetectionPolygonToBox, convertDetectionPolygonToMask, copySortedDetectionFrames, createAnnotationEditingEngine, createArrayDetectionFrameSource, createBufferedDetectionTimeline, createColdDetectionFrameSource, createCompositeDetectionFrameSource, createDefaultAnnotationPresentation, createDetectionPickKey, createEditableAnnotationFrameSession, createIdMaskFrame, createIdleDetectionBufferState, createMemoryColdDetectionFrameStore, createSourceAwarePresentation, createViewportController, createWritableDetectionFrameSource, decodeCompressedRleCounts, decodeCompressedRleMask, decodeDetectionMaskPayload, deleteAnnotationVertex, detectMaskBorders, detectionFrameOverlapsRange, distanceToSegment, encodeBinaryMask, encodeBinaryMaskWithBounds, encodeCompressedRleCounts, encodeDetectionMaskPayload, extractMaskContour, extractMaskRectRuns, filterDetectionFramesForRange, findClosestAnnotationSegment, getAnnotationHandles, getBufferedDetectionTimelineFrameSnapshot, getDetectionRect, getPointsRect, includeDefined, isDeflatedBase64DetectionMaskPayload, lightenColor, mediaToScreen, mergeDetectionMasks, mergeDetectionPolygonsByClass, normalizeDetectionClassName, offsetDetection, pickAnnotationHandle, pickDetectionAtPoint, pickDetectionByMaskId, pointInPolygon, polygonArea, polygonToRect, rasterizePolygonToMask, rasterizeRectToMask, rebaseDetectionPickToFrame, rectArea, rectToPolygon, resolveAnnotationStyleState, resolveContrastTextColor, resolveDetectionClassColorStyle, resolveMaskStyleOpacity, resolveStyleValue, screenToMedia, selectDetectionFrame, topLeftRectToCenterRect, validateDetectionFrames };\n//# sourceMappingURL=index.js.map\n",null,null,null,null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mask-preparation.worker.js","sources":["../../core/dist/index.js","../src/render-preparation/mask-frame-compositor.ts","../src/render-preparation/mask-frame-artifact.ts","../src/render-preparation/mask-preparation-worker-protocol.ts","../src/render-preparation/mask-preparation.worker.ts"],"sourcesContent":["/** COCO-compatible keypoint visibility values. */\nvar 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 = {}));\nvar DetectionMaskEncoding;\n(function (DetectionMaskEncoding) {\n DetectionMaskEncoding[\"CompressedRle\"] = \"compressedRle\";\n})(DetectionMaskEncoding || (DetectionMaskEncoding = {}));\n\nvar 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 */\nvar 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 = {}));\nvar 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\nfunction copySortedDetectionFrames(detectionFrames) {\n validateDetectionFrames(detectionFrames ?? []);\n return (detectionFrames ?? [])\n .map((frame) => ({\n detections: frame.detections.map((detection) => ({\n ...detection,\n attributes: detection.attributes\n ? [...detection.attributes]\n : undefined,\n keypoints: detection.keypoints\n ? {\n edges: detection.keypoints.edges.map((edge) => [edge[0], edge[1]]),\n points: detection.keypoints.points.map((point) => ({ ...point })),\n visibility: detection.keypoints.visibility\n ? [...detection.keypoints.visibility]\n : undefined,\n }\n : undefined,\n mask: detection.mask ? { ...detection.mask } : undefined,\n metadata: detection.metadata\n ? copyDetectionMetadata(detection.metadata)\n : undefined,\n polygon: detection.polygon\n ? {\n points: detection.polygon.points.map((point) => ({ ...point })),\n }\n : undefined,\n polyline: detection.polyline\n ? {\n points: detection.polyline.points.map((point) => ({ ...point })),\n }\n : undefined,\n rect: detection.rect ? { ...detection.rect } : undefined,\n })),\n endTime: frame.endTime,\n frameIndex: frame.frameIndex,\n mediaTime: frame.mediaTime,\n }))\n .sort((left, right) => left.mediaTime - right.mediaTime);\n}\nfunction copyDetectionMetadata(metadata) {\n const clone = globalThis.structuredClone;\n if (clone) {\n return clone(metadata);\n }\n return copyMetadataValue(metadata);\n}\nfunction copyMetadataValue(value) {\n if (Array.isArray(value)) {\n return value.map(copyMetadataValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(Object.entries(value).map(([key, child]) => [\n key,\n copyMetadataValue(child),\n ]));\n }\n return value;\n}\nfunction validateDetectionFrames(detectionFrames) {\n for (const [frameOffset, frame] of detectionFrames.entries()) {\n validateNumber(frame.mediaTime, `frames[${frameOffset}].mediaTime`, {\n min: 0,\n });\n if (frame.endTime !== undefined) {\n validateNumber(frame.endTime, `frames[${frameOffset}].endTime`, {\n exclusiveMin: frame.mediaTime,\n });\n }\n if (frame.frameIndex !== undefined) {\n validateNumber(frame.frameIndex, `frames[${frameOffset}].frameIndex`, {\n integer: true,\n min: 0,\n });\n }\n for (const [detectionOffset, detection] of frame.detections.entries()) {\n const detectionPath = `frames[${frameOffset}].detections[${detectionOffset}]`;\n if (detection.confidence !== undefined) {\n validateNumber(detection.confidence, `${detectionPath}.confidence`, {\n max: 1,\n min: 0,\n });\n }\n if (detection.zIndex !== undefined) {\n validateNumber(detection.zIndex, `${detectionPath}.zIndex`);\n }\n if (detection.sourceId !== undefined &&\n typeof detection.sourceId !== \"string\") {\n throw new Error(`${detectionPath}.sourceId must be a string.`);\n }\n if (detection.sourceDetectionIndex !== undefined) {\n validateNumber(detection.sourceDetectionIndex, `${detectionPath}.sourceDetectionIndex`, {\n integer: true,\n min: 0,\n });\n }\n if (detection.rect) {\n validateNumber(detection.rect.x, `${detectionPath}.rect.x`);\n validateNumber(detection.rect.y, `${detectionPath}.rect.y`);\n validateNumber(detection.rect.width, `${detectionPath}.rect.width`, {\n exclusiveMin: 0,\n });\n validateNumber(detection.rect.height, `${detectionPath}.rect.height`, {\n exclusiveMin: 0,\n });\n }\n validatePoints(detection.polygon?.points, `${detectionPath}.polygon`, 3);\n validatePoints(detection.polyline?.points, `${detectionPath}.polyline`, 2);\n if (detection.keypoints) {\n validatePoints(detection.keypoints.points, `${detectionPath}.keypoints`, 1);\n if (detection.keypoints.visibility !== undefined &&\n detection.keypoints.visibility.length !==\n detection.keypoints.points.length) {\n throw new Error(`${detectionPath}.keypoints.visibility must match points length.`);\n }\n for (const [edgeOffset, edge] of detection.keypoints.edges.entries()) {\n const edgePath = `${detectionPath}.keypoints.edges[${edgeOffset}]`;\n for (const [endpointOffset, endpoint] of edge.entries()) {\n validateNumber(endpoint, `${edgePath}[${endpointOffset}]`, {\n integer: true,\n min: 0,\n });\n if (endpoint >= detection.keypoints.points.length) {\n throw new Error(`${edgePath}[${endpointOffset}] is out of range.`);\n }\n }\n }\n }\n if (detection.mask) {\n validateNumber(detection.mask.width, `${detectionPath}.mask.width`, {\n integer: true,\n exclusiveMin: 0,\n });\n validateNumber(detection.mask.height, `${detectionPath}.mask.height`, {\n integer: true,\n exclusiveMin: 0,\n });\n if (detection.mask.counts.length === 0) {\n throw new Error(`${detectionPath}.mask.counts must not be empty.`);\n }\n }\n }\n }\n}\nfunction validatePoints(points, path, minimumLength) {\n if (!points) {\n return;\n }\n if (points.length < minimumLength) {\n throw new Error(`${path}.points must contain at least ${minimumLength} points.`);\n }\n for (const [pointOffset, point] of points.entries()) {\n validateNumber(point.x, `${path}.points[${pointOffset}].x`);\n validateNumber(point.y, `${path}.points[${pointOffset}].y`);\n }\n}\nfunction validateNumber(value, path, options = {}) {\n if (!Number.isFinite(value)) {\n throw new Error(`${path} must be a finite number.`);\n }\n if (options.integer && !Number.isInteger(value)) {\n throw new Error(`${path} must be an integer.`);\n }\n if (options.min !== undefined && value < options.min) {\n throw new Error(`${path} must be greater than or equal to ${options.min}.`);\n }\n if (options.exclusiveMin !== undefined && value <= options.exclusiveMin) {\n throw new Error(`${path} must be greater than ${options.exclusiveMin}.`);\n }\n if (options.max !== undefined && value > options.max) {\n throw new Error(`${path} must be less than or equal to ${options.max}.`);\n }\n}\nfunction filterDetectionFramesForRange(detectionFrames, startTime, endTime) {\n return detectionFrames.filter((frame) => detectionFrameOverlapsRange(frame, startTime, endTime));\n}\nfunction selectDetectionFrame(detectionFrames, mediaTime, options = {}) {\n if (options.selectionMode === DetectionFrameSelectionMode.NearestFrameIndex) {\n const selection = selectNearestFrameIndexDetectionFrame(detectionFrames, mediaTime, options.frameRate, options.frameIndexOriginTime);\n if (selection.isApplicable) {\n return selection.frame;\n }\n }\n return selectIntervalDetectionFrame(detectionFrames, mediaTime);\n}\nfunction 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}\nfunction selectIntervalDetectionFrame(detectionFrames, mediaTime) {\n let selectedFrame;\n let low = 0;\n let high = detectionFrames.length - 1;\n while (low <= high) {\n const middle = Math.floor((low + high) / 2);\n const frame = detectionFrames[middle];\n if (frame.mediaTime <= mediaTime) {\n selectedFrame = frame;\n low = middle + 1;\n }\n else {\n high = middle - 1;\n }\n }\n return selectedFrame && isDetectionFrameActive(selectedFrame, mediaTime)\n ? selectedFrame\n : undefined;\n}\nfunction selectNearestFrameIndexDetectionFrame(detectionFrames, mediaTime, frameRate, frameIndexOriginTime) {\n if (!frameRate || !Number.isFinite(frameRate) || frameRate <= 0) {\n return { frame: undefined, isApplicable: false };\n }\n const firstIndexedFrame = detectionFrames.find((frame) => frame.frameIndex !== undefined);\n if (!firstIndexedFrame || firstIndexedFrame.frameIndex === undefined) {\n return { frame: undefined, isApplicable: false };\n }\n const originTime = frameIndexOriginTime !== undefined\n ? frameIndexOriginTime\n : firstIndexedFrame.mediaTime - firstIndexedFrame.frameIndex / frameRate;\n const targetFrameIndex = Math.round((mediaTime - originTime) * frameRate);\n let nearestFrame;\n let nearestDistance = Number.POSITIVE_INFINITY;\n for (const frame of detectionFrames) {\n if (frame.frameIndex === undefined) {\n continue;\n }\n const distance = Math.abs(frame.frameIndex - targetFrameIndex);\n if (distance < nearestDistance ||\n (distance === nearestDistance &&\n nearestFrame?.frameIndex !== undefined &&\n frame.frameIndex > nearestFrame.frameIndex)) {\n nearestFrame = frame;\n nearestDistance = distance;\n }\n }\n return {\n frame: nearestDistance <= 1 ? nearestFrame : undefined,\n isApplicable: true,\n };\n}\nfunction isDetectionFrameActive(frame, mediaTime) {\n return (frame.mediaTime <= mediaTime &&\n (frame.endTime === undefined || mediaTime < frame.endTime));\n}\nfunction detectionFrameOverlapsRange(frame, startTime, endTime) {\n if (frame.endTime === undefined) {\n return frame.mediaTime >= startTime && frame.mediaTime <= endTime;\n }\n return frame.mediaTime <= endTime && frame.endTime > startTime;\n}\nfunction 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}\nfunction 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\nfunction createArrayDetectionFrameSource(frames) {\n const sortedFrames = copySortedDetectionFrames(frames);\n return {\n async loadFrames(startTime, endTime) {\n return copySortedDetectionFrames(filterDetectionFramesForRange(sortedFrames, startTime, endTime));\n },\n };\n}\n\nconst DEFAULT_BUFFER_AHEAD_SECONDS = 5;\nconst DEFAULT_BUFFER_BEHIND_SECONDS = 0.5;\nconst bufferedFrameSnapshots = new WeakMap();\n/**\n * Returns the timeline-owned hot-buffer snapshot without copying it.\n *\n * This is an internal platform-adapter fast path. Public callers should use\n * `getBufferedFrames()`, which preserves the existing defensive-copy contract.\n */\nfunction getBufferedDetectionTimelineFrameSnapshot(timeline) {\n return (bufferedFrameSnapshots.get(timeline)?.() ?? timeline.getBufferedFrames());\n}\nfunction createBufferedDetectionTimeline(options) {\n const bufferAheadSeconds = options.bufferAheadSeconds ?? DEFAULT_BUFFER_AHEAD_SECONDS;\n const bufferBehindSeconds = options.bufferBehindSeconds ?? DEFAULT_BUFFER_BEHIND_SECONDS;\n const refreshIntervalSeconds = options.refreshIntervalSeconds === undefined\n ? null\n : Math.max(0, options.refreshIntervalSeconds);\n const playbackGate = options.playbackGate;\n let buffer = [];\n let state = createIdleDetectionBufferState();\n let destroyed = false;\n let loadId = 0;\n let bufferedSourceVersion = null;\n let bufferedVersionRange = null;\n let timelineContext = {\n duration: null,\n loop: false,\n };\n let inFlight;\n let incrementalRefresh;\n let pendingPrefetch;\n let prefetchPump;\n const getSourceVersion = (ranges) => {\n if (!ranges) {\n return options.source.getVersion?.() ?? 0;\n }\n return ranges.reduce((version, range) => Math.max(version, options.source.getVersion?.(range) ?? 0), 0);\n };\n const isBufferFresh = () => bufferedVersionRange !== null &&\n bufferedSourceVersion === getSourceVersion(getBufferedSourceRanges());\n const getLoadRange = (mediaTime) => {\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n const startTime = comparableMediaTime - bufferBehindSeconds;\n const endTime = comparableMediaTime + bufferAheadSeconds;\n return createLoadPlan(startTime, endTime);\n };\n const loadWindow = (mediaTime) => {\n const { endTime, sourceRanges, startTime } = getLoadRange(mediaTime);\n const versionRange = { endTime, startTime };\n const sourceVersion = getSourceVersion(sourceRanges);\n if (inFlight &&\n inFlight.sourceVersion === sourceVersion &&\n rangeContains(inFlight.startTime, inFlight.endTime, startTime, endTime)) {\n return inFlight.promise;\n }\n const currentLoadId = loadId + 1;\n loadId = currentLoadId;\n state = {\n ...state,\n errorMessage: null,\n requestedEndTime: endTime,\n requestedStartTime: startTime,\n status: DetectionBufferStatus.Loading,\n };\n const promise = Promise.all(sourceRanges.map((range) => options.source.loadFrames(range.startTime, range.endTime)))\n .then((frameRanges) => {\n if (destroyed || currentLoadId !== loadId) {\n return;\n }\n const committedSourceVersion = getSourceVersion(sourceRanges);\n const loadedBuffer = copySortedDetectionFrames(frameRanges.flat());\n buffer =\n bufferedSourceVersion !== null &&\n bufferedSourceVersion === committedSourceVersion\n ? reuseBufferedFrameSnapshots(buffer, loadedBuffer)\n : loadedBuffer;\n bufferedVersionRange = versionRange;\n bufferedSourceVersion = committedSourceVersion;\n state = {\n bufferEndTime: endTime,\n bufferStartTime: startTime,\n detectionCount: countDetections(buffer),\n errorMessage: null,\n frameCount: buffer.length,\n requestedEndTime: endTime,\n requestedStartTime: startTime,\n status: DetectionBufferStatus.Ready,\n };\n })\n .catch((error) => {\n if (!destroyed && currentLoadId === loadId) {\n state = {\n ...state,\n errorMessage: getErrorMessage(error),\n status: DetectionBufferStatus.Error,\n };\n }\n throw error;\n })\n .finally(() => {\n if (inFlight?.id === currentLoadId) {\n inFlight = undefined;\n }\n });\n inFlight = {\n endTime,\n id: currentLoadId,\n promise,\n sourceVersion,\n startTime,\n };\n return promise;\n };\n const isBuffered = (mediaTime) => {\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n return (isBufferFresh() &&\n state.bufferStartTime !== null &&\n state.bufferEndTime !== null &&\n comparableMediaTime >= state.bufferStartTime &&\n comparableMediaTime <= state.bufferEndTime);\n };\n const isInsideBufferedRange = (mediaTime) => {\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n return (bufferedVersionRange !== null &&\n state.bufferStartTime !== null &&\n state.bufferEndTime !== null &&\n comparableMediaTime >= state.bufferStartTime &&\n comparableMediaTime <= state.bufferEndTime);\n };\n const refreshBuffer = async (mediaTime) => {\n if (isBuffered(mediaTime)) {\n return;\n }\n if (isInsideBufferedRange(mediaTime) &&\n bufferedSourceVersion !== null &&\n options.source.getChangesSince) {\n if (!incrementalRefresh) {\n incrementalRefresh = applyIncrementalChanges().finally(() => {\n incrementalRefresh = undefined;\n });\n }\n await incrementalRefresh;\n if (isBuffered(mediaTime)) {\n return;\n }\n return refreshBuffer(mediaTime);\n }\n await loadWindow(mediaTime);\n };\n const shouldPrefetch = (mediaTime) => {\n if (!isBuffered(mediaTime)) {\n return true;\n }\n if (shouldRefreshRollingWindow(mediaTime)) {\n return true;\n }\n if (state.bufferEndTime === null || bufferAheadSeconds <= 0) {\n return false;\n }\n return (getComparableMediaTime(mediaTime) + bufferAheadSeconds / 2 >=\n state.bufferEndTime);\n };\n const timeline = {\n async prepare(mediaTime, prepareOptions) {\n if (destroyed) {\n return;\n }\n if (shouldWaitForPlaybackGate(prepareOptions)) {\n await waitForPlaybackGate(mediaTime, prepareOptions);\n if (destroyed) {\n return;\n }\n }\n await refreshBuffer(mediaTime);\n },\n prefetch(mediaTime) {\n if (destroyed || !shouldPrefetch(mediaTime)) {\n return;\n }\n pendingPrefetch = { loadId, mediaTime };\n pumpPrefetchQueue();\n },\n selectFrame(mediaTime) {\n if (!isBuffered(mediaTime)) {\n return undefined;\n }\n return selectDetectionFrame(buffer, getSourceMediaTime(mediaTime), options);\n },\n setTimelineContext(context) {\n timelineContext = context;\n bufferedSourceVersion = null;\n bufferedVersionRange = null;\n },\n getBufferedFrames() {\n return copySortedDetectionFrames(buffer);\n },\n getState() {\n return { ...state };\n },\n destroy() {\n if (destroyed) {\n return;\n }\n destroyed = true;\n pendingPrefetch = undefined;\n buffer = [];\n bufferedSourceVersion = null;\n bufferedVersionRange = null;\n state = {\n ...state,\n bufferEndTime: null,\n bufferStartTime: null,\n detectionCount: 0,\n frameCount: 0,\n status: DetectionBufferStatus.Destroyed,\n };\n options.source.destroy?.();\n },\n };\n bufferedFrameSnapshots.set(timeline, () => buffer);\n return timeline;\n function pumpPrefetchQueue() {\n if (destroyed || prefetchPump) {\n return;\n }\n prefetchPump = drainPrefetchQueue().finally(() => {\n prefetchPump = undefined;\n if (!destroyed && pendingPrefetch) {\n pumpPrefetchQueue();\n }\n });\n }\n async function drainPrefetchQueue() {\n while (!destroyed && pendingPrefetch) {\n if (inFlight) {\n await inFlight.promise.catch(() => undefined);\n continue;\n }\n const request = pendingPrefetch;\n pendingPrefetch = undefined;\n if (request.loadId !== loadId) {\n continue;\n }\n const { mediaTime } = request;\n if (!shouldPrefetch(mediaTime)) {\n continue;\n }\n await (shouldRefreshRollingWindow(mediaTime)\n ? loadWindow(mediaTime)\n : refreshBuffer(mediaTime)).catch(() => undefined);\n }\n }\n async function applyIncrementalChanges() {\n if (destroyed ||\n bufferedSourceVersion === null ||\n !options.source.getChangesSince) {\n return;\n }\n const sourceRanges = getBufferedSourceRanges();\n const incrementalLoadId = loadId;\n const incrementalVersionRange = bufferedVersionRange;\n const changes = options.source.getChangesSince(bufferedSourceVersion, sourceRanges);\n if (changes.requiresReload) {\n bufferedSourceVersion = null;\n return;\n }\n if (changes.ranges.length === 0) {\n bufferedSourceVersion = changes.version;\n return;\n }\n const changedRanges = getOverlappingRanges(changes.ranges, sourceRanges);\n if (changedRanges.length === 0) {\n bufferedSourceVersion = changes.version;\n return;\n }\n try {\n const changedFrameRanges = await Promise.all(changedRanges.map((range) => options.source.loadFrames(range.startTime, range.endTime)));\n if (destroyed ||\n loadId !== incrementalLoadId ||\n bufferedVersionRange !== incrementalVersionRange) {\n return;\n }\n buffer = mergeIncrementalFrames(buffer, changedFrameRanges.flat(), changedRanges);\n bufferedSourceVersion = changes.version;\n state = {\n ...state,\n detectionCount: countDetections(buffer),\n errorMessage: null,\n frameCount: buffer.length,\n status: DetectionBufferStatus.Ready,\n };\n }\n catch (error) {\n if (!destroyed) {\n state = {\n ...state,\n errorMessage: getErrorMessage(error),\n status: DetectionBufferStatus.Error,\n };\n }\n throw error;\n }\n }\n function shouldWaitForPlaybackGate(prepareOptions) {\n return (prepareOptions?.gatePlayback === true &&\n playbackGate?.enabled === true &&\n Boolean(options.source.waitForRange));\n }\n async function waitForPlaybackGate(mediaTime, prepareOptions) {\n if (!playbackGate?.enabled || !options.source.waitForRange) {\n return;\n }\n const requiredAheadSeconds = Math.max(0, playbackGate.requiredAheadSeconds ?? 0);\n const comparableMediaTime = getComparableMediaTime(mediaTime);\n const endTime = getRequiredCoverageEndTime({\n duration: isLoopingTimeline() ? null : prepareOptions?.duration,\n firstTimestamp: prepareOptions?.firstTimestamp,\n mediaTime: comparableMediaTime,\n requiredAheadSeconds,\n });\n if (endTime <= comparableMediaTime) {\n return;\n }\n const coveragePlan = createLoadPlan(comparableMediaTime, endTime);\n state = {\n ...state,\n errorMessage: null,\n requestedEndTime: coveragePlan.endTime,\n requestedStartTime: coveragePlan.startTime,\n status: DetectionBufferStatus.Loading,\n };\n try {\n await Promise.all(coveragePlan.sourceRanges.map((range) => options.source.waitForRange?.(range)));\n }\n catch (error) {\n if (!destroyed) {\n state = {\n ...state,\n errorMessage: getErrorMessage(error),\n status: DetectionBufferStatus.Error,\n };\n }\n throw error;\n }\n }\n function shouldRefreshRollingWindow(mediaTime) {\n if (refreshIntervalSeconds === null ||\n refreshIntervalSeconds <= 0 ||\n state.bufferStartTime === null ||\n state.bufferEndTime === null) {\n return false;\n }\n const { endTime, startTime } = getLoadRange(mediaTime);\n return (Math.abs(startTime - state.bufferStartTime) >= refreshIntervalSeconds ||\n Math.abs(endTime - state.bufferEndTime) >= refreshIntervalSeconds);\n }\n function createLoadPlan(requestedStartTime, requestedEndTime) {\n const startTime = Math.min(requestedStartTime, requestedEndTime);\n const endTime = Math.max(startTime, requestedEndTime);\n if (!isLoopingTimeline()) {\n const clampedStartTime = Math.max(0, startTime);\n const clampedEndTime = Math.max(clampedStartTime, endTime);\n return {\n endTime: clampedEndTime,\n sourceRanges: [\n {\n endTime: clampedEndTime,\n startTime: clampedStartTime,\n },\n ],\n startTime: clampedStartTime,\n };\n }\n const duration = timelineContext.duration ?? 0;\n if (endTime - startTime >= duration) {\n return {\n endTime: duration,\n sourceRanges: [{ endTime: duration, startTime: 0 }],\n startTime: 0,\n };\n }\n return {\n endTime,\n sourceRanges: getLoopingSourceRanges(startTime, endTime, duration),\n startTime,\n };\n }\n function getBufferedSourceRanges() {\n if (!bufferedVersionRange) {\n return [];\n }\n return createLoadPlan(bufferedVersionRange.startTime, bufferedVersionRange.endTime).sourceRanges;\n }\n function isLoopingTimeline() {\n return (timelineContext.loop &&\n timelineContext.duration !== null &&\n timelineContext.duration > 0);\n }\n function getComparableMediaTime(mediaTime) {\n if (!isLoopingTimeline() ||\n state.bufferStartTime === null ||\n state.bufferEndTime === null ||\n timelineContext.duration === null) {\n return mediaTime;\n }\n const duration = timelineContext.duration;\n let comparableMediaTime = mediaTime;\n while (comparableMediaTime < state.bufferStartTime) {\n comparableMediaTime += duration;\n }\n while (comparableMediaTime > state.bufferEndTime) {\n comparableMediaTime -= duration;\n }\n return comparableMediaTime;\n }\n function getSourceMediaTime(mediaTime) {\n if (!isLoopingTimeline() || timelineContext.duration === null) {\n return mediaTime;\n }\n if (mediaTime >= 0 && mediaTime <= timelineContext.duration) {\n return mediaTime;\n }\n return modulo(mediaTime, timelineContext.duration);\n }\n}\nfunction createIdleDetectionBufferState() {\n return {\n bufferEndTime: null,\n bufferStartTime: null,\n detectionCount: 0,\n errorMessage: null,\n frameCount: 0,\n requestedEndTime: null,\n requestedStartTime: null,\n status: DetectionBufferStatus.Idle,\n };\n}\nfunction rangeContains(outerStart, outerEnd, innerStart, innerEnd) {\n return outerStart <= innerStart && innerEnd <= outerEnd;\n}\nfunction countDetections(frames) {\n return frames.reduce((total, frame) => total + frame.detections.length, 0);\n}\nfunction getErrorMessage(error) {\n return error instanceof Error\n ? error.message\n : \"Detection buffer load failed.\";\n}\nfunction getRequiredCoverageEndTime(options) {\n const requestedEndTime = options.mediaTime + options.requiredAheadSeconds;\n if (options.duration === null || options.duration === undefined) {\n return requestedEndTime;\n }\n return Math.min(requestedEndTime, (options.firstTimestamp ?? 0) + Math.max(options.duration, 0));\n}\nfunction getLoopingSourceRanges(startTime, endTime, duration) {\n const normalizedStartTime = modulo(startTime, duration);\n const normalizedEndTime = modulo(endTime, duration);\n const startCycle = Math.floor(startTime / duration);\n const endCycle = Math.floor(endTime / duration);\n if (startCycle === endCycle) {\n return [{ endTime: normalizedEndTime, startTime: normalizedStartTime }];\n }\n const ranges = [];\n if (normalizedStartTime < duration) {\n ranges.push({ endTime: duration, startTime: normalizedStartTime });\n }\n if (normalizedEndTime > 0) {\n ranges.push({ endTime: normalizedEndTime, startTime: 0 });\n }\n return ranges;\n}\nfunction modulo(value, modulus) {\n return ((value % modulus) + modulus) % modulus;\n}\nfunction getOverlappingRanges(changedRanges, bufferedRanges) {\n const intersections = [];\n for (const changedRange of changedRanges) {\n for (const bufferedRange of bufferedRanges) {\n const startTime = Math.max(changedRange.startTime, bufferedRange.startTime);\n const endTime = Math.min(changedRange.endTime, bufferedRange.endTime);\n if (startTime <= endTime) {\n intersections.push({ endTime, startTime });\n }\n }\n }\n return intersections;\n}\nfunction mergeIncrementalFrames(currentFrames, changedFrames, changedRanges) {\n const framesByIdentity = new Map();\n for (const frame of currentFrames) {\n if (changedRanges.some((range) => detectionFrameOverlapsRange(frame, range.startTime, range.endTime))) {\n continue;\n }\n framesByIdentity.set(getDetectionFrameIdentity(frame), frame);\n }\n for (const frame of changedFrames) {\n framesByIdentity.set(getDetectionFrameIdentity(frame), frame);\n }\n return Array.from(framesByIdentity.values()).sort(compareDetectionFrames);\n}\nfunction reuseBufferedFrameSnapshots(currentFrames, loadedFrames) {\n const currentFramesByIdentity = new Map(currentFrames.map((frame) => [getDetectionFrameIdentity(frame), frame]));\n return loadedFrames.map((frame) => currentFramesByIdentity.get(getDetectionFrameIdentity(frame)) ?? frame);\n}\nfunction getDetectionFrameIdentity(frame) {\n return frame.frameIndex === undefined\n ? `time:${frame.mediaTime}`\n : `index:${frame.frameIndex}`;\n}\nfunction compareDetectionFrames(left, right) {\n if (left.mediaTime !== right.mediaTime) {\n return left.mediaTime - right.mediaTime;\n }\n return (left.frameIndex ?? 0) - (right.frameIndex ?? 0);\n}\n\nfunction createColdDetectionFrameSource(options) {\n return {\n loadFrames(startTime, endTime) {\n return options.store.loadFrames({\n datasetId: options.datasetId,\n endTime,\n startTime,\n });\n },\n };\n}\n\nfunction createCompositeDetectionFrameSource(options) {\n const sources = normalizeCompositeSources(options.sources);\n return {\n async loadFrames(startTime, endTime) {\n const loadedSources = await Promise.all(sources.map(async (source) => ({\n ...source,\n frames: copySortedDetectionFrames(await source.source.loadFrames(startTime, endTime)),\n })));\n if (options.selectionMode === DetectionFrameSelectionMode.NearestFrameIndex) {\n const nearestFrames = composeNearestFrameIndexFrames(loadedSources, startTime, endTime, options);\n if (nearestFrames) {\n return nearestFrames;\n }\n }\n return composeIntervalFrames(loadedSources, startTime, endTime, options);\n },\n async waitForRange(range) {\n await Promise.all(sources\n .filter((source) => source.requiredForPlayback)\n .map((source) => source.source.waitForRange?.(range)));\n },\n getAvailableRanges() {\n return mergeRanges$1(sources.flatMap((source) => source.source.getAvailableRanges?.() ?? []));\n },\n getVersion(range) {\n return sources.reduce((version, source) => version + (source.source.getVersion?.(range) ?? 0), 0);\n },\n destroy() {\n for (const source of sources) {\n source.source.destroy?.();\n }\n },\n };\n}\nfunction normalizeCompositeSources(entries) {\n const sourceIds = new Set();\n return entries\n .map((entry, declarationIndex) => {\n if (sourceIds.has(entry.id)) {\n throw new Error(`Duplicate detection source id: ${entry.id}.`);\n }\n sourceIds.add(entry.id);\n const inputCount = [\n entry.frames !== undefined,\n entry.source !== undefined,\n ].filter(Boolean).length;\n if (inputCount !== 1) {\n throw new Error(`Detection source ${entry.id} must provide exactly one input: frames or source.`);\n }\n return {\n declarationIndex,\n id: entry.id,\n order: entry.order ?? 0,\n requiredForPlayback: entry.requiredForPlayback !== false,\n source: entry.source ?? createArrayDetectionFrameSource(entry.frames ?? []),\n sync: entry.sync,\n };\n })\n .sort((left, right) => left.order - right.order ||\n left.declarationIndex - right.declarationIndex);\n}\nfunction composeIntervalFrames(sources, startTime, endTime, options) {\n const boundaryTimes = new Set([startTime]);\n for (const source of sources) {\n for (const frame of source.frames) {\n if (frame.mediaTime >= startTime && frame.mediaTime < endTime) {\n boundaryTimes.add(frame.mediaTime);\n }\n if (frame.endTime !== undefined &&\n frame.endTime > startTime &&\n frame.endTime < endTime) {\n boundaryTimes.add(frame.endTime);\n }\n }\n }\n const sortedBoundaryTimes = [...boundaryTimes].sort((left, right) => left - right);\n const frames = [];\n for (const [boundaryIndex, mediaTime] of sortedBoundaryTimes.entries()) {\n if (mediaTime < startTime || mediaTime >= endTime) {\n continue;\n }\n const nextBoundaryTime = sortedBoundaryTimes[boundaryIndex + 1] ?? endTime;\n const endTimeForFrame = Math.min(nextBoundaryTime, endTime);\n const frame = composeFrameAtTime(sources, mediaTime, endTimeForFrame, {\n ...options,\n selectionMode: DetectionFrameSelectionMode.Interval,\n });\n if (frame) {\n frames.push(frame);\n }\n }\n return frames;\n}\nfunction composeNearestFrameIndexFrames(sources, startTime, endTime, options) {\n const frameRate = options.frameRate;\n if (!frameRate || !Number.isFinite(frameRate) || frameRate <= 0) {\n return null;\n }\n const indexedFrames = sources.flatMap((source) => source.frames.filter((frame) => frame.frameIndex !== undefined));\n const firstIndexedFrame = indexedFrames[0];\n if (!firstIndexedFrame || firstIndexedFrame.frameIndex === undefined) {\n return null;\n }\n const originTime = options.frameIndexOriginTime ??\n firstIndexedFrame.mediaTime - firstIndexedFrame.frameIndex / frameRate;\n const frameIndexes = [\n ...new Set(indexedFrames\n .map((frame) => frame.frameIndex)\n .filter((frameIndex) => frameIndex !== undefined)),\n ].sort((left, right) => left - right);\n const frames = [];\n for (const frameIndex of frameIndexes) {\n const mediaTime = originTime + frameIndex / frameRate;\n if (mediaTime < startTime || mediaTime >= endTime) {\n continue;\n }\n const frame = composeFrameAtTime(sources, mediaTime, Math.min(mediaTime + 1 / frameRate, endTime), {\n ...options,\n selectionMode: DetectionFrameSelectionMode.NearestFrameIndex,\n }, frameIndex);\n if (frame) {\n frames.push(frame);\n }\n }\n return frames;\n}\nfunction composeFrameAtTime(sources, mediaTime, endTime, options, frameIndex) {\n const detections = [];\n const activeFrameIndexes = [];\n for (const source of sources) {\n const activeFrame = selectDetectionFrame(source.frames, mediaTime, {\n ...options,\n ...source.sync,\n });\n if (!activeFrame) {\n continue;\n }\n if (activeFrame.frameIndex !== undefined) {\n activeFrameIndexes.push(activeFrame.frameIndex);\n }\n activeFrame.detections.forEach((detection, sourceDetectionIndex) => {\n detections.push(copyDetectionWithSource(detection, source.id, sourceDetectionIndex));\n });\n }\n if (detections.length === 0) {\n return undefined;\n }\n return {\n detections,\n endTime,\n frameIndex: frameIndex ?? resolveComposedFrameIndex(activeFrameIndexes) ?? undefined,\n mediaTime,\n };\n}\nfunction copyDetectionWithSource(detection, sourceId, sourceDetectionIndex) {\n return {\n ...detection,\n mask: detection.mask ? { ...detection.mask } : undefined,\n metadata: detection.metadata ? { ...detection.metadata } : undefined,\n rect: detection.rect ? { ...detection.rect } : undefined,\n sourceDetectionIndex,\n sourceId,\n };\n}\nfunction resolveComposedFrameIndex(frameIndexes) {\n if (frameIndexes.length === 0) {\n return undefined;\n }\n const firstFrameIndex = frameIndexes[0];\n return frameIndexes.every((frameIndex) => frameIndex === firstFrameIndex)\n ? firstFrameIndex\n : undefined;\n}\nfunction mergeRanges$1(ranges) {\n const sortedRanges = [...ranges].sort((left, right) => left.startTime - right.startTime);\n const mergedRanges = [];\n for (const range of sortedRanges) {\n const lastRange = mergedRanges.at(-1);\n if (!lastRange || range.startTime > lastRange.endTime) {\n mergedRanges.push({ ...range });\n continue;\n }\n mergedRanges[mergedRanges.length - 1] = {\n startTime: lastRange.startTime,\n endTime: Math.max(lastRange.endTime, range.endTime),\n };\n }\n return mergedRanges;\n}\n\nvar 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 = {}));\nfunction createEditableAnnotationFrameSession(initialFrame) {\n let snapshot = createSnapshot(initialFrame);\n let destroyed = false;\n const listeners = new Set();\n assertStableIds(snapshot);\n const commit = (frame, kind, detectionIds) => {\n assertActive();\n const previous = snapshot;\n const current = createSnapshot(frame);\n assertStableIds(current);\n snapshot = current;\n const mutation = Object.freeze({\n current,\n detectionIds: Object.freeze([...detectionIds]),\n kind,\n previous,\n });\n for (const listener of listeners) {\n listener(mutation);\n }\n return current;\n };\n const session = {\n getSnapshot() {\n assertActive();\n return snapshot;\n },\n add(detection, index = snapshot.detections.length) {\n assertActive();\n const id = requireDetectionId(detection);\n if (findDetectionIndex(snapshot, id) !== -1) {\n throw new Error(`Detection id ${String(id)} already exists.`);\n }\n const detections = [...snapshot.detections];\n const insertionIndex = Math.max(0, Math.min(index, detections.length));\n detections.splice(insertionIndex, 0, detection);\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Add, [id]);\n },\n update(id, update) {\n assertActive();\n const detectionIndex = findDetectionIndex(snapshot, id);\n if (detectionIndex === -1) {\n throw new Error(`Detection id ${String(id)} was not found.`);\n }\n const detections = [...snapshot.detections];\n const current = detections[detectionIndex];\n const next = typeof update === \"function\"\n ? update(current)\n : { ...current, ...update };\n if (next.id !== id) {\n throw new Error(\"Detection updates must preserve the stable id.\");\n }\n detections[detectionIndex] = next;\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Update, [id]);\n },\n remove(id) {\n assertActive();\n const detectionIndex = findDetectionIndex(snapshot, id);\n if (detectionIndex === -1) {\n return snapshot;\n }\n const detections = [...snapshot.detections];\n detections.splice(detectionIndex, 1);\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Remove, [id]);\n },\n replace(frame) {\n return commit(frame, AnnotationFrameMutationKind.Replace, frame.detections.map(requireDetectionId));\n },\n transact(mutate, detectionIds = []) {\n assertActive();\n const detections = copySortedDetectionFrames([snapshot])[0]\n .detections;\n mutate(detections);\n return commit({ ...snapshot, detections }, AnnotationFrameMutationKind.Transact, detectionIds);\n },\n subscribe(listener) {\n assertActive();\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n destroy() {\n destroyed = true;\n listeners.clear();\n },\n };\n return session;\n function assertActive() {\n if (destroyed) {\n throw new Error(\"Editable annotation frame session has been destroyed.\");\n }\n }\n}\nfunction findDetectionIndex(frame, id) {\n return frame.detections.findIndex((detection) => detection.id === id);\n}\nfunction requireDetectionId(detection) {\n if (detection.id === undefined) {\n throw new Error(\"Editable annotation detections require a stable id.\");\n }\n return detection.id;\n}\nfunction assertStableIds(frame) {\n const ids = new Set();\n for (const detection of frame.detections) {\n const id = requireDetectionId(detection);\n if (ids.has(id)) {\n throw new Error(`Detection id ${String(id)} is duplicated.`);\n }\n ids.add(id);\n }\n}\nfunction createSnapshot(frame) {\n const snapshot = copySortedDetectionFrames([frame])[0];\n return deepFreeze(snapshot);\n}\nfunction deepFreeze(value) {\n if (value && typeof value === \"object\" && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const nested of Object.values(value)) {\n deepFreeze(nested);\n }\n }\n return value;\n}\n\nconst DEFAULT_CHUNK_DURATION_SECONDS = 1;\nfunction createMemoryColdDetectionFrameStore() {\n const datasets = new Map();\n let destroyed = false;\n return {\n async putFrames(options) {\n assertActive();\n const dataset = createDataset(resolveChunkDurationSeconds(options));\n upsertFrames(dataset, copySortedDetectionFrames(options.frames));\n datasets.set(options.datasetId, dataset);\n return createWriteSummary(options.datasetId, dataset);\n },\n async appendFrames(options) {\n assertActive();\n const existingDataset = datasets.get(options.datasetId);\n const chunkDurationSeconds = resolveChunkDurationSeconds(options, existingDataset);\n const dataset = existingDataset ?? createDataset(chunkDurationSeconds);\n upsertFrames(dataset, copySortedDetectionFrames(options.frames));\n datasets.set(options.datasetId, dataset);\n return createWriteSummary(options.datasetId, dataset);\n },\n async loadFrames(options) {\n assertActive();\n const dataset = datasets.get(options.datasetId);\n if (!dataset) {\n return [];\n }\n const startTime = Math.max(0, options.startTime);\n const endTime = Math.max(startTime, options.endTime);\n const frameKeys = new Set();\n const startChunkIndex = getChunkIndex(startTime, dataset.chunkDurationSeconds);\n const endChunkIndex = getChunkIndex(endTime, dataset.chunkDurationSeconds);\n for (let chunkIndex = startChunkIndex; chunkIndex <= endChunkIndex; chunkIndex += 1) {\n for (const frameKey of dataset.frameKeysByChunk.get(chunkIndex) ?? []) {\n frameKeys.add(frameKey);\n }\n }\n const frames = Array.from(frameKeys)\n .map((frameKey) => dataset.framesByKey.get(frameKey)?.frame)\n .filter((frame) => frame !== undefined &&\n detectionFrameOverlapsRange(frame, startTime, endTime));\n return copySortedDetectionFrames(frames);\n },\n async clearDataset(datasetId) {\n assertActive();\n datasets.delete(datasetId);\n },\n destroy() {\n destroyed = true;\n datasets.clear();\n },\n };\n function assertActive() {\n if (destroyed) {\n throw new Error(\"Memory cold detection frame store has been destroyed.\");\n }\n }\n}\nfunction createDataset(chunkDurationSeconds) {\n return {\n chunkDurationSeconds,\n detectionCount: 0,\n endTime: null,\n frameKeysByChunk: new Map(),\n framesByKey: new Map(),\n startTime: null,\n };\n}\nfunction upsertFrames(dataset, frames) {\n let shouldRecalculateBounds = false;\n for (const frame of frames) {\n const frameKey = getDetectionFrameDedupeKey(frame);\n const existingFrame = dataset.framesByKey.get(frameKey);\n if (existingFrame) {\n removeStoredFrame(dataset, frameKey, existingFrame);\n shouldRecalculateBounds ||= replacementCanShrinkBounds(dataset, existingFrame.frame, frame);\n }\n const chunkIndexes = getFrameChunkIndexes(frame, dataset.chunkDurationSeconds);\n dataset.framesByKey.set(frameKey, { chunkIndexes, frame });\n dataset.detectionCount += frame.detections.length;\n dataset.startTime = Math.min(dataset.startTime ?? frame.mediaTime, frame.mediaTime);\n dataset.endTime = Math.max(dataset.endTime ?? getFrameEndTime(frame), getFrameEndTime(frame));\n for (const chunkIndex of chunkIndexes) {\n const frameKeys = dataset.frameKeysByChunk.get(chunkIndex) ?? new Set();\n frameKeys.add(frameKey);\n dataset.frameKeysByChunk.set(chunkIndex, frameKeys);\n }\n }\n if (shouldRecalculateBounds) {\n recalculateBounds(dataset);\n }\n}\nfunction removeStoredFrame(dataset, frameKey, storedFrame) {\n dataset.framesByKey.delete(frameKey);\n dataset.detectionCount -= storedFrame.frame.detections.length;\n for (const chunkIndex of storedFrame.chunkIndexes) {\n const frameKeys = dataset.frameKeysByChunk.get(chunkIndex);\n frameKeys?.delete(frameKey);\n if (frameKeys?.size === 0) {\n dataset.frameKeysByChunk.delete(chunkIndex);\n }\n }\n}\nfunction replacementCanShrinkBounds(dataset, previousFrame, nextFrame) {\n return ((dataset.startTime === previousFrame.mediaTime &&\n nextFrame.mediaTime > previousFrame.mediaTime) ||\n (dataset.endTime === getFrameEndTime(previousFrame) &&\n getFrameEndTime(nextFrame) < getFrameEndTime(previousFrame)));\n}\nfunction recalculateBounds(dataset) {\n let startTime = null;\n let endTime = null;\n for (const { frame } of dataset.framesByKey.values()) {\n startTime = Math.min(startTime ?? frame.mediaTime, frame.mediaTime);\n endTime = Math.max(endTime ?? getFrameEndTime(frame), getFrameEndTime(frame));\n }\n dataset.startTime = startTime;\n dataset.endTime = endTime;\n}\nfunction resolveChunkDurationSeconds(options, existingDataset) {\n const chunkDurationSeconds = options.chunkDurationSeconds ??\n existingDataset?.chunkDurationSeconds ??\n DEFAULT_CHUNK_DURATION_SECONDS;\n if (chunkDurationSeconds <= 0) {\n throw new Error(\"chunkDurationSeconds must be greater than 0.\");\n }\n if (existingDataset &&\n options.chunkDurationSeconds !== undefined &&\n options.chunkDurationSeconds !== existingDataset.chunkDurationSeconds) {\n throw new Error(\"chunkDurationSeconds must match the existing detection dataset.\");\n }\n return chunkDurationSeconds;\n}\nfunction createWriteSummary(datasetId, dataset) {\n return {\n chunkCount: dataset.frameKeysByChunk.size,\n chunkDurationSeconds: dataset.chunkDurationSeconds,\n datasetId,\n detectionCount: dataset.detectionCount,\n endTime: dataset.endTime,\n frameCount: dataset.framesByKey.size,\n startTime: dataset.startTime,\n };\n}\nfunction getFrameChunkIndexes(frame, chunkDurationSeconds) {\n const startIndex = getChunkIndex(frame.mediaTime, chunkDurationSeconds);\n const endIndex = Math.max(startIndex, Math.ceil(getFrameEndTime(frame) / chunkDurationSeconds) - 1);\n return Array.from({ length: endIndex - startIndex + 1 }, (_, offset) => startIndex + offset);\n}\nfunction getFrameEndTime(frame) {\n return frame.endTime ?? frame.mediaTime;\n}\nfunction getChunkIndex(mediaTime, chunkDurationSeconds) {\n return Math.floor(mediaTime / chunkDurationSeconds);\n}\nfunction getDetectionFrameDedupeKey(frame) {\n return frame.frameIndex === undefined\n ? `time:${frame.mediaTime}`\n : `index:${frame.frameIndex}`;\n}\n\nconst RANGE_EPSILON_SECONDS = 1e-6;\nconst MAX_CHANGED_RANGE_JOURNAL_LENGTH = 512;\nfunction createWritableDetectionFrameSource(options) {\n let summary = null;\n let version = 0;\n let allRangeVersion = 0;\n let journalFloorVersion = 0;\n let destroyed = false;\n const changedRanges = [];\n const availableRanges = [];\n const waiters = [];\n const writeOptions = (frames) => ({\n chunkDurationSeconds: options.chunkDurationSeconds,\n datasetId: options.datasetId,\n frames,\n });\n const recordRangeWrite = (nextSummary, changedSourceRanges) => {\n summary = nextSummary;\n version += 1;\n for (const changedRange of changedSourceRanges) {\n changedRanges.push({ ...changedRange, version });\n recordAvailableRange(changedRange, availableRanges);\n }\n compactChangedRangeJournal();\n resolveCoveredWaiters();\n return nextSummary;\n };\n const recordAllRangesWrite = (nextSummary) => {\n summary = nextSummary;\n version += 1;\n allRangeVersion = version;\n journalFloorVersion = version;\n changedRanges.length = 0;\n availableRanges.length = 0;\n if (nextSummary.startTime !== null && nextSummary.endTime !== null) {\n recordAvailableRange({\n endTime: nextSummary.endTime,\n startTime: nextSummary.startTime,\n }, availableRanges);\n }\n resolveCoveredWaiters();\n return nextSummary;\n };\n return {\n datasetId: options.datasetId,\n async appendFrames(frames) {\n assertActive();\n const nextSummary = await options.store.appendFrames(writeOptions(frames));\n assertActive();\n const changedSourceRanges = getDetectionFrameRanges(frames);\n const retainedSummary = await applyRetention(nextSummary);\n assertActive();\n if (retainedSummary !== nextSummary) {\n return recordAllRangesWrite(retainedSummary);\n }\n if (changedSourceRanges.length === 0) {\n summary = nextSummary;\n return nextSummary;\n }\n return recordRangeWrite(nextSummary, changedSourceRanges);\n },\n async replaceFrames(frames) {\n assertActive();\n const nextSummary = await options.store.putFrames(writeOptions(frames));\n assertActive();\n const retainedSummary = await applyRetention(nextSummary);\n assertActive();\n return recordAllRangesWrite(retainedSummary);\n },\n async clear() {\n assertActive();\n await options.store.clearDataset(options.datasetId);\n assertActive();\n summary = null;\n version += 1;\n allRangeVersion = version;\n journalFloorVersion = version;\n changedRanges.length = 0;\n availableRanges.length = 0;\n },\n async loadFrames(startTime, endTime) {\n assertActive();\n const loadedFrames = await options.store.loadFrames({\n datasetId: options.datasetId,\n endTime,\n startTime,\n });\n assertActive();\n return loadedFrames;\n },\n getSummary() {\n return summary ? { ...summary } : null;\n },\n getAvailableRanges() {\n return availableRanges.map((range) => ({ ...range }));\n },\n waitForRange(range) {\n if (destroyed) {\n return Promise.reject(createDestroyedError());\n }\n if (isRangeCovered(range, availableRanges)) {\n return Promise.resolve();\n }\n return new Promise((resolve, reject) => {\n waiters.push({ range, reject, resolve });\n });\n },\n getVersion(range) {\n if (!range) {\n return version;\n }\n return changedRanges.reduce((rangeVersion, changedRange) => rangesOverlap(range, changedRange)\n ? Math.max(rangeVersion, changedRange.version)\n : rangeVersion, Math.max(allRangeVersion, journalFloorVersion));\n },\n getChangesSince(previousVersion, ranges) {\n const relevantVersion = ranges.reduce((rangeVersion, range) => Math.max(rangeVersion, changedRanges.reduce((changedVersion, changedRange) => rangesOverlap(range, changedRange)\n ? Math.max(changedVersion, changedRange.version)\n : changedVersion, Math.max(allRangeVersion, journalFloorVersion))), Math.max(allRangeVersion, journalFloorVersion));\n if (relevantVersion <= previousVersion) {\n return {\n ranges: [],\n requiresReload: false,\n version: relevantVersion,\n };\n }\n if (previousVersion < allRangeVersion ||\n previousVersion < journalFloorVersion) {\n return {\n ranges: [],\n requiresReload: true,\n version: relevantVersion,\n };\n }\n const changedSourceRanges = changedRanges\n .filter((changedRange) => changedRange.version > previousVersion &&\n ranges.some((range) => rangesOverlap(range, changedRange)))\n .map(({ endTime, startTime }) => ({ endTime, startTime }));\n return {\n ranges: mergeRanges(changedSourceRanges),\n requiresReload: false,\n version: relevantVersion,\n };\n },\n destroy() {\n if (destroyed) {\n return;\n }\n destroyed = true;\n for (const waiter of waiters) {\n waiter.reject(new Error(\"Detection frame source has been destroyed.\"));\n }\n waiters.length = 0;\n options.store.destroy?.();\n },\n };\n function assertActive() {\n if (destroyed) {\n throw createDestroyedError();\n }\n }\n async function applyRetention(nextSummary) {\n const retention = options.retention;\n if (retention === undefined ||\n !shouldApplyWindowRetention(retention) ||\n nextSummary.endTime === null) {\n return nextSummary;\n }\n const retentionWindowSeconds = retention.windowSeconds;\n if (retentionWindowSeconds === undefined ||\n !Number.isFinite(retentionWindowSeconds) ||\n retentionWindowSeconds <= 0) {\n throw new Error(\"retention.windowSeconds must be greater than 0.\");\n }\n const retentionStartTime = Math.max(0, nextSummary.endTime - retentionWindowSeconds);\n if (nextSummary.startTime !== null &&\n nextSummary.startTime + RANGE_EPSILON_SECONDS >= retentionStartTime) {\n return nextSummary;\n }\n const retainedFrames = await options.store.loadFrames({\n datasetId: options.datasetId,\n endTime: nextSummary.endTime,\n startTime: retentionStartTime,\n });\n return options.store.putFrames(writeOptions(retainedFrames));\n }\n function resolveCoveredWaiters() {\n for (let index = waiters.length - 1; index >= 0; index -= 1) {\n const waiter = waiters[index];\n if (!waiter || !isRangeCovered(waiter.range, availableRanges)) {\n continue;\n }\n waiters.splice(index, 1);\n waiter.resolve();\n }\n }\n function compactChangedRangeJournal() {\n const overflow = changedRanges.length - MAX_CHANGED_RANGE_JOURNAL_LENGTH;\n if (overflow <= 0) {\n return;\n }\n const removedRanges = changedRanges.splice(0, overflow);\n journalFloorVersion = Math.max(journalFloorVersion, removedRanges.at(-1)?.version ?? 0);\n }\n}\nfunction createDestroyedError() {\n return new Error(\"Detection frame source has been destroyed.\");\n}\nfunction shouldApplyWindowRetention(retention) {\n return (retention?.mode === DetectionFrameRetentionMode.PersistWindow ||\n retention?.mode === DetectionFrameRetentionMode.MemoryOnly);\n}\nfunction getDetectionFrameRanges(frames) {\n return mergeRanges(frames.map((frame) => ({\n endTime: frame.endTime ?? frame.mediaTime,\n startTime: frame.mediaTime,\n })));\n}\nfunction rangesOverlap(left, right) {\n return left.startTime <= right.endTime && right.startTime <= left.endTime;\n}\nfunction mergeRanges(ranges) {\n const sortedRanges = ranges\n .map((range) => ({ ...range }))\n .sort((left, right) => left.startTime - right.startTime);\n const mergedRanges = [];\n for (const range of sortedRanges) {\n const previousRange = mergedRanges.at(-1);\n if (previousRange &&\n range.startTime <= previousRange.endTime + RANGE_EPSILON_SECONDS) {\n previousRange.endTime = Math.max(previousRange.endTime, range.endTime);\n continue;\n }\n mergedRanges.push({ ...range });\n }\n return mergedRanges;\n}\nfunction recordAvailableRange(range, availableRanges) {\n if (range.endTime < range.startTime) {\n return;\n }\n availableRanges.push({ ...range });\n availableRanges.sort((left, right) => left.startTime - right.startTime);\n let writeIndex = 0;\n for (const nextRange of availableRanges) {\n const currentRange = availableRanges[writeIndex - 1];\n if (currentRange &&\n nextRange.startTime <= currentRange.endTime + RANGE_EPSILON_SECONDS) {\n currentRange.endTime = Math.max(currentRange.endTime, nextRange.endTime);\n continue;\n }\n availableRanges[writeIndex] = { ...nextRange };\n writeIndex += 1;\n }\n availableRanges.length = writeIndex;\n}\nfunction isRangeCovered(range, availableRanges) {\n return availableRanges.some((availableRange) => availableRange.startTime <= range.startTime + RANGE_EPSILON_SECONDS &&\n availableRange.endTime + RANGE_EPSILON_SECONDS >= range.endTime);\n}\n\nvar 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 = {}));\nvar MediaInteractionMode;\n(function (MediaInteractionMode) {\n MediaInteractionMode[\"Always\"] = \"always\";\n MediaInteractionMode[\"Disabled\"] = \"disabled\";\n MediaInteractionMode[\"PausedOnly\"] = \"pausedOnly\";\n})(MediaInteractionMode || (MediaInteractionMode = {}));\n\nfunction 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}\nfunction topLeftRectToCenterRect(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}\nfunction 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}\nfunction getDetectionRect(detection) {\n return (detection.rect ??\n getPointsRect(detection.polygon?.points ?? []) ??\n getPointsRect(detection.polyline?.points ?? []) ??\n getPointsRect(detection.keypoints?.points ?? []));\n}\nfunction containsPoint(rect, point, padding = 0) {\n const halfWidth = rect.width / 2;\n const halfHeight = rect.height / 2;\n return (point.x >= rect.x - halfWidth - padding &&\n point.x <= rect.x + halfWidth + padding &&\n point.y >= rect.y - halfHeight - padding &&\n point.y <= rect.y + halfHeight + padding);\n}\nfunction pointInPolygon(point, polygon) {\n if (polygon.length < 3) {\n return false;\n }\n let inside = false;\n for (let currentIndex = 0, previousIndex = polygon.length - 1; currentIndex < polygon.length; previousIndex = currentIndex, currentIndex += 1) {\n const current = polygon[currentIndex];\n const previous = polygon[previousIndex];\n const crossesRay = current.y > point.y !== previous.y > point.y &&\n point.x <\n ((previous.x - current.x) * (point.y - current.y)) /\n (previous.y - current.y) +\n current.x;\n if (crossesRay) {\n inside = !inside;\n }\n }\n return inside;\n}\nfunction distanceToSegment(point, start, end) {\n const deltaX = end.x - start.x;\n const deltaY = end.y - start.y;\n const lengthSquared = deltaX * deltaX + deltaY * deltaY;\n if (lengthSquared === 0) {\n return Math.hypot(point.x - start.x, point.y - start.y);\n }\n const projection = Math.max(0, Math.min(1, ((point.x - start.x) * deltaX + (point.y - start.y) * deltaY) /\n lengthSquared));\n const closestX = start.x + projection * deltaX;\n const closestY = start.y + projection * deltaY;\n return Math.hypot(point.x - closestX, point.y - closestY);\n}\nfunction polygonArea(points) {\n if (points.length < 3) {\n return 0;\n }\n let twiceArea = 0;\n for (let index = 0; index < points.length; index += 1) {\n const current = points[index];\n const next = points[(index + 1) % points.length];\n twiceArea += current.x * next.y - next.x * current.y;\n }\n return Math.abs(twiceArea) / 2;\n}\nfunction rectArea(rect) {\n return rect ? Math.max(0, rect.width) * Math.max(0, rect.height) : 0;\n}\n\nconst decodedMaskCache = new WeakMap();\nfunction pickDetectionAtPoint(frame, point, options = {}) {\n if (!frame) {\n return null;\n }\n const padding = Math.max(0, options.padding ?? 0);\n const polylinePadding = Math.max(0, options.polylinePadding ?? 6);\n const keypointPadding = Math.max(0, options.keypointPadding ?? 10);\n const edgePadding = Math.max(0, options.edgePadding ?? 8);\n const candidates = [];\n for (let detectionIndex = 0; detectionIndex < frame.detections.length; detectionIndex += 1) {\n const detection = frame.detections[detectionIndex];\n if (!detection ||\n (detection.locked && options.includeLocked === false) ||\n options.filter?.(detection, detectionIndex) === false) {\n continue;\n }\n const detectionArea = Math.max(1, rectArea(getDetectionRect(detection)));\n const pushCandidate = (target, area = detectionArea, geometryIndex) => {\n candidates.push({\n area,\n priority: getPickTargetPriority(target),\n result: {\n detection,\n detectionIndex,\n frame,\n geometryIndex,\n mediaTime: frame.mediaTime,\n point,\n target,\n },\n zIndex: detection.zIndex ?? detectionIndex,\n });\n };\n if (detection.rect && containsPoint(detection.rect, point, padding)) {\n pushCandidate(DetectionPickTarget.Box, rectArea(detection.rect));\n }\n if (detection.polygon && pointInPolygon(point, detection.polygon.points)) {\n pushCandidate(DetectionPickTarget.Polygon, Math.max(1, polygonArea(detection.polygon.points)));\n }\n if (detection.polyline) {\n const segmentIndex = findHitSegment(point, detection.polyline.points, polylinePadding);\n if (segmentIndex !== -1) {\n pushCandidate(DetectionPickTarget.Polyline, detectionArea, segmentIndex);\n }\n }\n if (detection.keypoints) {\n const keypointIndex = detection.keypoints.points.findIndex((keypoint, index) => detection.keypoints?.visibility?.[index] !==\n KeypointVisibility.NotLabeled &&\n Math.hypot(point.x - keypoint.x, point.y - keypoint.y) <=\n keypointPadding);\n if (keypointIndex !== -1) {\n pushCandidate(DetectionPickTarget.Keypoint, Math.PI * keypointPadding * keypointPadding, keypointIndex);\n }\n else {\n const edgeIndex = detection.keypoints.edges.findIndex(([fromIndex, toIndex]) => {\n const from = detection.keypoints?.points[fromIndex];\n const to = detection.keypoints?.points[toIndex];\n return Boolean(from &&\n to &&\n detection.keypoints?.visibility?.[fromIndex] !==\n KeypointVisibility.NotLabeled &&\n detection.keypoints?.visibility?.[toIndex] !==\n KeypointVisibility.NotLabeled &&\n distanceToSegment(point, from, to) <= edgePadding);\n });\n if (edgeIndex !== -1) {\n const [fromIndex, toIndex] = detection.keypoints.edges[edgeIndex];\n const from = detection.keypoints.points[fromIndex];\n const to = detection.keypoints.points[toIndex];\n const edgeArea = Math.max(1, Math.hypot(to.x - from.x, to.y - from.y) * edgePadding * 2);\n pushCandidate(DetectionPickTarget.Edge, edgeArea, edgeIndex);\n }\n }\n }\n if (detection.mask && options.includeMasks !== false) {\n const decoded = getDecodedMask(detection.mask);\n const mediaDimensions = options.maskMediaDimensions;\n const x = Math.floor(mediaDimensions && mediaDimensions.width > 0\n ? (point.x / mediaDimensions.width) * decoded.width\n : point.x);\n const y = Math.floor(mediaDimensions && mediaDimensions.height > 0\n ? (point.y / mediaDimensions.height) * decoded.height\n : point.y);\n if (x >= 0 &&\n y >= 0 &&\n x < decoded.width &&\n y < decoded.height &&\n decoded.data[y * decoded.width + x]) {\n pushCandidate(DetectionPickTarget.Mask, getMaskMediaArea(decoded, mediaDimensions));\n }\n }\n }\n candidates.sort((left, right) => {\n const priorityDifference = left.priority - right.priority;\n if (priorityDifference !== 0) {\n return priorityDifference;\n }\n const areaDifference = left.area - right.area;\n if (areaDifference !== 0) {\n return areaDifference;\n }\n const zIndexDifference = right.zIndex - left.zIndex;\n return zIndexDifference === 0\n ? right.result.detectionIndex - left.result.detectionIndex\n : zIndexDifference;\n });\n return candidates[0]?.result ?? null;\n}\nfunction getPickTargetPriority(target) {\n switch (target) {\n case DetectionPickTarget.Keypoint:\n return 0;\n case DetectionPickTarget.Edge:\n case DetectionPickTarget.Polyline:\n return 1;\n default:\n return 2;\n }\n}\nfunction getDecodedMask(mask) {\n const cached = decodedMaskCache.get(mask);\n if (cached)\n return cached;\n const decoded = decodeCompressedRleMask(mask);\n const result = {\n ...decoded,\n pixelArea: countMaskPixels(decoded.data),\n };\n decodedMaskCache.set(mask, result);\n return result;\n}\nfunction getMaskMediaArea(mask, mediaDimensions) {\n if (!mediaDimensions ||\n mediaDimensions.width <= 0 ||\n mediaDimensions.height <= 0) {\n return mask.pixelArea;\n }\n return (mask.pixelArea *\n (mediaDimensions.width / mask.width) *\n (mediaDimensions.height / mask.height));\n}\nfunction createDetectionPickKey(pick) {\n if (!pick) {\n return null;\n }\n const frameKey = [pick.frame.frameIndex ?? \"time\", pick.frame.mediaTime];\n const detectionKey = detectionPickKey(pick);\n return [\n ...frameKey,\n ...detectionKey,\n pick.target,\n pick.geometryIndex ?? \"geometry\",\n ].join(\":\");\n}\nfunction rebaseDetectionPickToFrame(pick, frame) {\n if (!pick || !frame) {\n return null;\n }\n const detectionIndex = pick.detection.id === undefined ||\n !hasUniqueDetectionId(pick.frame, pick.detection.id)\n ? pick.detectionIndex\n : frame.detections.findIndex((detection) => detection.id === pick.detection.id);\n const detection = frame.detections[detectionIndex];\n if (!detection) {\n return null;\n }\n const rebasedPick = {\n detection,\n detectionIndex,\n frame,\n geometryIndex: pick.geometryIndex,\n mediaTime: frame.mediaTime,\n point: pick.point,\n target: pick.target,\n };\n return createDetectionPickKey(rebasedPick) === createDetectionPickKey(pick)\n ? rebasedPick\n : null;\n}\nfunction detectionPickKey(pick) {\n if (pick.detection.id === undefined) {\n return [\"anonymous\", pick.detectionIndex];\n }\n return hasUniqueDetectionId(pick.frame, pick.detection.id)\n ? [\"id\", String(pick.detection.id)]\n : [\"duplicate-id\", String(pick.detection.id), \"index\", pick.detectionIndex];\n}\nfunction hasUniqueDetectionId(frame, id) {\n let count = 0;\n for (const detection of frame.detections) {\n if (detection.id !== id)\n continue;\n count += 1;\n if (count > 1)\n return false;\n }\n return count === 1;\n}\nfunction pickDetectionByMaskId(frame, maskId, point) {\n if (!frame || maskId <= 0 || !Number.isInteger(maskId)) {\n return null;\n }\n const detectionIndex = maskId - 1;\n const detection = frame.detections[detectionIndex];\n if (!detection) {\n return null;\n }\n return {\n detection,\n detectionIndex,\n frame,\n mediaTime: frame.mediaTime,\n point,\n target: DetectionPickTarget.Mask,\n };\n}\nfunction findHitSegment(point, points, padding, closed) {\n const segmentCount = points.length - 1;\n for (let index = 0; index < segmentCount; index += 1) {\n const start = points[index];\n const end = points[(index + 1) % points.length];\n if (start && end && distanceToSegment(point, start, end) <= padding) {\n return index;\n }\n }\n return -1;\n}\nfunction countMaskPixels(data) {\n let count = 0;\n for (const value of data) {\n count += value ? 1 : 0;\n }\n return Math.max(1, count);\n}\n\nconst MIN_SCALE = 0.1;\nconst MAX_SCALE = 10;\nconst MAX_WHEEL_DELTA = 50;\nfunction createViewportController(initial = {}) {\n let transform = freeze({\n locked: initial.locked ?? false,\n scale: clampScale(initial.scale ?? 0.8),\n x: initial.x ?? 0,\n y: initial.y ?? 0,\n });\n const listeners = new Set();\n const update = (next) => {\n if (next.scale === transform.scale &&\n next.x === transform.x &&\n next.y === transform.y &&\n next.locked === transform.locked)\n return;\n transform = freeze(next);\n for (const listener of listeners)\n listener(transform);\n };\n const controller = {\n getTransform: () => transform,\n screenToMedia: (point) => screenToMedia(point, transform),\n mediaToScreen: (point) => mediaToScreen(point, transform),\n setTransform(next) {\n if (transform.locked)\n return;\n update({\n ...transform,\n ...(next.scale === undefined ? {} : { scale: clampScale(next.scale) }),\n ...(next.x === undefined ? {} : { x: next.x }),\n ...(next.y === undefined ? {} : { y: next.y }),\n });\n },\n setLocked(locked) {\n update({ ...transform, locked });\n },\n panBy(dx, dy) {\n if (transform.locked)\n return;\n update({ ...transform, x: transform.x + dx, y: transform.y + dy });\n },\n zoomAt(point, factor) {\n if (transform.locked || !Number.isFinite(factor) || factor <= 0)\n return;\n const mediaPoint = screenToMedia(point, transform);\n const scale = clampScale(transform.scale * factor);\n update({\n ...transform,\n scale,\n x: point.x - mediaPoint.x * scale,\n y: point.y - mediaPoint.y * scale,\n });\n },\n zoomFromWheel(point, deltaY) {\n const delta = Math.max(-MAX_WHEEL_DELTA, Math.min(MAX_WHEEL_DELTA, deltaY));\n controller.zoomAt(point, Math.exp(-delta * 0.01));\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n return controller;\n}\nfunction screenToMedia(point, transform) {\n return {\n x: (point.x - transform.x) / transform.scale,\n y: (point.y - transform.y) / transform.scale,\n };\n}\nfunction mediaToScreen(point, transform) {\n return {\n x: point.x * transform.scale + transform.x,\n y: point.y * transform.scale + transform.y,\n };\n}\nfunction clampScale(scale) {\n return Math.max(MIN_SCALE, Math.min(MAX_SCALE, Number.isFinite(scale) ? scale : 1));\n}\nfunction freeze(transform) {\n return Object.freeze(transform);\n}\n\nvar 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 = {}));\nvar 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 = {}));\nvar AnnotationHandleKind;\n(function (AnnotationHandleKind) {\n AnnotationHandleKind[\"Resize\"] = \"resize\";\n AnnotationHandleKind[\"Vertex\"] = \"vertex\";\n AnnotationHandleKind[\"AddVertex\"] = \"addVertex\";\n AnnotationHandleKind[\"Keypoint\"] = \"keypoint\";\n})(AnnotationHandleKind || (AnnotationHandleKind = {}));\n\nconst HANDLE_RADIUS = 6;\nconst ADD_HANDLE_RADIUS = 3.6;\nconst HANDLE_HIT_SIZE = 16;\nfunction getAnnotationHandles(detection, viewportScale = 1) {\n if (detection.locked || detection.mask)\n return [];\n const radius = HANDLE_RADIUS / viewportScale;\n const hitSize = HANDLE_HIT_SIZE / viewportScale;\n if (detection.polygon)\n return getPathHandles(detection.polygon.points, true, radius, hitSize);\n if (detection.polyline)\n return getPathHandles(detection.polyline.points, false, radius, hitSize);\n if (detection.keypoints) {\n return detection.keypoints.points.map((point, geometryIndex) => ({\n cursor: \"move\",\n geometryIndex,\n hitSize,\n id: `kp-${geometryIndex}`,\n kind: AnnotationHandleKind.Keypoint,\n point,\n radius,\n }));\n }\n if (detection.rect)\n return getBoxHandles(detection.rect, radius, hitSize);\n return [];\n}\nfunction pickAnnotationHandle(handles, point) {\n return [...handles]\n .reverse()\n .find((handle) => Math.abs(point.x - handle.point.x) <= handle.hitSize / 2 &&\n Math.abs(point.y - handle.point.y) <= handle.hitSize / 2);\n}\nfunction applyAnnotationHandleDrag(detection, handle, point) {\n if (detection.rect && handle.kind === AnnotationHandleKind.Resize) {\n return { ...detection, rect: resizeRect(detection.rect, handle.id, point) };\n }\n if (handle.kind === AnnotationHandleKind.AddVertex &&\n handle.edgeIndex !== undefined) {\n const key = detection.polygon ? \"polygon\" : \"polyline\";\n const geometry = detection[key];\n if (!geometry)\n return detection;\n const points = [...geometry.points];\n points.splice(handle.edgeIndex + 1, 0, point);\n return { ...detection, [key]: { points } };\n }\n if (handle.geometryIndex === undefined)\n return detection;\n if (detection.polygon)\n return replacePathPoint(detection, \"polygon\", handle.geometryIndex, point);\n if (detection.polyline)\n return replacePathPoint(detection, \"polyline\", handle.geometryIndex, point);\n if (detection.keypoints) {\n const points = [...detection.keypoints.points];\n points[handle.geometryIndex] = point;\n return { ...detection, keypoints: { ...detection.keypoints, points } };\n }\n return detection;\n}\nfunction deleteAnnotationVertex(detection, vertexIndex) {\n const geometry = detection.polygon ?? detection.polyline;\n const minimum = detection.polygon ? 3 : 2;\n if (!geometry || geometry.points.length <= minimum)\n return null;\n const points = geometry.points.filter((_, index) => index !== vertexIndex);\n return detection.polygon\n ? { ...detection, polygon: { points } }\n : { ...detection, polyline: { points } };\n}\nfunction offsetDetection(detection, dx, dy) {\n const offsetPoint = ({ x, y }) => ({ x: x + dx, y: y + dy });\n return {\n ...detection,\n ...(detection.rect\n ? {\n rect: {\n ...detection.rect,\n x: detection.rect.x + dx,\n y: detection.rect.y + dy,\n },\n }\n : {}),\n ...(detection.polygon\n ? { polygon: { points: detection.polygon.points.map(offsetPoint) } }\n : {}),\n ...(detection.polyline\n ? { polyline: { points: detection.polyline.points.map(offsetPoint) } }\n : {}),\n ...(detection.keypoints\n ? {\n keypoints: {\n ...detection.keypoints,\n points: detection.keypoints.points.map(offsetPoint),\n },\n }\n : {}),\n };\n}\nfunction getBoxHandles(rect, radius, hitSize) {\n const left = rect.x - rect.width / 2;\n const right = rect.x + rect.width / 2;\n const top = rect.y - rect.height / 2;\n const bottom = rect.y + rect.height / 2;\n const definitions = [\n [\"nw\", { x: left, y: top }, \"nwse-resize\"],\n [\"n\", { x: rect.x, y: top }, \"ns-resize\"],\n [\"ne\", { x: right, y: top }, \"nesw-resize\"],\n [\"e\", { x: right, y: rect.y }, \"ew-resize\"],\n [\"se\", { x: right, y: bottom }, \"nwse-resize\"],\n [\"s\", { x: rect.x, y: bottom }, \"ns-resize\"],\n [\"sw\", { x: left, y: bottom }, \"nesw-resize\"],\n [\"w\", { x: left, y: rect.y }, \"ew-resize\"],\n ];\n return definitions.map(([id, point, cursor]) => ({\n cursor,\n hitSize,\n id,\n kind: AnnotationHandleKind.Resize,\n point,\n radius,\n }));\n}\nfunction getPathHandles(points, closed, radius, hitSize) {\n const handles = points.map((point, geometryIndex) => ({\n cursor: \"move\",\n geometryIndex,\n hitSize,\n id: `vertex-${geometryIndex}`,\n kind: AnnotationHandleKind.Vertex,\n point,\n radius,\n }));\n const edgeCount = closed ? points.length : Math.max(0, points.length - 1);\n for (let edgeIndex = 0; edgeIndex < edgeCount; edgeIndex += 1) {\n const from = points[edgeIndex];\n const to = points[(edgeIndex + 1) % points.length];\n handles.push({\n cursor: \"copy\",\n edgeIndex,\n hitSize,\n id: `add-${edgeIndex}`,\n kind: AnnotationHandleKind.AddVertex,\n point: { x: (from.x + to.x) / 2, y: (from.y + to.y) / 2 },\n radius: ADD_HANDLE_RADIUS / (HANDLE_RADIUS / radius),\n });\n }\n return handles;\n}\nfunction resizeRect(rect, handle, point) {\n let left = rect.x - rect.width / 2;\n let right = rect.x + rect.width / 2;\n let top = rect.y - rect.height / 2;\n let bottom = rect.y + rect.height / 2;\n if (handle.includes(\"w\"))\n left = Math.min(point.x, right - 5);\n if (handle.includes(\"e\"))\n right = Math.max(point.x, left + 5);\n if (handle.includes(\"n\"))\n top = Math.min(point.y, bottom - 5);\n if (handle.includes(\"s\"))\n bottom = Math.max(point.y, top + 5);\n return {\n x: (left + right) / 2,\n y: (top + bottom) / 2,\n width: right - left,\n height: bottom - top,\n };\n}\nfunction replacePathPoint(detection, key, index, point) {\n const geometry = detection[key];\n const points = [...geometry.points];\n points[index] = point;\n return { ...detection, [key]: { points } };\n}\n/** Finds the closest path segment, useful for contextual vertex insertion. */\nfunction findClosestAnnotationSegment(points, point, closed) {\n const count = closed ? points.length : points.length - 1;\n let best;\n for (let index = 0; index < count; index += 1) {\n const distance = distanceToSegment(point, points[index], points[(index + 1) % points.length]);\n if (!best || distance < best.distance)\n best = { index, distance };\n }\n return best;\n}\n\nconst MOVE_THRESHOLD = 4;\nconst CLICK_CANCEL_MS = 250;\nconst CLICK_CANCEL_DIAGONAL = 25;\nconst CLOSE_ZONE_SCREEN_PX = 12;\nfunction createAnnotationEditingEngine(options = {}) {\n let tool = null;\n let gesture = null;\n let state = idleState();\n const stateListeners = new Set();\n const fastTranslateListeners = new Set();\n return {\n getState: () => state,\n setCreationTool(nextTool) {\n if (gesture)\n cancel();\n tool = nextTool;\n },\n pointerDown(input, pick = null) {\n if (input.button !== undefined && input.button !== 0)\n return;\n if (tool) {\n beginCreation(input);\n }\n else if (pick && !pick.detection.locked && !pick.detection.mask) {\n beginMove(pick, input);\n }\n },\n pointerMove(input) {\n if (!gesture)\n return;\n switch (gesture.kind) {\n case \"box\":\n gesture = { ...gesture, current: input };\n setPreview(resolveBoxPreview(gesture));\n break;\n case \"move\": {\n const dx = input.point.x - gesture.start.point.x;\n const dy = input.point.y - gesture.start.point.y;\n const moved = gesture.moved || Math.hypot(dx, dy) >= MOVE_THRESHOLD / scale();\n gesture = { ...gesture, current: input, moved };\n if (moved) {\n const preview = offsetDetection(gesture.detection, dx, dy);\n setPreview(preview);\n if (gesture.detection.id !== undefined) {\n options.onFastTranslate?.(gesture.detection.id, dx, dy);\n for (const listener of fastTranslateListeners) {\n listener(gesture.detection.id, dx, dy);\n }\n }\n }\n break;\n }\n case \"resize\":\n gesture = { ...gesture, current: input };\n setPreview(applyAnnotationHandleDrag(gesture.detection, gesture.handle, input.point));\n break;\n case \"path\":\n setPreview(resolvePathPreview([...gesture.points, input.point]));\n break;\n case \"freehand\": {\n const previous = gesture.points.at(-1);\n if (!previous ||\n previous.x !== input.point.x ||\n previous.y !== input.point.y) {\n gesture.points.push(input.point);\n }\n gesture = { ...gesture, current: input };\n setPreview(resolvePathPreview(gesture.points));\n break;\n }\n }\n },\n pointerUp(input) {\n if (!gesture)\n return;\n if (gesture.kind === \"path\")\n return;\n const active = gesture;\n gesture = null;\n release(active.start.pointerId);\n if (active.kind === \"box\") {\n const preview = resolveBoxPreview({ ...active, current: input });\n const duration = input.timestamp - active.start.timestamp;\n const diagonal = Math.hypot(input.point.x - active.start.point.x, input.point.y - active.start.point.y) * scale();\n const rect = preview.rect;\n if (!rect ||\n rect.width < 1 ||\n rect.height < 1 ||\n (duration < CLICK_CANCEL_MS && diagonal <= CLICK_CANCEL_DIAGONAL)) {\n cancel();\n return;\n }\n if (tool?.shouldCommit?.(rect) === false) {\n cancel();\n return;\n }\n commit(preview, null);\n return;\n }\n if (active.kind === \"freehand\") {\n const points = [...active.points, input.point];\n if (points.length < 2 || tool?.shouldCommit?.(points) === false) {\n cancel();\n return;\n }\n commit(tool.createDetection(points), null);\n return;\n }\n if (active.kind === \"move\") {\n if (!active.moved) {\n setState(idleState());\n return;\n }\n const preview = offsetDetection(active.detection, input.point.x - active.start.point.x, input.point.y - active.start.point.y);\n commit(preview, active.detection);\n return;\n }\n const preview = applyAnnotationHandleDrag(active.detection, active.handle, input.point);\n commit(preview, active.detection);\n },\n keyDown(key) {\n if (key === \"Escape\") {\n cancel();\n }\n else if (key === \"Enter\" && gesture?.kind === \"path\") {\n commitPath();\n }\n },\n beginHandleDrag(detection, handle, input) {\n if (detection.locked || detection.mask)\n return;\n capture(input.pointerId);\n gesture = {\n current: input,\n detection,\n handle,\n kind: \"resize\",\n start: input,\n };\n setState({\n activeDetectionId: detection.id ?? null,\n activeHandleId: handle.id,\n kind: AnnotationGestureStateKind.Resizing,\n pointerId: input.pointerId ?? null,\n preview: detection,\n });\n },\n deleteVertex(detection, vertexIndex) {\n const next = deleteAnnotationVertex(detection, vertexIndex);\n if (next)\n commit(next, detection);\n return next;\n },\n cancel,\n hasCreationTool: () => tool !== null,\n subscribe(listener) {\n stateListeners.add(listener);\n return () => stateListeners.delete(listener);\n },\n subscribeFastTranslate(listener) {\n fastTranslateListeners.add(listener);\n return () => fastTranslateListeners.delete(listener);\n },\n };\n function beginCreation(input) {\n if (!tool)\n return;\n const mode = tool.mode ??\n (tool.geometry === AnnotationGeometryKind.Box\n ? \"drag\"\n : tool.geometry === AnnotationGeometryKind.Mask\n ? \"freehand\"\n : \"multiClick\");\n if (mode === \"drag\") {\n capture(input.pointerId);\n gesture = { current: input, kind: \"box\", start: input };\n const preview = resolveBoxPreview(gesture);\n options.onPreview?.(preview);\n setState({\n activeDetectionId: null,\n activeHandleId: null,\n kind: AnnotationGestureStateKind.Creating,\n pointerId: input.pointerId ?? null,\n preview,\n });\n return;\n }\n if (mode === \"freehand\") {\n capture(input.pointerId);\n gesture = {\n current: input,\n kind: \"freehand\",\n points: [input.point],\n start: input,\n };\n setPreview(resolvePathPreview([input.point]));\n return;\n }\n if (tool.geometry !== AnnotationGeometryKind.Polygon &&\n tool.geometry !== AnnotationGeometryKind.Polyline &&\n tool.geometry !== AnnotationGeometryKind.Keypoints)\n return;\n if (gesture?.kind !== \"path\") {\n capture(input.pointerId);\n gesture = {\n kind: \"path\",\n lastTimestamp: input.timestamp,\n pointerId: input.pointerId ?? null,\n points: [input.point],\n };\n setPreview(resolvePathPreview([input.point, input.point]));\n return;\n }\n const minimum = tool.minVertices ??\n (tool.geometry === AnnotationGeometryKind.Polygon ? 3 : 2);\n const closeDistance = Math.hypot(input.point.x - gesture.points[0].x, input.point.y - gesture.points[0].y) * scale();\n const doubleClick = input.detail !== undefined\n ? input.detail >= 2\n : input.timestamp - gesture.lastTimestamp < CLICK_CANCEL_MS;\n if (gesture.points.length >= minimum &&\n ((tool.geometry === AnnotationGeometryKind.Polygon &&\n closeDistance <= CLOSE_ZONE_SCREEN_PX) ||\n doubleClick)) {\n commitPath();\n return;\n }\n gesture.points.push(input.point);\n gesture.lastTimestamp = input.timestamp;\n setPreview(resolvePathPreview([...gesture.points, input.point]));\n }\n function beginMove(pick, input) {\n capture(input.pointerId);\n gesture = {\n current: input,\n detection: pick.detection,\n kind: \"move\",\n moved: false,\n start: input,\n };\n setState({\n activeDetectionId: pick.detection.id ?? null,\n activeHandleId: null,\n kind: AnnotationGestureStateKind.Moving,\n pointerId: input.pointerId ?? null,\n preview: null,\n });\n }\n function resolveBoxPreview(active) {\n const left = Math.min(active.start.point.x, active.current.point.x);\n const right = Math.max(active.start.point.x, active.current.point.x);\n const top = Math.min(active.start.point.y, active.current.point.y);\n const bottom = Math.max(active.start.point.y, active.current.point.y);\n const rect = {\n x: (left + right) / 2,\n y: (top + bottom) / 2,\n width: right - left,\n height: bottom - top,\n };\n return tool.createDetection(rect);\n }\n function resolvePathPreview(points) {\n return tool.createDetection(points);\n }\n function commitPath() {\n if (!tool || gesture?.kind !== \"path\")\n return;\n const minimum = tool.minVertices ??\n (tool.geometry === AnnotationGeometryKind.Polygon ? 3 : 2);\n if (gesture.points.length < minimum) {\n cancel();\n return;\n }\n const preview = tool.createDetection(gesture.points);\n if (tool.shouldCommit?.(gesture.points) === false) {\n cancel();\n return;\n }\n release(gesture.pointerId ?? undefined);\n gesture = null;\n commit(preview, null);\n }\n function commit(detection, previous) {\n options.onCommit?.(detection, previous);\n options.onPreview?.(null);\n setState(idleState());\n }\n function setPreview(preview) {\n options.onPreview?.(preview);\n setState({\n activeDetectionId: state.activeDetectionId,\n activeHandleId: state.activeHandleId,\n kind: state.kind === AnnotationGestureStateKind.Idle\n ? AnnotationGestureStateKind.Creating\n : state.kind,\n pointerId: state.pointerId ??\n (gesture && \"pointerId\" in gesture\n ? (gesture.pointerId ?? null)\n : null),\n preview,\n });\n }\n function cancel() {\n const pointerId = gesture && \"start\" in gesture\n ? gesture.start.pointerId\n : gesture?.kind === \"path\"\n ? (gesture.pointerId ?? undefined)\n : undefined;\n release(pointerId);\n gesture = null;\n options.onPreview?.(null);\n options.onCancel?.();\n setState(idleState());\n }\n function setState(next) {\n state = Object.freeze(next);\n options.onStateChange?.(state);\n for (const listener of stateListeners)\n listener(state);\n }\n function scale() {\n return Math.max(options.viewportScale?.() ?? 1, Number.EPSILON);\n }\n function capture(pointerId) {\n if (pointerId !== undefined)\n options.capturePointer?.(pointerId);\n }\n function release(pointerId) {\n if (pointerId !== undefined)\n options.releasePointer?.(pointerId);\n }\n}\nfunction idleState() {\n return Object.freeze({\n activeDetectionId: null,\n activeHandleId: null,\n kind: AnnotationGestureStateKind.Idle,\n pointerId: null,\n preview: null,\n });\n}\n\nfunction resolveStyleValue(value, detection, context) {\n return typeof value === \"function\"\n ? value(detection, context)\n : value;\n}\n\nvar BoxShape;\n(function (BoxShape) {\n BoxShape[\"Rect\"] = \"rect\";\n BoxShape[\"RoundedRect\"] = \"roundedRect\";\n})(BoxShape || (BoxShape = {}));\nvar BoxStrokeAlignment;\n(function (BoxStrokeAlignment) {\n BoxStrokeAlignment[\"Inside\"] = \"inside\";\n BoxStrokeAlignment[\"Center\"] = \"center\";\n BoxStrokeAlignment[\"Outside\"] = \"outside\";\n})(BoxStrokeAlignment || (BoxStrokeAlignment = {}));\n\nconst DEFAULT_BOX_STROKE_ALPHA = 1;\nconst DEFAULT_BOX_STROKE_COLOR = 0x00ff66;\nconst DEFAULT_BOX_STROKE_WIDTH = 2;\n/**\n * Default configurable box style.\n *\n * This is the simplest `supervision-js` equivalent of a box annotator: it\n * converts detections with `rect` geometry into renderer-neutral box draw\n * instructions. Use options such as `shape`, `cornerRadius`, `stroke`, and\n * `fill` for static or per-detection styling.\n */\nclass BaseBoxStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (!detection.rect ||\n context.hidden ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const shape = this.resolveShape(detection, context);\n const cornerRadius = this.resolveCornerRadius(detection, context, shape);\n const instruction = {\n fill: this.resolveFill(detection, context),\n rect: detection.rect,\n shape,\n stroke: this.resolveStroke(detection, context),\n };\n if (cornerRadius !== undefined) {\n return {\n ...instruction,\n cornerRadius,\n };\n }\n return instruction;\n }\n resolveShape(detection, context) {\n return (resolveStyleValue(this.options.shape, detection, context) ?? BoxShape.Rect);\n }\n resolveCornerRadius(detection, context, shape) {\n if (shape !== BoxShape.RoundedRect) {\n return undefined;\n }\n return resolveStyleValue(this.options.cornerRadius, detection, context);\n }\n resolveStroke(detection, context) {\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n if (stroke === null) {\n return undefined;\n }\n const resolvedStroke = {\n alpha: stroke?.alpha ?? DEFAULT_BOX_STROKE_ALPHA,\n color: stroke?.color ?? DEFAULT_BOX_STROKE_COLOR,\n width: stroke?.width ?? DEFAULT_BOX_STROKE_WIDTH,\n };\n return {\n ...resolvedStroke,\n ...(stroke?.alignment === undefined\n ? {}\n : { alignment: stroke.alignment }),\n ...(stroke?.dash === undefined\n ? context.ephemeral\n ? { dash: [6, 4] }\n : {}\n : { dash: stroke.dash }),\n };\n }\n resolveFill(detection, context) {\n const fill = resolveStyleValue(this.options.fill, detection, context);\n if (fill === null || fill === undefined) {\n return undefined;\n }\n return {\n alpha: fill.alpha ?? 1,\n color: fill.color ?? DEFAULT_BOX_STROKE_COLOR,\n };\n }\n}\n\nvar FocusTargetMode;\n(function (FocusTargetMode) {\n FocusTargetMode[\"Hovered\"] = \"hovered\";\n FocusTargetMode[\"Selected\"] = \"selected\";\n FocusTargetMode[\"HoveredAndSelected\"] = \"hoveredAndSelected\";\n FocusTargetMode[\"Ambient\"] = \"ambient\";\n})(FocusTargetMode || (FocusTargetMode = {}));\n\nconst DEFAULT_FOCUS_FILL_COLOR = 0x020617;\nconst DEFAULT_FOCUS_FILL_ALPHA = 0.45;\nconst DEFAULT_FOCUS_CORNER_RADIUS = 8;\n/**\n * Default configurable focus style.\n *\n * Focus styles dim the current media frame while leaving the selected or\n * hovered detections visible. Renderers may use prepared mask artifacts for\n * shape-accurate cutouts, falling back to detection rectangles when needed.\n */\nclass BaseFocusStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(context) {\n if (this.options.shouldRender?.(context) === false) {\n return undefined;\n }\n const targetMode = this.options.targetMode ?? FocusTargetMode.Selected;\n const targets = getFocusTargets(context, targetMode);\n const ambient = targetMode === FocusTargetMode.Ambient &&\n !context.selectedPick &&\n !context.hoveredPick;\n const fill = resolveFocusStyleValue(this.options.fill, context);\n if (targets.length === 0 || fill === null) {\n return undefined;\n }\n return {\n fallback: this.resolveFallback(context),\n fill: {\n alpha: fill?.alpha ?? DEFAULT_FOCUS_FILL_ALPHA,\n color: fill?.color ?? DEFAULT_FOCUS_FILL_COLOR,\n },\n targetMode,\n targets,\n ...(ambient ? { ambient: true } : {}),\n };\n }\n resolveFallback(context) {\n const shape = resolveFocusStyleValue(this.options.shape, context) ??\n BoxShape.RoundedRect;\n const cornerRadius = shape === BoxShape.RoundedRect\n ? (resolveFocusStyleValue(this.options.cornerRadius, context) ??\n DEFAULT_FOCUS_CORNER_RADIUS)\n : undefined;\n if (cornerRadius === undefined) {\n return { shape };\n }\n return {\n cornerRadius,\n shape,\n };\n }\n}\nfunction getFocusTargets(context, targetMode) {\n const targets = [];\n if (targetMode === FocusTargetMode.Ambient) {\n if (context.selectedPick)\n return [context.selectedPick];\n if (context.hoveredPick)\n return [context.hoveredPick];\n return context.frame.detections.map((detection, detectionIndex) => ({\n detection,\n detectionIndex,\n frame: context.frame,\n mediaTime: context.mediaTime,\n point: detection.rect\n ? { x: detection.rect.x, y: detection.rect.y }\n : { x: 0, y: 0 },\n target: detection.mask\n ? DetectionPickTarget.Mask\n : detection.polygon\n ? DetectionPickTarget.Polygon\n : DetectionPickTarget.Box,\n }));\n }\n if ((targetMode === FocusTargetMode.Selected ||\n targetMode === FocusTargetMode.HoveredAndSelected) &&\n context.selectedPick) {\n targets.push(context.selectedPick);\n }\n if ((targetMode === FocusTargetMode.Hovered ||\n targetMode === FocusTargetMode.HoveredAndSelected) &&\n context.hoveredPick) {\n targets.push(context.hoveredPick);\n }\n return dedupeTargetsForFrame(targets, context.frame);\n}\nfunction dedupeTargetsForFrame(targets, frame) {\n const keys = new Set();\n const dedupedTargets = [];\n for (const target of targets) {\n if (target.frame !== frame) {\n continue;\n }\n const key = `${target.detectionIndex}:${target.target}`;\n if (keys.has(key)) {\n continue;\n }\n keys.add(key);\n dedupedTargets.push(target);\n }\n return dedupedTargets;\n}\nfunction resolveFocusStyleValue(value, context) {\n if (typeof value === \"function\") {\n return value(context);\n }\n return value;\n}\n\nvar DetectionInteractionState;\n(function (DetectionInteractionState) {\n DetectionInteractionState[\"Hovered\"] = \"hovered\";\n DetectionInteractionState[\"Selected\"] = \"selected\";\n})(DetectionInteractionState || (DetectionInteractionState = {}));\n\nconst DEFAULT_HOVER_FILL_COLOR = 0x67e8f9;\nconst DEFAULT_HOVER_FILL_ALPHA = 0.1;\nconst DEFAULT_HOVER_STROKE_COLOR = 0x67e8f9;\nconst DEFAULT_HOVER_STROKE_ALPHA = 0.95;\nconst DEFAULT_HOVER_STROKE_WIDTH = 3;\nconst DEFAULT_SELECTED_FILL_COLOR = 0xfde047;\nconst DEFAULT_SELECTED_FILL_ALPHA = 0.18;\nconst DEFAULT_SELECTED_STROKE_COLOR = 0xfde047;\nconst DEFAULT_SELECTED_STROKE_ALPHA = 1;\nconst DEFAULT_SELECTED_STROKE_WIDTH = 4;\n/**\n * Default configurable interaction style.\n *\n * It resolves hover and selected picks into state-specific presentations using\n * the same style contracts as normal boxes, masks, and labels. The older\n * rectangle options are kept as compatibility sugar and resolve to a box style.\n */\nclass BaseInteractionStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const statePresentation = context.state === DetectionInteractionState.Selected\n ? this.options.selected\n : this.options.hovered;\n if (statePresentation !== undefined) {\n return statePresentation ?? undefined;\n }\n const rect = detection.rect;\n if (!rect) {\n return undefined;\n }\n return {\n boxStyle: createResolvedBoxStyle(this.resolveBoxInstruction(detection, context, rect)),\n };\n }\n resolveBoxInstruction(detection, context, rect) {\n const shape = this.resolveShape(detection, context);\n const cornerRadius = this.resolveCornerRadius(detection, context, shape);\n const instruction = {\n fill: this.resolveFill(detection, context),\n rect,\n shape,\n stroke: this.resolveStroke(detection, context),\n };\n if (cornerRadius !== undefined) {\n return {\n ...instruction,\n cornerRadius,\n };\n }\n return instruction;\n }\n resolveShape(detection, context) {\n return (resolveStyleValue(this.options.shape, detection, context) ?? BoxShape.Rect);\n }\n resolveCornerRadius(detection, context, shape) {\n if (shape !== BoxShape.RoundedRect) {\n return undefined;\n }\n return resolveStyleValue(this.options.cornerRadius, detection, context);\n }\n resolveStroke(detection, context) {\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n if (stroke === null) {\n return undefined;\n }\n const defaults = getStateDefaults(context.state);\n const resolvedStroke = {\n alpha: stroke?.alpha ?? defaults.strokeAlpha,\n color: stroke?.color ?? defaults.strokeColor,\n width: stroke?.width ?? defaults.strokeWidth,\n };\n if (stroke?.alignment !== undefined) {\n return {\n ...resolvedStroke,\n alignment: stroke.alignment,\n };\n }\n return resolvedStroke;\n }\n resolveFill(detection, context) {\n const fill = resolveStyleValue(this.options.fill, detection, context);\n if (fill === null) {\n return undefined;\n }\n const defaults = getStateDefaults(context.state);\n return {\n alpha: fill?.alpha ?? defaults.fillAlpha,\n color: fill?.color ?? defaults.fillColor,\n };\n }\n}\nfunction createResolvedBoxStyle(instruction) {\n return {\n resolve() {\n return instruction;\n },\n };\n}\nfunction getStateDefaults(state) {\n if (state === DetectionInteractionState.Selected) {\n return {\n fillAlpha: DEFAULT_SELECTED_FILL_ALPHA,\n fillColor: DEFAULT_SELECTED_FILL_COLOR,\n strokeAlpha: DEFAULT_SELECTED_STROKE_ALPHA,\n strokeColor: DEFAULT_SELECTED_STROKE_COLOR,\n strokeWidth: DEFAULT_SELECTED_STROKE_WIDTH,\n };\n }\n return {\n fillAlpha: DEFAULT_HOVER_FILL_ALPHA,\n fillColor: DEFAULT_HOVER_FILL_COLOR,\n strokeAlpha: DEFAULT_HOVER_STROKE_ALPHA,\n strokeColor: DEFAULT_HOVER_STROKE_COLOR,\n strokeWidth: DEFAULT_HOVER_STROKE_WIDTH,\n };\n}\n\nvar 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 = {}));\nvar LabelVisibilityMode;\n(function (LabelVisibilityMode) {\n LabelVisibilityMode[\"Always\"] = \"always\";\n LabelVisibilityMode[\"HoveredOnly\"] = \"hoveredOnly\";\n})(LabelVisibilityMode || (LabelVisibilityMode = {}));\n\n/** Returns black or white for readable text over an RGB background. */\nfunction resolveContrastTextColor(color) {\n \"worklet\";\n const red = (color >> 16) & 0xff;\n const green = (color >> 8) & 0xff;\n const blue = color & 0xff;\n const luminance = (red * 299 + green * 587 + blue * 114) / 1000;\n return luminance >= 150 ? 0x111111 : 0xffffff;\n}\nfunction lightenColor(color, amount = 0.14) {\n \"worklet\";\n const mix = (value) => Math.round(value + (255 - value) * amount);\n return ((mix((color >> 16) & 0xff) << 16) |\n (mix((color >> 8) & 0xff) << 8) |\n mix(color & 0xff));\n}\n\n/**\n * Default label style.\n *\n * Resolves labels from `className`, `metadata.label`, or a custom text\n * resolver, optionally including confidence.\n */\nclass BaseLabelStyle {\n includeConfidence;\n offsetY;\n options;\n constructor(options = {}) {\n this.options = options;\n this.includeConfidence = options.includeConfidence ?? false;\n this.offsetY = options.offsetY ?? 0;\n }\n resolve(detection, context) {\n if (!getDetectionRect(detection) ||\n context.hidden ||\n (this.options.visibilityMode === LabelVisibilityMode.HoveredOnly &&\n !context.hovered) ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const text = resolveStyleValue(this.options.text, detection, context) ??\n formatDetectionLabel(detection, this.includeConfidence);\n if (!text) {\n return undefined;\n }\n const background = this.resolveBackground(detection, context);\n return {\n background,\n ...this.resolveOffset(detection, context),\n placement: this.resolvePlacement(detection, context),\n rect: getDetectionRect(detection),\n text,\n textStyle: this.resolveTextStyle(detection, context, background),\n };\n }\n resolveBackground(detection, context) {\n const background = resolveStyleValue(this.options.background, detection, context);\n return {\n alpha: background?.alpha ?? 0.72,\n color: context.hovered\n ? lightenColor(background?.color ?? 0x111827)\n : (background?.color ?? 0x111827),\n cornerRadius: background?.cornerRadius ?? 4,\n paddingX: background?.paddingX ?? 6,\n paddingY: background?.paddingY ?? 3,\n ...(background?.topCornersOnly === undefined\n ? {}\n : { topCornersOnly: background.topCornersOnly }),\n };\n }\n resolveTextStyle(detection, context, background) {\n const textStyle = resolveStyleValue(this.options.textStyle, detection, context);\n return {\n alpha: textStyle?.alpha ?? 1,\n color: textStyle?.color ?? resolveContrastTextColor(background.color),\n fontFamily: textStyle?.fontFamily ?? \"Inter, sans-serif\",\n fontSize: textStyle?.fontSize ?? 13,\n fontWeight: textStyle?.fontWeight ?? \"600\",\n };\n }\n resolveOffset(detection, context) {\n const offset = resolveStyleValue(this.options.offset, detection, context);\n if (offset === null) {\n return {};\n }\n return {\n ...(offset?.x === undefined ? {} : { offsetX: offset.x }),\n offsetY: offset?.y ?? this.offsetY,\n };\n }\n resolvePlacement(detection, context) {\n return (resolveStyleValue(this.options.placement, detection, context) ??\n LabelPlacement.Top);\n }\n}\nfunction formatDetectionLabel(detection, includeConfidence) {\n const label = detection.className ??\n (typeof detection.metadata?.label === \"string\"\n ? detection.metadata.label\n : undefined);\n if (!label) {\n return undefined;\n }\n if (!includeConfidence || detection.confidence === undefined) {\n return label;\n }\n return `${label} ${Math.round(detection.confidence * 100)}%`;\n}\n\nvar MaskRenderMode;\n(function (MaskRenderMode) {\n MaskRenderMode[\"FillAndStroke\"] = \"fillAndStroke\";\n MaskRenderMode[\"FillOnly\"] = \"fillOnly\";\n MaskRenderMode[\"StrokeOnly\"] = \"strokeOnly\";\n})(MaskRenderMode || (MaskRenderMode = {}));\n\n/**\n * Default compressed-RLE mask style.\n *\n * Static color/stroke options can reuse prepared mask artifacts by key. Dynamic\n * color or stroke resolvers intentionally do not expose an artifact key, so new\n * style objects rebuild prepared palettes instead of reusing stale ones.\n */\nclass BaseMaskStyle {\n artifactKey;\n opacity;\n options;\n constructor(options = {}) {\n this.options = options;\n this.opacity = clampOpacity(options.opacity ?? options.alpha ?? 0.35);\n this.artifactKey = createArtifactKey(options);\n }\n resolve(detection, context) {\n if (!detection.mask ||\n context.hidden ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const color = resolveStyleValue(this.options.color, detection, context) ??\n DEFAULT_MASK_COLOR;\n const mode = resolveStyleValue(this.options.mode, detection, context) ??\n MaskRenderMode.FillAndStroke;\n const stroke = resolveStroke(resolveStyleValue(this.options.stroke, detection, context), color, mode);\n return {\n alpha: mode === MaskRenderMode.StrokeOnly\n ? 0\n : clampOpacity(resolveStyleValue(this.options.fillAlpha, detection, context) ??\n 1),\n color,\n mask: detection.mask,\n stroke: mode === MaskRenderMode.FillOnly ? undefined : stroke,\n };\n }\n}\nconst DEFAULT_MASK_COLOR = 0x00ff66;\nconst DEFAULT_MASK_STROKE_ALPHA = 1;\nconst DEFAULT_MASK_STROKE_WIDTH = 1;\nfunction clampOpacity(opacity) {\n return Number.isFinite(opacity) ? Math.max(0, Math.min(opacity, 1)) : 1;\n}\nfunction serializeStroke(stroke) {\n if (!stroke) {\n return \"none\";\n }\n return `${stroke.color}:${stroke.alpha}:${stroke.width}`;\n}\nfunction normalizeStroke(stroke, fallbackColor) {\n if (!stroke) {\n return undefined;\n }\n return {\n alpha: stroke.alpha ?? DEFAULT_MASK_STROKE_ALPHA,\n color: stroke.color ?? fallbackColor,\n width: stroke.width ?? DEFAULT_MASK_STROKE_WIDTH,\n };\n}\nfunction resolveStroke(stroke, fallbackColor, mode) {\n if (mode === MaskRenderMode.FillOnly) {\n return undefined;\n }\n if (mode === MaskRenderMode.StrokeOnly && stroke === undefined) {\n return normalizeStroke({}, fallbackColor);\n }\n return normalizeStroke(stroke, fallbackColor);\n}\nfunction createArtifactKey(options) {\n if (typeof options.color === \"function\" ||\n typeof options.fillAlpha === \"function\" ||\n typeof options.mode === \"function\" ||\n typeof options.stroke === \"function\") {\n return undefined;\n }\n const color = options.color ?? DEFAULT_MASK_COLOR;\n const fillAlpha = options.fillAlpha ?? 1;\n const mode = options.mode ?? MaskRenderMode.FillAndStroke;\n return `base:${color}:${fillAlpha}:${mode}:${serializeStroke(resolveStroke(options.stroke, color, mode))}`;\n}\n\nclass BasePolygonStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (!detection.polygon ||\n context.hidden ||\n detection.polygon.points.length < 3 ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const fill = resolveStyleValue(this.options.fill, detection, context);\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n return {\n points: detection.polygon.points,\n ...(fill === null\n ? {}\n : {\n fill: {\n alpha: fill?.alpha ?? 0.16,\n color: fill?.color ?? 0x00ff66,\n },\n }),\n ...(stroke === null\n ? {}\n : {\n stroke: {\n alpha: stroke?.alpha ?? 1,\n color: stroke?.color ?? 0x00ff66,\n width: stroke?.width ?? 2,\n ...(stroke?.alignment === undefined\n ? {}\n : { alignment: stroke.alignment }),\n ...(stroke?.dash === undefined ? {} : { dash: stroke.dash }),\n },\n }),\n };\n }\n}\n\nclass BasePolylineStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n if (!detection.polyline ||\n context.hidden ||\n detection.polyline.points.length < 2 ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const stroke = resolveStyleValue(this.options.stroke, detection, context);\n if (stroke === null) {\n return undefined;\n }\n return {\n points: detection.polyline.points,\n stroke: {\n alpha: stroke?.alpha ?? 1,\n color: stroke?.color ?? 0x00ff66,\n width: stroke?.width ?? 2,\n ...(stroke?.alignment === undefined\n ? {}\n : { alignment: stroke.alignment }),\n ...(stroke?.dash === undefined ? {} : { dash: stroke.dash }),\n },\n };\n }\n}\n\nvar KeypointMarkerShape;\n(function (KeypointMarkerShape) {\n KeypointMarkerShape[\"Circle\"] = \"circle\";\n KeypointMarkerShape[\"Cross\"] = \"cross\";\n})(KeypointMarkerShape || (KeypointMarkerShape = {}));\n\nclass BaseKeypointStyle {\n options;\n constructor(options = {}) {\n this.options = options;\n }\n resolve(detection, context) {\n const geometry = detection.keypoints;\n if (!geometry ||\n context.hidden ||\n this.options.shouldRender?.(detection, context) === false) {\n return undefined;\n }\n const definition = detection.className\n ? this.options.definitions?.[detection.className]\n : undefined;\n const markerFill = resolveStyleValue(this.options.markerFill, detection, context);\n const markerStroke = resolveStyleValue(this.options.markerStroke, detection, context);\n const edgeStroke = resolveStyleValue(this.options.edgeStroke, detection, context);\n const shadowStroke = resolveStyleValue(this.options.edgeShadowStroke, detection, context);\n const radius = resolveStyleValue(this.options.radius, detection, context) ?? 6;\n const edges = geometry.edges.map(([fromIndex, toIndex], edgeIndex) => ({\n from: geometry.points[fromIndex],\n to: geometry.points[toIndex],\n stroke: {\n alpha: edgeStroke?.alpha ?? 1,\n color: definition?.edges[edgeIndex]?.color ?? edgeStroke?.color ?? 0x00ff66,\n width: edgeStroke?.width ?? 2,\n },\n ...(shadowStroke === null\n ? {}\n : {\n shadowStroke: {\n alpha: shadowStroke?.alpha ?? 0.65,\n color: shadowStroke?.color ?? 0x000000,\n width: shadowStroke?.width ?? 4,\n },\n }),\n }));\n const markers = geometry.points.flatMap((point, index) => {\n const visibility = geometry.visibility?.[index] ?? KeypointVisibility.Visible;\n if (visibility === KeypointVisibility.NotLabeled) {\n return [];\n }\n return [\n {\n fill: {\n alpha: markerFill?.alpha ?? 1,\n color: definition?.vertices[index]?.color ??\n markerFill?.color ??\n 0x00ff66,\n },\n index,\n point,\n radius,\n shape: visibility === KeypointVisibility.Occluded\n ? KeypointMarkerShape.Cross\n : KeypointMarkerShape.Circle,\n stroke: {\n alpha: markerStroke?.alpha ?? 1,\n color: markerStroke?.color ?? 0xffffff,\n width: markerStroke?.width ?? 2,\n },\n },\n ];\n });\n return { edges, markers };\n }\n}\n\nconst SUPERVISION_ROBOFLOW_COLOR = 0xa351fb;\nconst DEFAULT_DETECTION_COLOR_SEQUENCE = [\n createClassColorStyle(0x38bdf8, 0x164e63, 0xecfeff, 0x7dd3fc),\n createClassColorStyle(0x22c55e, 0x14532d, 0xf0fdf4, 0x86efac),\n createClassColorStyle(0xa78bfa, 0x4c1d95, 0xf5f3ff, 0xc4b5fd),\n createClassColorStyle(0xfacc15, 0x713f12, 0xfffbeb, 0xfde047),\n createClassColorStyle(0xf97316, 0x7c2d12, 0xfff7ed, 0xffa23a),\n createClassColorStyle(0xf472b6, 0x831843, 0xfdf2f8, 0xf9a8d4),\n createClassColorStyle(0x60a5fa, 0x1e3a8a, 0xeff6ff, 0x93c5fd),\n createClassColorStyle(0xfb7185, 0x881337, 0xfff1f2, 0xfda4af),\n createClassColorStyle(0x34d399, 0x064e3b, 0xecfdf5, 0x6ee7b7),\n createClassColorStyle(0xe879f9, 0x701a75, 0xfdf4ff, 0xf0abfc),\n];\nconst DEFAULT_DETECTION_CLASS_STYLES = {\n basketball: DEFAULT_DETECTION_COLOR_SEQUENCE[4],\n bed: DEFAULT_DETECTION_COLOR_SEQUENCE[5],\n bottle: DEFAULT_DETECTION_COLOR_SEQUENCE[4],\n \"cell phone\": DEFAULT_DETECTION_COLOR_SEQUENCE[8],\n cow: DEFAULT_DETECTION_COLOR_SEQUENCE[2],\n cup: DEFAULT_DETECTION_COLOR_SEQUENCE[3],\n horse: DEFAULT_DETECTION_COLOR_SEQUENCE[0],\n keyboard: DEFAULT_DETECTION_COLOR_SEQUENCE[1],\n knife: DEFAULT_DETECTION_COLOR_SEQUENCE[7],\n laptop: DEFAULT_DETECTION_COLOR_SEQUENCE[6],\n person: DEFAULT_DETECTION_COLOR_SEQUENCE[1],\n \"potted plant\": DEFAULT_DETECTION_COLOR_SEQUENCE[8],\n \"sports ball\": DEFAULT_DETECTION_COLOR_SEQUENCE[4],\n tv: DEFAULT_DETECTION_COLOR_SEQUENCE[2],\n \"white team player\": createClassColorStyle(0xf8fafc, 0x334155, 0xffffff, 0xffffff),\n \"yellow team player\": DEFAULT_DETECTION_COLOR_SEQUENCE[3],\n};\n// The \"worklet\" directives below are inert everywhere except React Native:\n// browsers and Node see a no-op string, while React Native's worklets Babel\n// plugin makes these functions callable inside frame worklets, so every\n// platform resolves detection colors through this one implementation.\n// Worklet constraint on ordering: the plugin turns marked declarations into\n// non-hoisted assignments that capture each other at module-init time, so\n// helpers must be defined before the functions that call them.\nfunction normalizeDetectionClassName(className) {\n \"worklet\";\n return (className ?? \"\")\n .trim()\n .toLowerCase()\n .replace(/[_-]/g, \" \")\n .replace(/\\s+/g, \" \");\n}\nfunction hashClassName(className) {\n \"worklet\";\n let hash = 0;\n for (let index = 0; index < className.length; index += 1) {\n hash = (hash * 31 + className.charCodeAt(index)) >>> 0;\n }\n return hash;\n}\nfunction resolveDetectionClassColorStyle(className) {\n \"worklet\";\n const normalizedClassName = normalizeDetectionClassName(className);\n const knownStyle = DEFAULT_DETECTION_CLASS_STYLES[normalizedClassName];\n if (knownStyle) {\n return knownStyle;\n }\n return DEFAULT_DETECTION_COLOR_SEQUENCE[hashClassName(normalizedClassName) % DEFAULT_DETECTION_COLOR_SEQUENCE.length];\n}\nfunction createClassColorStyle(fill, labelBackground, labelText, stroke) {\n return {\n fill,\n labelBackground,\n labelText,\n stroke,\n };\n}\n\nconst DEFAULT_BOX_CORNER_RADIUS = 1;\nconst DEFAULT_OUTLINE_WIDTH = 2;\nconst DEFAULT_FILL_ALPHA = 0.08;\nconst DEFAULT_MASK_FILL_ALPHA = 0.45;\nconst DEFAULT_KEYPOINT_EDGE_WIDTH = 1.5;\nconst DEFAULT_KEYPOINT_SHADOW_WIDTH = 3;\nconst DEFAULT_KEYPOINT_SHADOW_ALPHA = 0.25;\nconst DEFAULT_KEYPOINT_RADIUS = 3.5;\nconst DEFAULT_LABEL_CORNER_RADIUS = 4;\nconst DEFAULT_LABEL_PADDING_X = 6;\nconst DEFAULT_LABEL_PADDING_Y = 3;\nconst DEFAULT_LABEL_FONT_SIZE = 12;\nconst DEFAULT_LABEL_FONT_FAMILY = \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace\";\n/**\n * Builds the canonical, unselected annotation presentation used by Roboflow's\n * Core annotation editor. It deliberately excludes host-specific interaction,\n * editing, focus, and theme behaviour so consumers can compose those layers.\n */\nfunction createDefaultAnnotationPresentation(options = {}) {\n return {\n boxStyle: createDefaultBoxStyle(options),\n keypointStyle: createDefaultKeypointStyle(options),\n labelStyle: createDefaultLabelStyle(options),\n maskStyle: createDefaultMaskStyle(options),\n polygonStyle: createDefaultPolygonStyle(options),\n polylineStyle: createDefaultPolylineStyle(options),\n };\n}\n/**\n * The canonical default style of one built-in layer.\n *\n * These exist so a renderer kind can build only the style it needs instead of\n * the whole default presentation. Keep them equivalent to the matching field of\n * {@link createDefaultAnnotationPresentation}.\n */\nfunction createDefaultBoxStyle(options = {}) {\n const getClassColor = createClassColorResolver(options);\n return new BaseBoxStyle({\n cornerRadius: DEFAULT_BOX_CORNER_RADIUS,\n fill: (detection) => ({\n alpha: DEFAULT_FILL_ALPHA,\n color: getClassColor(detection),\n }),\n shape: BoxShape.RoundedRect,\n shouldRender: (detection) => !(detection.mask ||\n detection.polygon ||\n detection.polyline ||\n detection.keypoints),\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n });\n}\nfunction createDefaultKeypointStyle(options = {}) {\n const getClassColor = createClassColorResolver(options);\n return new BaseKeypointStyle({\n ...(options.skeletonDefinitions === undefined\n ? {}\n : { definitions: options.skeletonDefinitions }),\n edgeShadowStroke: {\n alpha: DEFAULT_KEYPOINT_SHADOW_ALPHA,\n color: 0x000000,\n width: DEFAULT_KEYPOINT_SHADOW_WIDTH,\n },\n edgeStroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_KEYPOINT_EDGE_WIDTH,\n }),\n markerFill: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n }),\n markerStroke: { alpha: 1, color: 0xffffff, width: 1 },\n radius: DEFAULT_KEYPOINT_RADIUS,\n });\n}\nfunction createDefaultLabelStyle(options = {}) {\n const getClassColor = createClassColorResolver(options);\n return new BaseLabelStyle({\n background: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n cornerRadius: DEFAULT_LABEL_CORNER_RADIUS,\n paddingX: DEFAULT_LABEL_PADDING_X,\n paddingY: DEFAULT_LABEL_PADDING_Y,\n topCornersOnly: true,\n }),\n includeConfidence: options.includeConfidence,\n placement: LabelPlacement.Top,\n textStyle: {\n fontFamily: DEFAULT_LABEL_FONT_FAMILY,\n fontSize: DEFAULT_LABEL_FONT_SIZE,\n fontWeight: \"600\",\n },\n });\n}\nfunction createDefaultMaskStyle(options = {}) {\n const getClassColor = createClassColorResolver(options);\n return new BaseMaskStyle({\n color: (detection) => getClassColor(detection),\n fillAlpha: DEFAULT_MASK_FILL_ALPHA,\n mode: MaskRenderMode.FillAndStroke,\n opacity: 1,\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n });\n}\nfunction createDefaultPolygonStyle(options = {}) {\n const getClassColor = createClassColorResolver(options);\n return new BasePolygonStyle({\n fill: (detection) => ({\n alpha: DEFAULT_FILL_ALPHA,\n color: getClassColor(detection),\n }),\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n });\n}\nfunction createDefaultPolylineStyle(options = {}) {\n const getClassColor = createClassColorResolver(options);\n return new BasePolylineStyle({\n stroke: (detection) => ({\n alpha: 1,\n color: getClassColor(detection),\n width: DEFAULT_OUTLINE_WIDTH,\n }),\n });\n}\nfunction createClassColorResolver(options) {\n return (detection) => resolveDefaultClassColor(detection, options.getClassColor);\n}\nfunction resolveDefaultClassColor(detection, getClassColor) {\n const color = getClassColor?.(detection.className);\n return typeof color === \"number\" && Number.isFinite(color)\n ? color\n : resolveDetectionClassColorStyle(detection.className).fill;\n}\n\n/**\n * The built-in annotation renderer vocabulary.\n *\n * These stay plain string literals so `{ kind: \"box\" }` remains assignable to\n * the public descriptor union from JavaScript and TypeScript alike.\n */\nconst annotationRendererKinds = [\n \"box\",\n \"keypoints\",\n \"label\",\n \"mask\",\n \"polygon\",\n \"polyline\",\n];\n/**\n * Creates built-in annotation renderer descriptors for\n * `MediaRendererPresentation.renderers`.\n *\n * The currently supported renderers retain their established scene ordering:\n * masks, polygons, vectors, labels. A later renderer kind may add a new\n * composition capability without changing that ordering for existing scenes.\n */\nconst annotationRenderers = {\n box: (options) => createAnnotationRenderer(\"box\", options),\n keypoints: (options) => createAnnotationRenderer(\"keypoints\", options),\n label: (options) => createAnnotationRenderer(\"label\", options),\n mask: (options) => createAnnotationRenderer(\"mask\", options),\n polygon: (options) => createAnnotationRenderer(\"polygon\", options),\n polyline: (options) => createAnnotationRenderer(\"polyline\", options),\n};\nfunction createAnnotationRenderer(kind, options) {\n // Every built-in renderer keeps its kind as its stable id. TypeScript cannot\n // narrow the descriptor union through the generic kind parameter, so the\n // descriptor shape is asserted here and covered by a focused test.\n return { id: kind, kind, ...options };\n}\n\nconst annotationRendererRegistry = {\n box: { createCanonicalStyle: createDefaultBoxStyle, styleField: \"boxStyle\" },\n keypoints: {\n createCanonicalStyle: createDefaultKeypointStyle,\n styleField: \"keypointStyle\",\n },\n label: {\n createCanonicalStyle: createDefaultLabelStyle,\n styleField: \"labelStyle\",\n },\n mask: {\n createCanonicalStyle: createDefaultMaskStyle,\n styleField: \"maskStyle\",\n },\n polygon: {\n createCanonicalStyle: createDefaultPolygonStyle,\n styleField: \"polygonStyle\",\n },\n polyline: {\n createCanonicalStyle: createDefaultPolylineStyle,\n styleField: \"polylineStyle\",\n },\n};\n/** Presentation fields owned by the given renderer kinds, in the same order. */\nfunction resolveAnnotationRendererStyleFields(kinds) {\n return kinds.map((kind) => annotationRendererRegistry[kind].styleField);\n}\n\n/**\n * Resolves built-in renderer descriptors into the existing specialized style\n * fields. The browser backend deliberately keeps ownership of its box, mask,\n * label, polygon, polyline, and keypoint pipelines; this normalizer only\n * supplies those pipelines with their configured style.\n */\nfunction resolveAnnotationRendererPresentation(presentation) {\n const renderers = presentation.renderers;\n if (renderers === undefined) {\n return presentation;\n }\n const resolved = {\n boxStyle: null,\n keypointStyle: null,\n labelStyle: null,\n maskStyle: null,\n polygonStyle: null,\n polylineStyle: null,\n };\n const rendererIds = new Set();\n const rendererKinds = new Set();\n for (const renderer of renderers) {\n if (rendererIds.has(renderer.id)) {\n throw new RangeError(`MediaRendererPresentation.renderers contains duplicate renderer id \"${renderer.id}\".`);\n }\n rendererIds.add(renderer.id);\n if (rendererKinds.has(renderer.kind)) {\n throw new RangeError(`MediaRendererPresentation.renderers contains duplicate renderer kind \"${renderer.kind}\".`);\n }\n rendererKinds.add(renderer.kind);\n applyRendererStyle(resolved, presentation, renderer);\n }\n return {\n ...presentation,\n ...resolved,\n };\n}\nfunction applyRendererStyle(resolved, configured, renderer) {\n const { createCanonicalStyle, styleField } = annotationRendererRegistry[renderer.kind];\n const configuredStyle = configured[styleField];\n const style = renderer.style !== undefined\n ? renderer.style\n : configuredStyle !== undefined\n ? configuredStyle\n : createCanonicalStyle();\n // The registry pairs each kind with the presentation field holding the same\n // style contract, but TypeScript cannot correlate that pairing across a\n // lookup on a union, so the write is asserted once here.\n resolved[styleField] = style;\n}\n\nfunction createSourceAwarePresentation(globalPresentation = {}, sources, options = {}) {\n if (!sources.some((source) => source.presentation !== undefined)) {\n return globalPresentation;\n }\n const sourcePresentations = new Map(sources.map((source) => [source.id, source.presentation]));\n const enabledStyleFields = options.enabledRendererKinds === undefined\n ? undefined\n : new Set(resolveAnnotationRendererStyleFields(options.enabledRendererKinds));\n const shouldApplySourceStyle = (style) => hasSourceStyle(sources, style) &&\n (enabledStyleFields === undefined || enabledStyleFields.has(style));\n return {\n ...globalPresentation,\n boxStyle: shouldApplySourceStyle(\"boxStyle\")\n ? new SourceAwareBoxStyle(normalizeGlobalBoxStyle(globalPresentation.boxStyle), sourcePresentations)\n : globalPresentation.boxStyle,\n labelStyle: shouldApplySourceStyle(\"labelStyle\")\n ? new SourceAwareLabelStyle(normalizeGlobalLabelStyle(globalPresentation.labelStyle), sourcePresentations)\n : globalPresentation.labelStyle,\n maskStyle: shouldApplySourceStyle(\"maskStyle\")\n ? new SourceAwareMaskStyle(normalizeGlobalMaskStyle(globalPresentation.maskStyle), sourcePresentations)\n : globalPresentation.maskStyle,\n polygonStyle: shouldApplySourceStyle(\"polygonStyle\")\n ? new SourceAwarePolygonStyle(normalizeGlobalPolygonStyle(globalPresentation.polygonStyle), sourcePresentations)\n : globalPresentation.polygonStyle,\n polylineStyle: shouldApplySourceStyle(\"polylineStyle\")\n ? new SourceAwarePolylineStyle(normalizeGlobalPolylineStyle(globalPresentation.polylineStyle), sourcePresentations)\n : globalPresentation.polylineStyle,\n keypointStyle: shouldApplySourceStyle(\"keypointStyle\")\n ? new SourceAwareKeypointStyle(normalizeGlobalKeypointStyle(globalPresentation.keypointStyle), sourcePresentations)\n : globalPresentation.keypointStyle,\n };\n}\nclass SourceAwareBoxStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"boxStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwareLabelStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"labelStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwareMaskStyle {\n globalStyle;\n sourcePresentations;\n artifactKey = undefined;\n opacity;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n this.opacity = globalStyle?.opacity;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"maskStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwarePolygonStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"polygonStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwarePolylineStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"polylineStyle\");\n return style?.resolve(detection, context);\n }\n}\nclass SourceAwareKeypointStyle {\n globalStyle;\n sourcePresentations;\n constructor(globalStyle, sourcePresentations) {\n this.globalStyle = globalStyle;\n this.sourcePresentations = sourcePresentations;\n }\n resolve(detection, context) {\n const style = resolveSourceStyle(detection, this.globalStyle, this.sourcePresentations, \"keypointStyle\");\n return style?.resolve(detection, context);\n }\n}\nfunction hasSourceStyle(sources, key) {\n return sources.some((source) => source.presentation?.[key] !== undefined);\n}\nfunction resolveSourceStyle(detection, globalStyle, sourcePresentations, key) {\n const sourcePresentation = detection.sourceId\n ? sourcePresentations.get(detection.sourceId)\n : undefined;\n const sourceStyle = sourcePresentation?.[key];\n return sourceStyle === undefined ? globalStyle : sourceStyle;\n}\nfunction normalizeGlobalBoxStyle(style) {\n return style === undefined ? new BaseBoxStyle() : style;\n}\nfunction normalizeGlobalLabelStyle(style) {\n return style === undefined ? new BaseLabelStyle() : style;\n}\nfunction normalizeGlobalMaskStyle(style) {\n return style === undefined ? new BaseMaskStyle() : style;\n}\nfunction normalizeGlobalPolygonStyle(style) {\n return style === undefined ? new BasePolygonStyle() : style;\n}\nfunction normalizeGlobalPolylineStyle(style) {\n return style === undefined ? new BasePolylineStyle() : style;\n}\nfunction normalizeGlobalKeypointStyle(style) {\n return style === undefined ? new BaseKeypointStyle() : style;\n}\n\nvar DetectionMaskPayloadFormat;\n(function (DetectionMaskPayloadFormat) {\n DetectionMaskPayloadFormat[\"RawCocoRle\"] = \"rawCocoRle\";\n DetectionMaskPayloadFormat[\"DeflatedBase64\"] = \"deflatedBase64\";\n})(DetectionMaskPayloadFormat || (DetectionMaskPayloadFormat = {}));\nfunction 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/** Encodes a binary mask and derives its bounds in the same raster traversal. */\nfunction encodeBinaryMaskWithBounds(data, width, height) {\n assertMaskDimensions(data, width, height);\n const runs = [];\n let currentValue = 0;\n let runLength = 0;\n let minX = width;\n let minY = height;\n let maxX = -1;\n let maxY = -1;\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) {\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\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 bounds: maxX < 0\n ? null\n : {\n height: maxY - minY + 1,\n width: maxX - minX + 1,\n x: minX + (maxX - minX + 1) / 2,\n y: minY + (maxY - minY + 1) / 2,\n },\n mask: {\n counts: encodeCompressedRleCounts(runs),\n encoding: DetectionMaskEncoding.CompressedRle,\n height,\n width,\n },\n };\n}\nfunction encodeDetectionMaskPayload(mask, codec) {\n return codec ? codec.deflate(mask.counts) : mask.counts;\n}\nfunction decodeDetectionMaskPayload(payload, width, height, options = {}) {\n const format = options.format ??\n (isDeflatedBase64DetectionMaskPayload(payload)\n ? DetectionMaskPayloadFormat.DeflatedBase64\n : DetectionMaskPayloadFormat.RawCocoRle);\n if (format === DetectionMaskPayloadFormat.DeflatedBase64 && !options.codec) {\n throw new Error(\"A detection mask compression codec is required for deflated payloads.\");\n }\n return {\n counts: format === DetectionMaskPayloadFormat.DeflatedBase64\n ? options.codec.inflate(payload)\n : payload,\n encoding: DetectionMaskEncoding.CompressedRle,\n height,\n width,\n };\n}\n/** Matches the annotation editor's legacy transport-format heuristic. */\nfunction isDeflatedBase64DetectionMaskPayload(value) {\n return value.length > 100 && /^[A-Za-z0-9+/]+={0,2}$/.test(value);\n}\nfunction computeMaskBounds(data, width, height) {\n assertMaskDimensions(data, width, height);\n let minX = width;\n let minY = height;\n let maxX = -1;\n let maxY = -1;\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n if (!data[y * width + x]) {\n continue;\n }\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n }\n if (maxX < 0) {\n return null;\n }\n const boundsWidth = maxX - minX + 1;\n const boundsHeight = maxY - minY + 1;\n return {\n height: boundsHeight,\n width: boundsWidth,\n x: minX + boundsWidth / 2,\n y: minY + boundsHeight / 2,\n };\n}\nfunction computeDetectionMaskRect(mask) {\n const decoded = decodeCompressedRleMask(mask);\n const bounds = computeMaskBounds(decoded.data, decoded.width, decoded.height);\n return bounds ?? undefined;\n}\nfunction detectMaskBorders(data, width, height) {\n assertMaskDimensions(data, width, height);\n const borders = new Uint8Array(data.length);\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const offset = y * width + x;\n if (!data[offset]) {\n continue;\n }\n if (x === 0 ||\n y === 0 ||\n x === width - 1 ||\n y === height - 1 ||\n !data[offset - 1] ||\n !data[offset + 1] ||\n !data[offset - width] ||\n !data[offset + width]) {\n borders[offset] = 1;\n }\n }\n }\n return borders;\n}\nfunction extractMaskContour(data, width, height) {\n assertMaskDimensions(data, width, height);\n const stride = Math.max(1, Math.floor(height / 100));\n const leftEdge = [];\n const rightEdge = [];\n for (let y = 0; y < height; y += stride) {\n let left = -1;\n let right = -1;\n for (let x = 0; x < width; x += 1) {\n if (data[y * width + x]) {\n left = left === -1 ? x : left;\n right = x;\n }\n }\n if (left !== -1) {\n leftEdge.push({ x: left, y });\n rightEdge.push({ x: right, y });\n }\n }\n return leftEdge.length < 2\n ? undefined\n : [...leftEdge, ...rightEdge.reverse()];\n}\nfunction extractMaskRectRuns(data, width, height) {\n assertMaskDimensions(data, width, height);\n const rects = [];\n const openRects = new Map();\n for (let y = 0; y < height; y += 1) {\n const activeSpans = new Set();\n let x = 0;\n while (x < width) {\n while (x < width && !data[y * width + x]) {\n x += 1;\n }\n if (x >= width) {\n break;\n }\n const startX = x;\n while (x < width && data[y * width + x]) {\n x += 1;\n }\n const runWidth = x - startX;\n const key = `${startX}:${runWidth}`;\n const openRect = openRects.get(key);\n activeSpans.add(key);\n if (openRect && openRect.y + openRect.height === y) {\n openRects.set(key, { ...openRect, height: openRect.height + 1 });\n }\n else {\n if (openRect) {\n rects.push(openRect);\n }\n openRects.set(key, { height: 1, width: runWidth, x: startX, y });\n }\n }\n for (const [key, openRect] of openRects) {\n if (!activeSpans.has(key)) {\n rects.push(openRect);\n openRects.delete(key);\n }\n }\n }\n rects.push(...openRects.values());\n return rects.length > 0 ? rects : undefined;\n}\nfunction 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\nfunction rectToPolygon(rect) {\n const halfWidth = rect.width / 2;\n const halfHeight = rect.height / 2;\n return {\n points: [\n { x: rect.x - halfWidth, y: rect.y - halfHeight },\n { x: rect.x + halfWidth, y: rect.y - halfHeight },\n { x: rect.x + halfWidth, y: rect.y + halfHeight },\n { x: rect.x - halfWidth, y: rect.y + halfHeight },\n ],\n };\n}\nfunction polygonToRect(polygon) {\n return getPointsRect(polygon.points);\n}\nfunction rasterizeRectToMask(rect, dimensions) {\n const data = createEmptyMask(dimensions);\n const topLeft = centerRectToTopLeftRect(rect);\n const left = Math.max(0, Math.round(topLeft.x));\n const top = Math.max(0, Math.round(topLeft.y));\n const right = Math.min(dimensions.width - 1, Math.round(rect.x + rect.width / 2));\n const bottom = Math.min(dimensions.height - 1, Math.round(rect.y + rect.height / 2));\n for (let y = top; y <= bottom; y += 1) {\n for (let x = left; x <= right; x += 1) {\n data[y * dimensions.width + x] = 1;\n }\n }\n return data;\n}\nfunction 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}\nfunction convertDetectionBoxToPolygon(detection) {\n return detection.rect\n ? replaceGeometry(detection, { polygon: rectToPolygon(detection.rect) })\n : detection;\n}\nfunction convertDetectionPolygonToBox(detection) {\n const rect = detection.polygon ? polygonToRect(detection.polygon) : undefined;\n return rect ? replaceGeometry(detection, { rect }) : detection;\n}\nfunction convertDetectionMaskToBox(detection) {\n const rect = detection.mask\n ? computeDetectionMaskRect(detection.mask)\n : undefined;\n return rect ? replaceGeometry(detection, { rect }) : detection;\n}\nfunction convertDetectionMaskToPolygon(detection) {\n if (!detection.mask) {\n return detection;\n }\n const decoded = decodeCompressedRleMask(detection.mask);\n const contour = extractMaskContour(decoded.data, decoded.width, decoded.height);\n const fallbackRect = computeDetectionMaskRect(detection.mask);\n const polygon = contour && contour.length >= 3\n ? { points: contour }\n : fallbackRect\n ? rectToPolygon(fallbackRect)\n : undefined;\n return polygon ? replaceGeometry(detection, { polygon }) : detection;\n}\nfunction convertDetectionBoxToMask(detection, dimensions) {\n if (!detection.rect) {\n return detection;\n }\n const mask = encodeBinaryMask(rasterizeRectToMask(detection.rect, dimensions), dimensions.width, dimensions.height);\n return replaceGeometry(detection, { mask });\n}\nfunction convertDetectionPolygonToMask(detection, dimensions) {\n if (!detection.polygon) {\n return detection;\n }\n const mask = encodeBinaryMask(rasterizePolygonToMask(detection.polygon.points, dimensions), dimensions.width, dimensions.height);\n return replaceGeometry(detection, { mask });\n}\nfunction mergeDetectionMasks(detections) {\n if (detections.length < 2 || detections.some(({ mask }) => !mask)) {\n return null;\n }\n const first = detections[0];\n if (detections.some((detection) => detection.className !== first.className)) {\n return null;\n }\n const masks = detections.map(({ mask }) => decodeCompressedRleMask(mask));\n const width = masks[0].width;\n const height = masks[0].height;\n if (masks.some((mask) => mask.width !== width || mask.height !== height)) {\n throw new Error(\"Merged detection masks must have matching dimensions.\");\n }\n const data = new Uint8Array(width * height);\n for (const mask of masks) {\n for (let index = 0; index < data.length; index += 1) {\n data[index] ||= mask.data[index] ?? 0;\n }\n }\n return replaceGeometry(first, {\n mask: encodeBinaryMask(data, width, height),\n });\n}\n/**\n * Groups polygon detections by class and returns one union bounding-box\n * detection per class. This intentionally converts the output to rectangles.\n */\nfunction mergeDetectionPolygonsByClass(detections, options = {}) {\n const groups = new Map();\n for (const detection of detections) {\n if (!detection.polygon) {\n continue;\n }\n const group = groups.get(detection.className) ?? [];\n group.push(detection);\n groups.set(detection.className, group);\n }\n return [...groups.entries()].flatMap(([className, group], groupIndex) => {\n const points = group.flatMap((detection) => detection.polygon.points);\n const rect = getPointsRect(points);\n if (!rect) {\n return [];\n }\n const first = group[0];\n const id = options.createId?.(className, groupIndex) ?? first.id;\n return [\n replaceGeometry({\n ...first,\n id,\n }, { rect }),\n ];\n });\n}\nfunction 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}\nfunction replaceGeometry(detection, geometry) {\n return {\n ...detection,\n keypoints: undefined,\n mask: geometry.mask,\n polygon: geometry.polygon,\n polyline: undefined,\n rect: geometry.rect,\n };\n}\n\nfunction canReuseMaskStyleArtifacts(previousMaskStyle, nextMaskStyle) {\n if (previousMaskStyle === nextMaskStyle) {\n return true;\n }\n return (previousMaskStyle?.artifactKey !== undefined &&\n nextMaskStyle?.artifactKey !== undefined &&\n previousMaskStyle.artifactKey === nextMaskStyle.artifactKey);\n}\nfunction resolveMaskStyleOpacity(maskStyle) {\n const opacity = maskStyle?.opacity;\n if (opacity === undefined) {\n return 1;\n }\n return Number.isFinite(opacity) ? Math.max(0, Math.min(opacity, 1)) : 1;\n}\n\nconst MAX_ID_MASK_PALETTE_ENTRIES = 64;\nconst MAX_ID_MASK_STROKE_WIDTH = 16;\nfunction 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}\nfunction 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\nfunction includeDefined(values) {\n return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined));\n}\n\nfunction resolveAnnotationStyleState(detection, visibility) {\n const id = detection.id;\n return {\n hidden: visibility?.annotationsHidden === true ||\n (detection.className !== undefined &&\n includes(visibility?.hiddenClasses, detection.className)) ||\n (id !== undefined && includes(visibility?.hiddenDetectionIds, id)),\n loading: id !== undefined && includes(visibility?.loadingDetectionIds, id),\n ephemeral: id !== undefined && includes(visibility?.ephemeralDetectionIds, id),\n isCreating: id !== undefined && visibility?.creatingDetectionId === id,\n };\n}\nfunction includes(values, value) {\n if (!values)\n return false;\n return Array.isArray(values)\n ? values.includes(value)\n : values.has(value);\n}\n\nvar 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 */\nvar 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 */\nvar 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 */\nvar 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 */\nvar 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 */\nvar 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 */\nvar MediaSessionActivityStatus;\n(function (MediaSessionActivityStatus) {\n MediaSessionActivityStatus[\"Error\"] = \"error\";\n MediaSessionActivityStatus[\"Running\"] = \"running\";\n MediaSessionActivityStatus[\"Waiting\"] = \"waiting\";\n})(MediaSessionActivityStatus || (MediaSessionActivityStatus = {}));\n\nexport { AnnotationFrameMutationKind, AnnotationGeometryKind, AnnotationGestureStateKind, AnnotationHandleKind, BaseBoxStyle, BaseFocusStyle, BaseInteractionStyle, BaseKeypointStyle, BaseLabelStyle, BaseMaskStyle, BasePolygonStyle, BasePolylineStyle, BoxShape, BoxStrokeAlignment, DEFAULT_DETECTION_CLASS_STYLES, DEFAULT_DETECTION_COLOR_SEQUENCE, DetectionBufferStatus, DetectionFrameRetentionMode, DetectionFrameSelectionMode, DetectionInteractionState, DetectionMaskEncoding, DetectionMaskPayloadFormat, DetectionPickTarget, FocusTargetMode, KeypointMarkerShape, KeypointVisibility, LabelPlacement, LabelVisibilityMode, MAX_ID_MASK_PALETTE_ENTRIES, MAX_ID_MASK_STROKE_WIDTH, MaskRenderMode, MediaInteractionMode, MediaRendererFit, MediaRendererPlaybackState, MediaSessionActivityKind, MediaSessionActivityStatus, MediaSessionMode, MediaSessionStatus, MediaSourceStatus, SUPERVISION_ROBOFLOW_COLOR, annotationRendererKinds, annotationRenderers, applyAnnotationHandleDrag, canReuseMaskStyleArtifacts, centerRectToTopLeftRect, computeDetectionMaskRect, computeMaskBounds, containsPoint, convertDetectionBoxToMask, convertDetectionBoxToPolygon, convertDetectionMaskToBox, convertDetectionMaskToPolygon, convertDetectionPolygonToBox, convertDetectionPolygonToMask, copySortedDetectionFrames, createAnnotationEditingEngine, createArrayDetectionFrameSource, createBufferedDetectionTimeline, createColdDetectionFrameSource, createCompositeDetectionFrameSource, createDefaultAnnotationPresentation, createDetectionPickKey, createEditableAnnotationFrameSession, createIdMaskFrame, createIdleDetectionBufferState, createMemoryColdDetectionFrameStore, createSourceAwarePresentation, createViewportController, createWritableDetectionFrameSource, decodeCompressedRleCounts, decodeCompressedRleMask, decodeDetectionMaskPayload, deleteAnnotationVertex, detectMaskBorders, detectionFrameOverlapsRange, distanceToSegment, encodeBinaryMask, encodeBinaryMaskWithBounds, encodeCompressedRleCounts, encodeDetectionMaskPayload, extractMaskContour, extractMaskRectRuns, filterDetectionFramesForRange, findClosestAnnotationSegment, getAnnotationHandles, getBufferedDetectionTimelineFrameSnapshot, getDetectionRect, getPointsRect, includeDefined, isDeflatedBase64DetectionMaskPayload, lightenColor, mediaToScreen, mergeDetectionMasks, mergeDetectionPolygonsByClass, normalizeDetectionClassName, offsetDetection, pickAnnotationHandle, pickDetectionAtPoint, pickDetectionByMaskId, pointInPolygon, polygonArea, polygonToRect, rasterizePolygonToMask, rasterizeRectToMask, rebaseDetectionPickToFrame, rectArea, rectToPolygon, resolveAnnotationRendererPresentation, resolveAnnotationStyleState, resolveContrastTextColor, resolveDetectionClassColorStyle, resolveMaskStyleOpacity, resolveStyleValue, screenToMedia, selectDetectionFrame, topLeftRectToCenterRect, validateDetectionFrames };\n//# sourceMappingURL=index.js.map\n",null,null,null,null],"names":[],"mappings":"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"}