@exige/web-scanner-sdk 0.2.30 → 0.2.31

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.
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../src/sdk/display-quad.ts","../src/react/scanner-context.ts","../src/react/context.tsx","../src/react/hooks.ts","../src/live-overlay-geometry.ts","../src/components/ModelDownloadRing.tsx","../src/react/parts.tsx"],"sourcesContent":["import type { DocumentQuad, Point } from './types'\n\nfunction points(quad: DocumentQuad) {\n return [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft]\n}\n\nfunction withPoints(next: Point[]): DocumentQuad {\n const [topLeft, topRight, bottomRight, bottomLeft] = next\n return {\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n edges: {\n top: { start: topLeft, end: topRight },\n right: { start: topRight, end: bottomRight },\n bottom: { start: bottomRight, end: bottomLeft },\n left: { start: bottomLeft, end: topLeft },\n },\n }\n}\n\nfunction cloneQuad(quad: DocumentQuad) {\n return withPoints(points(quad).map((point) => ({ ...point })))\n}\n\nexport interface QuadDisplaySmootherOptions {\n response?: number\n snapDistance?: number\n}\n\n/**\n * Smooths only the displayed quad. Detector stability must continue to use raw\n * detections and must never consume this animated output.\n */\nexport class QuadDisplaySmoother {\n private current?: DocumentQuad\n private target?: DocumentQuad\n private readonly response: number\n private readonly snapDistance: number\n\n constructor(options: QuadDisplaySmootherOptions = {}) {\n this.response = options.response ?? 14\n this.snapDistance = options.snapDistance ?? 0.1\n }\n\n setTarget(quad: DocumentQuad, frameWidth: number, frameHeight: number) {\n const diagonal = Math.max(1, Math.hypot(frameWidth, frameHeight))\n const shouldSnap = !this.current || points(quad).some((point, index) => {\n const previous = points(this.current!)[index]\n return Math.hypot(point.x - previous.x, point.y - previous.y) / diagonal > this.snapDistance\n })\n this.target = cloneQuad(quad)\n if (shouldSnap) this.current = cloneQuad(quad)\n return { quad: this.current, snapped: shouldSnap }\n }\n\n step(deltaMs: number) {\n if (!this.current || !this.target) return this.current\n const alpha = 1 - Math.exp(-this.response * Math.max(0, deltaMs) / 1000)\n this.current = withPoints(points(this.current).map((point, index) => {\n const target = points(this.target!)[index]\n return {\n x: point.x + (target.x - point.x) * alpha,\n y: point.y + (target.y - point.y) * alpha,\n }\n }))\n return this.current\n }\n\n clear() {\n this.current = undefined\n this.target = undefined\n }\n\n getCurrent() {\n return this.current\n }\n}\n","import { createContext } from 'react'\nimport type { ScannerApi, ScannerState } from './types'\n\nexport interface ScannerContextValue extends ScannerState, ScannerApi {\n bindPreview: (node: HTMLVideoElement | null) => void\n}\n\nexport const ScannerContext = createContext<ScannerContextValue | null>(null)\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport {\n formatCaptureDiagnosticsReport,\n hasTransientUserActivation,\n meanFrameLuminance,\n NEAR_BLACK_LUMINANCE,\n pickNativeCameraStill,\n shouldUseSystemCameraCapture,\n startCamera,\n type CameraDiagnostics,\n type CameraPhoto,\n type CameraSession,\n} from '../sdk/camera'\nimport {\n selectFinderHint,\n startFinder,\n type FinderSession,\n type FinderStatus,\n} from '../sdk/finder'\nimport { scanSystemCameraStill } from '../sdk/scan'\nimport {\n startDriverLicenseSession,\n type DriverLicenseSession,\n} from '../sdk/driver-license'\nimport { QuadDisplaySmoother } from '../sdk/display-quad'\nimport {\n subscribeModelDownloads,\n type ModelDownloadSnapshot,\n} from '../sdk/model-download'\nimport type { DocumentQuad } from '../sdk/types'\nimport type { ScannerApi, ScannerCapture, ScannerProviderProps, ScannerState } from './types'\nimport { ScannerContext, type ScannerContextValue } from './scanner-context'\n\nfunction revokePreviewUrl(url: string | undefined) {\n if (url?.startsWith('blob:')) URL.revokeObjectURL(url)\n}\n\nfunction stillUrlFromCanvas(canvas: HTMLCanvasElement): string | undefined {\n try {\n const url = canvas.toDataURL('image/jpeg', 0.92)\n return url.startsWith('data:image/') ? url : undefined\n } catch {\n return undefined\n }\n}\n\nfunction invokeIfFunction<T>(\n fn: ((value: T) => void | Promise<void>) | undefined,\n value: T,\n) {\n if (typeof fn === 'function') return fn(value)\n}\n\nexport function ScannerProvider({\n open,\n useCase = 'document',\n autoCapture = 'defaultOn',\n captureMode = 'auto',\n torch = 'defaultOff',\n onCapture,\n onDriverLicense,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n apiRef,\n children,\n}: ScannerProviderProps) {\n const usingSystemCamera = shouldUseSystemCameraCapture(captureMode)\n const cameraRef = useRef<CameraSession | undefined>(undefined)\n const finderRef = useRef<FinderSession | undefined>(undefined)\n const finderStatusRef = useRef<FinderStatus | undefined>(undefined)\n const latestPhotoRef = useRef<CameraPhoto | undefined>(undefined)\n const capturedDisplayRef = useRef<{\n quad?: DocumentQuad\n sourceWidth?: number\n sourceHeight?: number\n }>({})\n const displaySmootherRef = useRef(new QuadDisplaySmoother())\n const captureErrorRef = useRef(false)\n const systemCaptureInFlightRef = useRef(false)\n const callbacksRef = useRef({\n onCapture,\n onDriverLicense,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n useCase,\n })\n const licenseSessionRef = useRef<DriverLicenseSession | undefined>(undefined)\n const licenseReadyRef = useRef<Promise<DriverLicenseSession> | undefined>(undefined)\n const handleLicenseStillRef = useRef<(capture: ScannerCapture) => Promise<void>>(async () => undefined)\n const stateRef = useRef<ScannerState>(null!)\n const [preview, setPreview] = useState<HTMLVideoElement | null>(null)\n const [phase, setPhase] = useState<ScannerState['phase']>(\n usingSystemCamera && open ? 'capturing' : usingSystemCamera ? 'ready' : 'starting',\n )\n const [finderStatus, setFinderStatus] = useState<FinderStatus>()\n const [displayQuad, setDisplayQuad] = useState<DocumentQuad>()\n const [previewSize, setPreviewSize] = useState({ width: 1, height: 1 })\n const [settings, setSettings] = useState<MediaTrackSettings>()\n const [captureMethod, setCaptureMethod] = useState<CameraPhoto['method']>()\n const [error, setError] = useState('')\n const [attempt, setAttempt] = useState(0)\n const [diagnostics, setDiagnostics] = useState<CameraDiagnostics>()\n const [shutterDiagnostics, setShutterDiagnostics] = useState<CameraDiagnostics>()\n const [copyState, setCopyState] = useState<ScannerState['copyState']>('idle')\n const [frozenPreviewUrl, setFrozenPreviewUrl] = useState<string>()\n const frozenPreviewUrlRef = useRef<string | undefined>(undefined)\n const [licenseSide, setLicenseSide] = useState<'front' | 'back'>('front')\n const licenseSideRef = useRef<'front' | 'back'>('front')\n const [licenseBusy, setLicenseBusy] = useState(false)\n const [modelDownload, setModelDownload] = useState<ModelDownloadSnapshot>({\n downloading: false,\n loaded: 0,\n total: null,\n })\n\n const clearFrozenPreview = useCallback(() => {\n revokePreviewUrl(frozenPreviewUrlRef.current)\n frozenPreviewUrlRef.current = undefined\n setFrozenPreviewUrl(undefined)\n }, [])\n\n const freezePreview = useCallback((frame: HTMLCanvasElement, video?: HTMLVideoElement | null) => {\n const still = stillUrlFromCanvas(frame)\n revokePreviewUrl(frozenPreviewUrlRef.current)\n frozenPreviewUrlRef.current = still\n setFrozenPreviewUrl(still)\n video?.pause()\n }, [])\n\n useLayoutEffect(() => {\n callbacksRef.current = {\n onCapture,\n onDriverLicense,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n useCase,\n }\n }, [onCapture, onDriverLicense, onCancel, onError, onSettings, onFinderStatus, useCase])\n\n useEffect(() => subscribeModelDownloads(setModelDownload), [])\n\n useEffect(() => {\n if (!open || useCase !== 'drivers-license') {\n licenseReadyRef.current = undefined\n licenseSessionRef.current = undefined\n setLicenseSide('front')\n setLicenseBusy(false)\n return\n }\n const sessionPromise = startDriverLicenseSession({\n scan: { modelUrl, ortWasmPaths },\n })\n licenseReadyRef.current = sessionPromise\n void sessionPromise.then((session) => {\n licenseSessionRef.current = session\n })\n return () => {\n void sessionPromise.then((session) => session.cancel())\n if (licenseSessionRef.current) licenseSessionRef.current = undefined\n licenseReadyRef.current = undefined\n }\n }, [open, useCase, modelUrl, ortWasmPaths])\n\n const bindPreview = useCallback((node: HTMLVideoElement | null) => {\n setPreview(node)\n }, [])\n\n useEffect(() => {\n if (!open || !preview) return\n const updateSize = () => {\n const bounds = preview.getBoundingClientRect()\n setPreviewSize({ width: bounds.width, height: bounds.height })\n }\n updateSize()\n if (typeof ResizeObserver === 'undefined') {\n window.addEventListener('resize', updateSize)\n return () => window.removeEventListener('resize', updateSize)\n }\n const observer = new ResizeObserver(updateSize)\n observer.observe(preview)\n return () => observer.disconnect()\n }, [open, preview])\n\n useEffect(() => {\n if (!open) return\n const poll = window.setInterval(() => {\n const current = cameraRef.current?.getDiagnostics()\n if (current) setDiagnostics(current)\n }, 500)\n return () => window.clearInterval(poll)\n }, [open, attempt])\n\n useEffect(() => {\n if (!open) return\n let animationFrame = 0\n let previousTime = performance.now()\n const animate = (time: number) => {\n const next = displaySmootherRef.current.step(time - previousTime)\n previousTime = time\n if (next) setDisplayQuad(next)\n animationFrame = requestAnimationFrame(animate)\n }\n animationFrame = requestAnimationFrame(animate)\n return () => cancelAnimationFrame(animationFrame)\n }, [open])\n\n useEffect(() => {\n if (!open || usingSystemCamera) return\n if (!preview) return\n let cancelled = false\n\n const stop = () => {\n finderRef.current?.stop()\n finderRef.current = undefined\n cameraRef.current?.stop()\n cameraRef.current = undefined\n latestPhotoRef.current = undefined\n finderStatusRef.current = undefined\n capturedDisplayRef.current = {}\n clearFrozenPreview()\n }\n\n const start = async () => {\n stop()\n captureErrorRef.current = false\n setPhase('starting')\n setError('')\n setFinderStatus(undefined)\n setCaptureMethod(undefined)\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n clearFrozenPreview()\n try {\n const camera = await startCamera(preview, { torch })\n if (cancelled) {\n camera.stop()\n return\n }\n cameraRef.current = camera\n const actualSettings = camera.getSettings()\n setSettings(actualSettings)\n callbacksRef.current.onSettings?.(actualSettings)\n console.info('[ScannerProvider] camera settings', actualSettings)\n finderRef.current = await startFinder({\n source: preview,\n autoCapture,\n intervalMs: detectionIntervalMs,\n detection: {\n modelUrl,\n ortWasmPaths,\n },\n onStatus: (status) => {\n finderStatusRef.current = status\n setFinderStatus(status)\n callbacksRef.current.onFinderStatus?.(status)\n if (status.quad && status.sourceWidth && status.sourceHeight) {\n const update = displaySmootherRef.current.setTarget(\n status.quad,\n status.sourceWidth,\n status.sourceHeight,\n )\n setDisplayQuad(update.quad)\n } else {\n displaySmootherRef.current.clear()\n setDisplayQuad(undefined)\n }\n if (status.state !== 'captured' && !captureErrorRef.current) setPhase('ready')\n },\n captureFrame: async () => {\n setPhase('capturing')\n capturedDisplayRef.current = {\n quad: displaySmootherRef.current.getCurrent(),\n sourceWidth: finderStatusRef.current?.sourceWidth,\n sourceHeight: finderStatusRef.current?.sourceHeight,\n }\n const photo = await camera.capturePhoto()\n latestPhotoRef.current = photo\n setCaptureMethod(photo.method)\n setShutterDiagnostics(photo.diagnostics)\n setDiagnostics(photo.diagnostics)\n if (photo.luminance <= NEAR_BLACK_LUMINANCE) {\n throw new Error(\n `The captured frame was blank (luminance ${photo.luminance.toFixed(1)} via ${photo.method}). Keep the scanner visible while capturing and retake.`,\n )\n }\n freezePreview(photo.frame, preview)\n setPhase('captured')\n return photo.frame\n },\n onCaptureError: (captureError) => {\n captureErrorRef.current = true\n setPhase('error')\n setError(captureError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n callbacksRef.current.onError?.(captureError)\n },\n onCapture: async (capture) => {\n const photo = latestPhotoRef.current\n await new Promise((resolve) => window.setTimeout(resolve, 140))\n const nextCapture = {\n ...capture,\n method: photo?.method ?? 'video-frame',\n settings: photo?.settings ?? camera.getSettings(),\n fallbackReason: photo?.fallbackReason,\n luminance: photo?.luminance,\n diagnostics: photo?.diagnostics,\n displayedQuad: capturedDisplayRef.current.quad,\n displaySourceWidth: capturedDisplayRef.current.sourceWidth,\n displaySourceHeight: capturedDisplayRef.current.sourceHeight,\n }\n if (callbacksRef.current.useCase === 'drivers-license') {\n await handleLicenseStillRef.current(nextCapture)\n return\n }\n await invokeIfFunction(callbacksRef.current.onCapture, nextCapture)\n },\n })\n } catch (cause) {\n if (cancelled) return\n stop()\n const nextError = cause instanceof Error ? cause : new Error('Camera access failed.')\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }\n\n void start()\n return () => {\n cancelled = true\n stop()\n }\n }, [\n open,\n preview,\n usingSystemCamera,\n autoCapture,\n torch,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n attempt,\n clearFrozenPreview,\n freezePreview,\n ])\n\n const guidanceHint = finderStatus\n ? selectFinderHint(finderStatus.guidance, finderStatus.lighting)\n : undefined\n const detectorStatus = finderStatus?.modelStatus === 'failed'\n ? `ML failed${finderStatus.modelError ? `: ${finderStatus.modelError}` : ''}`\n : finderStatus?.detector === 'ml'\n ? `ML ${finderStatus.modelProvider ?? ''}`.trim()\n : 'ML loading'\n const state: ScannerState = {\n open,\n phase,\n autoCapture,\n captureMode,\n usingSystemCamera,\n finderStatus,\n displayQuad,\n previewSize,\n settings,\n captureMethod,\n error,\n diagnostics,\n shutterDiagnostics,\n copyState,\n guidanceHint,\n detectorStatus,\n modelDownload,\n frozenPreviewUrl,\n useCase,\n licenseSide: useCase === 'drivers-license' ? licenseSide : undefined,\n licenseBusy: useCase === 'drivers-license' ? licenseBusy : undefined,\n }\n useEffect(() => {\n stateRef.current = state\n })\n\n const cancel = useCallback(() => {\n callbacksRef.current.onCancel()\n }, [])\n\n const captureSystemStill = useCallback(async () => {\n if (systemCaptureInFlightRef.current) return\n systemCaptureInFlightRef.current = true\n captureErrorRef.current = false\n setError('')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n setPhase('capturing')\n try {\n const frame = await pickNativeCameraStill()\n freezePreview(frame)\n const settings = {\n width: frame.width,\n height: frame.height,\n } satisfies MediaTrackSettings\n setSettings(settings)\n callbacksRef.current.onSettings?.(settings)\n setCaptureMethod('system-camera')\n let luminance: number | undefined\n try {\n const pixels = frame.getContext('2d', { willReadFrequently: true })\n ?.getImageData(0, 0, frame.width, frame.height).data\n if (pixels) luminance = meanFrameLuminance(pixels)\n } catch {\n luminance = undefined\n }\n const detection = await scanSystemCameraStill(frame, {\n modelUrl,\n ortWasmPaths,\n })\n const licenseBack = callbacksRef.current.useCase === 'drivers-license'\n && licenseSideRef.current === 'back'\n if (!licenseBack && (detection.status !== 'success' || !detection.corners || !detection.quad)) {\n captureErrorRef.current = true\n setPhase('error')\n setError(detection.message)\n callbacksRef.current.onError?.(new Error(detection.message))\n return\n }\n capturedDisplayRef.current = {\n quad: detection.quad,\n sourceWidth: detection.sourceWidth,\n sourceHeight: detection.sourceHeight,\n }\n if (detection.quad) setDisplayQuad(detection.quad)\n setPhase('captured')\n const nextCapture = {\n frame,\n detection,\n reason: 'manual' as const,\n method: 'system-camera' as const,\n settings,\n luminance,\n displayedQuad: detection.quad,\n displaySourceWidth: detection.sourceWidth,\n displaySourceHeight: detection.sourceHeight,\n }\n if (callbacksRef.current.useCase === 'drivers-license') {\n await handleLicenseStillRef.current(nextCapture)\n return\n }\n await invokeIfFunction(callbacksRef.current.onCapture, nextCapture)\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Could not take a photo.')\n if (nextError.message === 'No photo was selected.') {\n if (frozenPreviewUrlRef.current) {\n setPhase('error')\n return\n }\n callbacksRef.current.onCancel()\n return\n }\n captureErrorRef.current = true\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n } finally {\n systemCaptureInFlightRef.current = false\n }\n }, [freezePreview, modelUrl, ortWasmPaths])\n\n const handleLicenseStill = useCallback(async (capture: ScannerCapture) => {\n const session = await licenseReadyRef.current\n if (!session) return\n setLicenseBusy(true)\n try {\n const step = await session.submitStill(capture.frame, capture.detection)\n if (step.kind === 'need-back') {\n licenseSideRef.current = 'back'\n setLicenseSide('back')\n captureErrorRef.current = false\n setError('')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n clearFrozenPreview()\n if (usingSystemCamera) {\n setPhase('ready')\n return\n }\n if (preview?.paused) void preview.play()\n setPhase('starting')\n setAttempt((value) => value + 1)\n return\n }\n if (step.kind === 'retry') {\n captureErrorRef.current = true\n setError(step.message)\n setPhase('error')\n return\n }\n await invokeIfFunction(callbacksRef.current.onDriverLicense, step.result)\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Driver’s license scan failed.')\n captureErrorRef.current = true\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n } finally {\n setLicenseBusy(false)\n }\n }, [clearFrozenPreview, preview, usingSystemCamera])\n\n useLayoutEffect(() => {\n handleLicenseStillRef.current = handleLicenseStill\n }, [handleLicenseStill])\n\n const capture = useCallback(async () => {\n if (usingSystemCamera) {\n await captureSystemStill()\n return\n }\n try {\n await finderRef.current?.capture()\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Could not capture the camera frame.')\n captureErrorRef.current = true\n setError(nextError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n if (latestPhotoRef.current?.diagnostics) setShutterDiagnostics(latestPhotoRef.current.diagnostics)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }, [captureSystemStill, usingSystemCamera])\n\n const captureSystemStillRef = useRef(captureSystemStill)\n captureSystemStillRef.current = captureSystemStill\n const openedSystemSessionRef = useRef(false)\n\n useLayoutEffect(() => {\n if (!open || !usingSystemCamera) {\n openedSystemSessionRef.current = false\n return\n }\n if (openedSystemSessionRef.current) return\n openedSystemSessionRef.current = true\n captureErrorRef.current = false\n setError('')\n setFinderStatus(undefined)\n setCaptureMethod(undefined)\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n clearFrozenPreview()\n if (!hasTransientUserActivation()) {\n setPhase('ready')\n return\n }\n void captureSystemStillRef.current()\n }, [open, usingSystemCamera, clearFrozenPreview])\n\n const retry = useCallback(() => {\n captureErrorRef.current = false\n setError('')\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n if (usingSystemCamera) {\n void captureSystemStill()\n return\n }\n clearFrozenPreview()\n if (useCase === 'drivers-license') {\n setPhase('starting')\n setAttempt((value) => value + 1)\n return\n }\n const liveCamera = cameraRef.current\n if (preview?.paused) void preview.play()\n setPhase(liveCamera ? 'ready' : 'starting')\n if (!liveCamera) setAttempt((value) => value + 1)\n }, [captureSystemStill, clearFrozenPreview, preview, useCase, usingSystemCamera])\n\n const setTorch = useCallback(async (enabled: boolean) => {\n const camera = cameraRef.current\n if (!camera) return\n await camera.setTorch(enabled)\n setDiagnostics(camera.getDiagnostics())\n }, [])\n\n const setAutoCapture = useCallback((enabled: boolean) => {\n finderRef.current?.setAutoCapture(enabled)\n }, [])\n\n const copyReport = useCallback(async () => {\n const current = stateRef.current\n const live = cameraRef.current?.getDiagnostics() ?? current.diagnostics\n const finder = current.finderStatus\n const report = formatCaptureDiagnosticsReport({\n error: current.error || undefined,\n captureMethod: current.captureMethod,\n luminance: latestPhotoRef.current?.luminance,\n fallbackReason: latestPhotoRef.current?.fallbackReason,\n shutter: current.shutterDiagnostics ?? latestPhotoRef.current?.diagnostics,\n live,\n finder: finder\n ? {\n state: finder.state,\n confidence: finder.confidence,\n stableFrames: finder.stableFrames,\n requiredStableFrames: finder.requiredStableFrames,\n detector: finder.detector,\n modelStatus: finder.modelStatus,\n modelError: finder.modelError,\n modelProvider: finder.modelProvider,\n modelNote: finder.modelNote,\n inferenceMs: finder.inferenceMs,\n sourceWidth: finder.sourceWidth,\n sourceHeight: finder.sourceHeight,\n }\n : undefined,\n })\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(report)\n } else {\n const field = document.createElement('textarea')\n field.value = report\n field.setAttribute('readonly', '')\n field.style.position = 'fixed'\n field.style.left = '-9999px'\n document.body.append(field)\n field.select()\n const copied = document.execCommand('copy')\n field.remove()\n if (!copied) throw new Error('Clipboard copy is unavailable.')\n }\n setCopyState('copied')\n } catch {\n setCopyState('failed')\n }\n }, [])\n\n const getState = useCallback(() => stateRef.current, [])\n\n const api = useMemo<ScannerApi>(() => ({\n capture,\n cancel,\n retry,\n setTorch,\n setAutoCapture,\n copyReport,\n getState,\n }), [capture, cancel, retry, setTorch, setAutoCapture, copyReport, getState])\n\n useEffect(() => {\n if (!apiRef) return\n apiRef.current = api\n return () => {\n apiRef.current = null\n }\n }, [api, apiRef])\n\n const value: ScannerContextValue = {\n ...state,\n ...api,\n bindPreview,\n }\n\n return (\n <ScannerContext.Provider value={value}>\n {children}\n </ScannerContext.Provider>\n )\n}\n","import { useContext, useRef } from 'react'\nimport type { ScannerApi } from './types'\nimport { ScannerContext } from './scanner-context'\n\nexport function useScannerRef() {\n return useRef<ScannerApi | null>(null)\n}\n\nexport function useScanner() {\n const value = useContext(ScannerContext)\n if (!value) throw new Error('useScanner must be used within ScannerProvider.')\n return value\n}\n","import type { Point } from './sdk/types'\n\nexport type LivePreviewFit = 'contain' | 'cover'\n\nexport interface LiveOverlayTransform {\n viewBox: string\n preserveAspectRatio: 'none' | 'xMidYMid meet'\n scale: number\n offsetX: number\n offsetY: number\n}\n\nexport function liveOverlayTransform(\n sourceWidth: number,\n sourceHeight: number,\n renderedWidth: number,\n renderedHeight: number,\n fit: LivePreviewFit,\n): LiveOverlayTransform {\n const safeSourceWidth = Math.max(1, sourceWidth)\n const safeSourceHeight = Math.max(1, sourceHeight)\n const safeRenderedWidth = Math.max(1, renderedWidth)\n const safeRenderedHeight = Math.max(1, renderedHeight)\n const widthScale = safeRenderedWidth / safeSourceWidth\n const heightScale = safeRenderedHeight / safeSourceHeight\n const scale = fit === 'cover'\n ? Math.max(widthScale, heightScale)\n : Math.min(widthScale, heightScale)\n const offsetX = (safeRenderedWidth - safeSourceWidth * scale) / 2\n const offsetY = (safeRenderedHeight - safeSourceHeight * scale) / 2\n if (fit === 'contain') {\n return {\n viewBox: `0 0 ${safeSourceWidth} ${safeSourceHeight}`,\n preserveAspectRatio: 'xMidYMid meet',\n scale,\n offsetX,\n offsetY,\n }\n }\n const visibleWidth = safeRenderedWidth / scale\n const visibleHeight = safeRenderedHeight / scale\n return {\n viewBox: `${-offsetX / scale} ${-offsetY / scale} ${visibleWidth} ${visibleHeight}`,\n preserveAspectRatio: 'none',\n scale,\n offsetX,\n offsetY,\n }\n}\n\nexport function mapLiveSourcePoint(point: Point, transform: LiveOverlayTransform): Point {\n return {\n x: transform.offsetX + point.x * transform.scale,\n y: transform.offsetY + point.y * transform.scale,\n }\n}\n","import type { ModelDownloadSnapshot } from '../sdk/model-download'\n\nexport function ModelDownloadRing({ snapshot }: { snapshot: ModelDownloadSnapshot }) {\n if (!snapshot.downloading) return null\n const ratio = snapshot.total && snapshot.total > 0\n ? Math.min(1, snapshot.loaded / snapshot.total)\n : null\n const percent = ratio === null ? null : Math.round(ratio * 100)\n const radius = 28\n const circumference = 2 * Math.PI * radius\n return (\n <div\n className={`model-download-ring${ratio === null ? ' is-indeterminate' : ''}`}\n role=\"progressbar\"\n aria-label=\"Model download\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent ?? undefined}\n data-loaded={snapshot.loaded}\n data-total={snapshot.total ?? ''}\n >\n <svg viewBox=\"0 0 72 72\" aria-hidden=\"true\">\n <circle className=\"track\" cx=\"36\" cy=\"36\" r={radius} />\n <circle\n className=\"value\"\n cx=\"36\"\n cy=\"36\"\n r={radius}\n strokeDasharray={ratio === null ? undefined : `${circumference} ${circumference}`}\n strokeDashoffset={ratio === null ? undefined : circumference * (1 - ratio)}\n />\n </svg>\n {percent !== null ? <strong>{percent}%</strong> : <strong className=\"model-download-ring__pending\">…</strong>}\n </div>\n )\n}\n","import { useCallback, useEffect, useRef, type CSSProperties } from 'react'\nimport { detectBrowserEngine } from '../sdk/camera'\nimport { liveOverlayTransform } from '../live-overlay-geometry'\nimport type { ModelDownloadSnapshot } from '../sdk/model-download'\nimport { ModelDownloadRing } from '../components/ModelDownloadRing'\nimport '../components/scanner-camera-overlay.css'\nimport { driverLicensePrompt } from '../sdk/driver-license'\nimport { useScanner } from './hooks'\nimport type { ScannerFrameProps, ScannerTheme } from './types'\n\nconst themeProperties = {\n primaryColorHex: '--scanner-overlay-primary',\n seekingColorHex: '--scanner-overlay-seeking',\n detectingColorHex: '--scanner-overlay-detecting',\n unstableColorHex: '--scanner-overlay-unstable',\n readyColorHex: '--scanner-overlay-ready',\n capturedColorHex: '--scanner-overlay-captured',\n} as const\n\nfunction themeVars(theme: ScannerTheme | undefined) {\n if (!theme) return undefined\n const vars: Record<string, string> = {}\n for (const [field, property] of Object.entries(themeProperties)) {\n const color = theme[field as keyof ScannerTheme]?.trim()\n if (color) vars[property] = color\n }\n return Object.keys(vars).length > 0 ? vars : undefined\n}\n\nexport function ScannerFrame({ theme, style, title, children }: ScannerFrameProps) {\n const scanner = useScanner()\n if (!scanner.open) return null\n const frameTitle = title\n ?? (scanner.useCase === 'drivers-license' ? 'Scan a driver’s license' : 'Scan a document')\n const vars = themeVars(theme)\n const frameStyle: CSSProperties | undefined = vars ? { ...style, ...vars } : style\n return (\n <div\n className={`scanner-camera-overlay ${scanner.phase === 'captured' || scanner.finderStatus?.state === 'captured' ? 'is-captured' : ''} ${scanner.usingSystemCamera ? 'is-system-camera' : ''}`.trim()}\n style={frameStyle}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={frameTitle}\n >\n {children}\n <ScannerModelDownload />\n </div>\n )\n}\n\nexport function ScannerPreview() {\n const { bindPreview, frozenPreviewUrl, usingSystemCamera } = useScanner()\n const videoRef = useRef<HTMLVideoElement | null>(null)\n const setPreviewNode = useCallback((node: HTMLVideoElement | null) => {\n videoRef.current = node\n bindPreview(node)\n }, [bindPreview])\n\n useEffect(() => {\n if (frozenPreviewUrl) videoRef.current?.pause()\n }, [frozenPreviewUrl])\n\n if (usingSystemCamera) {\n return frozenPreviewUrl ? (\n <img\n src={frozenPreviewUrl}\n className=\"scanner-camera-overlay__video scanner-camera-overlay__still\"\n alt=\"\"\n aria-label=\"Captured document\"\n />\n ) : (\n <div className=\"scanner-camera-overlay__video\" aria-hidden=\"true\" />\n )\n }\n\n return (\n <>\n <video\n ref={setPreviewNode}\n className=\"scanner-camera-overlay__video\"\n muted\n autoPlay\n playsInline\n style={{ objectFit: 'cover' }}\n aria-hidden={Boolean(frozenPreviewUrl)}\n aria-label=\"Rear camera preview\"\n />\n {frozenPreviewUrl ? (\n <img\n src={frozenPreviewUrl}\n className=\"scanner-camera-overlay__video scanner-camera-overlay__still\"\n alt=\"\"\n aria-label=\"Captured document\"\n />\n ) : null}\n </>\n )\n}\n\nexport function ScannerQuad() {\n const { finderStatus, displayQuad, previewSize } = useScanner()\n if (!displayQuad || !finderStatus?.sourceWidth || !finderStatus.sourceHeight) {\n return null\n }\n const overlayTransform = liveOverlayTransform(\n finderStatus.sourceWidth,\n finderStatus.sourceHeight,\n previewSize.width,\n previewSize.height,\n 'cover',\n )\n return (\n <svg\n className={`scanner-camera-overlay__quad ${finderStatus.state}`}\n viewBox={overlayTransform.viewBox}\n preserveAspectRatio={overlayTransform.preserveAspectRatio}\n aria-label={`${finderStatus.state} document boundary`}\n >\n <polygon points={`${displayQuad.topLeft.x},${displayQuad.topLeft.y} ${displayQuad.topRight.x},${displayQuad.topRight.y} ${displayQuad.bottomRight.x},${displayQuad.bottomRight.y} ${displayQuad.bottomLeft.x},${displayQuad.bottomLeft.y}`} />\n </svg>\n )\n}\n\nexport function ScannerTopBar({ title }: { title?: string }) {\n const {\n phase,\n guidanceHint,\n cancel,\n usingSystemCamera,\n useCase,\n licenseSide,\n licenseBusy,\n } = useScanner()\n const license = useCase === 'drivers-license'\n ? driverLicensePrompt(licenseSide ?? 'front', usingSystemCamera)\n : undefined\n const heading = title ?? license?.title ?? 'Scan a document'\n return (\n <div className=\"scanner-camera-overlay__topbar\">\n <div>\n <strong>{heading}</strong>\n <span aria-live=\"polite\">\n {licenseBusy && (licenseSide === 'back' ? 'Reading the barcode…' : 'Reading the front…')}\n {!licenseBusy && license && (\n <>\n {phase === 'error' && (licenseSide === 'back' ? 'Could not read the back' : 'Could not read the front')}\n {phase !== 'error' && license.headline}\n </>\n )}\n {!licenseBusy && !license && usingSystemCamera && (\n <>\n {phase === 'starting' && 'Preparing the system camera…'}\n {phase === 'ready' && 'Take a photo. There is no live document guide.'}\n {phase === 'capturing' && 'Looking for a document…'}\n {phase === 'captured' && 'Document captured'}\n {phase === 'error' && 'No document found'}\n </>\n )}\n {!licenseBusy && !license && !usingSystemCamera && (\n <>\n {phase === 'starting' && 'Starting rear camera…'}\n {phase === 'ready' && (guidanceHint ?? 'Place the document in the frame')}\n {phase === 'capturing' && 'Capturing full resolution…'}\n {phase === 'captured' && 'Document captured'}\n {phase === 'error' && 'Camera unavailable'}\n </>\n )}\n </span>\n </div>\n <button type=\"button\" onClick={cancel} aria-label=\"Close camera\">×</button>\n </div>\n )\n}\n\nexport function ScannerNotice() {\n const {\n phase,\n error,\n diagnostics,\n copyState,\n retry,\n copyReport,\n cancel,\n usingSystemCamera,\n frozenPreviewUrl,\n useCase,\n licenseSide,\n licenseBusy,\n } = useScanner()\n const license = useCase === 'drivers-license'\n ? driverLicensePrompt(licenseSide ?? 'front', usingSystemCamera)\n : undefined\n if (phase === 'error') {\n const title = license\n ? (licenseSide === 'back' ? 'Could not read the back' : 'Could not read the front')\n : usingSystemCamera\n ? frozenPreviewUrl ? 'No document found' : 'Could not take a photo'\n : diagnostics ? 'Capture failed' : 'Could not open the camera'\n return (\n <div className=\"scanner-camera-overlay__message\" role=\"alert\">\n <strong>{title}</strong>\n <p>{error}</p>\n <div>\n <button type=\"button\" onClick={retry}>Try again</button>\n <button type=\"button\" onClick={() => void copyReport()}>\n {copyState === 'copied' ? 'Copied' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n <button type=\"button\" onClick={cancel}>Cancel</button>\n </div>\n </div>\n )\n }\n if (licenseBusy) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>{licenseSide === 'back' ? 'Reading the barcode' : 'Reading the front'}</strong>\n <p>{licenseSide === 'back' ? 'Decoding the AAMVA PDF417 on the back.' : 'Finding the card and reading the front with OCR.'}</p>\n </div>\n )\n }\n if (usingSystemCamera && phase === 'capturing' && !frozenPreviewUrl) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>{license ? license.headline : 'Opening the system camera'}</strong>\n <p>{license ? license.detail : 'There is no live document guide. We find the page after you take the photo.'}</p>\n </div>\n )\n }\n if (usingSystemCamera && phase === 'ready' && !frozenPreviewUrl) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <strong>{license ? license.headline : 'System camera'}</strong>\n <p>{license ? license.detail : 'Tap the shutter to open the Camera app. There is no live document guide.'}</p>\n </div>\n )\n }\n if (phase === 'starting' && !usingSystemCamera) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>Requesting the highest practical resolution</strong>\n <p>Allow camera access to continue.</p>\n </div>\n )\n }\n return null\n}\n\nexport function ScannerStatus() {\n const {\n finderStatus,\n detectorStatus,\n settings,\n usingSystemCamera,\n captureMethod,\n phase,\n useCase,\n licenseSide,\n } = useScanner()\n const width = settings?.width\n const height = settings?.height\n const licenseLabel = useCase === 'drivers-license'\n ? ` · ${licenseSide === 'back' ? 'back' : 'front'}`\n : ''\n if (usingSystemCamera) {\n return (\n <div className=\"scanner-camera-overlay__status\" aria-live=\"polite\">\n <div className=\"scanner-camera-overlay__status-line\">\n <span className={phase === 'captured' ? 'ready' : phase === 'error' ? 'seeking' : 'detecting'} />\n {captureMethod === 'system-camera' ? 'system camera' : 'system camera · waiting'}\n {licenseLabel}\n {width && height ? ` · ${width}×${height}` : ''}\n </div>\n </div>\n )\n }\n return (\n <div className=\"scanner-camera-overlay__status\" aria-live=\"polite\">\n <div className=\"scanner-camera-overlay__status-line\">\n <span className={finderStatus?.state ?? 'detecting'} />\n {finderStatus?.state ?? 'detecting'}\n {licenseLabel}\n {finderStatus ? ` · ${Math.round(finderStatus.confidence * 100)}% · ${finderStatus.stableFrames}/${finderStatus.requiredStableFrames}` : ''}\n {` · ${detectorStatus}`}\n {finderStatus?.inferenceMs !== undefined ? ` · ${Math.round(finderStatus.inferenceMs)}ms` : ''}\n {width && height ? ` · ${width}×${height}` : ''}\n </div>\n </div>\n )\n}\n\nexport function ScannerDiagnostics() {\n const {\n diagnostics,\n shutterDiagnostics,\n captureMethod,\n copyState,\n copyReport,\n } = useScanner()\n const engine = diagnostics?.engine ?? detectBrowserEngine()\n return (\n <dl className=\"scanner-camera-overlay__diagnostics\" aria-label=\"Camera diagnostics\">\n <div>\n <dt>engine</dt>\n <dd>{engine.engine}/{engine.browser}{engine.iosWebKit ? ' ios' : ''}</dd>\n </div>\n <div>\n <dt>video</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.videoWidth}×${diagnostics.videoHeight} rs${diagnostics.readyState}${diagnostics.paused ? ' paused' : ''}${diagnostics.rendered ? '' : ' hidden'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>track</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.trackReadyState}${diagnostics.trackMuted ? ' muted' : ''}${diagnostics.trackEnabled ? '' : ' disabled'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>torch</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.torch.mode} · ${diagnostics.torch.supported ? (diagnostics.torch.on ? 'on' : 'off') : 'unsupported'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>luma</dt>\n <dd>\n {diagnostics\n ? `live ${diagnostics.liveLuminance.toFixed(1)} · mirror ${diagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(diagnostics.mirrorAgeMs) ? ` (${Math.round(diagnostics.mirrorAgeMs)}ms)` : ' (none)'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>path</dt>\n <dd>{captureMethod ?? 'video-frame / live-mirror'}</dd>\n </div>\n {shutterDiagnostics ? (\n <div>\n <dt>shutter</dt>\n <dd>\n {`live ${shutterDiagnostics.liveLuminance.toFixed(1)} · mirror ${shutterDiagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(shutterDiagnostics.mirrorAgeMs) ? ` (${Math.round(shutterDiagnostics.mirrorAgeMs)}ms)` : ' (none)'}`}\n </dd>\n </div>\n ) : null}\n <div>\n <dt>share</dt>\n <dd>\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__copy\"\n onClick={() => void copyReport()}\n >\n {copyState === 'copied' ? 'Copied report' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n </dd>\n </div>\n </dl>\n )\n}\n\nexport function ScannerControls() {\n const {\n autoCapture,\n phase,\n finderStatus,\n diagnostics,\n captureMethod,\n settings,\n cancel,\n capture,\n setAutoCapture,\n setTorch,\n usingSystemCamera,\n licenseBusy,\n } = useScanner()\n const width = settings?.width\n const height = settings?.height\n const showShutter = usingSystemCamera\n ? phase === 'ready'\n : autoCapture !== 'only'\n return (\n <div className=\"scanner-camera-overlay__controls\">\n <button type=\"button\" className=\"scanner-camera-overlay__cancel\" onClick={cancel}>Cancel</button>\n <div className=\"scanner-camera-overlay__capture\">\n {showShutter && (\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__shutter\"\n onClick={() => void capture()}\n disabled={phase !== 'ready' || Boolean(licenseBusy)}\n aria-label={usingSystemCamera ? 'Take a photo with the system camera' : 'Capture full-resolution photo'}\n >\n <span />\n </button>\n )}\n {!usingSystemCamera && (\n <div className=\"scanner-camera-overlay__toggles\">\n {finderStatus?.autoCapture.visible && (\n <label>\n <input\n type=\"checkbox\"\n checked={finderStatus.autoCapture.checked}\n onChange={(event) => setAutoCapture(event.target.checked)}\n />\n Auto-capture\n </label>\n )}\n {diagnostics?.torch.visible && (\n <label title={diagnostics.torch.automatic ? 'Torch is controlled automatically from scene brightness' : undefined}>\n <input\n type=\"checkbox\"\n checked={diagnostics.torch.on}\n disabled={!diagnostics.torch.mutable}\n onChange={(event) => void setTorch(event.target.checked)}\n />\n {diagnostics.torch.automatic ? 'Auto torch' : 'Torch'}\n </label>\n )}\n </div>\n )}\n </div>\n <div className=\"scanner-camera-overlay__quality\">\n <span>{usingSystemCamera ? 'System camera' : captureMethod === 'live-mirror' ? 'Mirror' : 'Camera'}</span>\n <strong>{width && height ? `${width} × ${height}` : usingSystemCamera ? 'Tap to photograph' : 'Measuring…'}</strong>\n </div>\n </div>\n )\n}\n\nexport function ScannerModelDownload({ snapshot }: { snapshot?: ModelDownloadSnapshot }) {\n const { modelDownload } = useScanner()\n return <ModelDownloadRing snapshot={snapshot ?? modelDownload} />\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/sdk/display-quad.ts","../src/react/scanner-context.ts","../src/react/context.tsx","../src/react/hooks.ts","../src/live-overlay-geometry.ts","../src/components/ModelDownloadRing.tsx","../src/react/guidance.ts","../src/react/parts.tsx"],"sourcesContent":["import type { DocumentQuad, Point } from './types'\n\nfunction points(quad: DocumentQuad) {\n return [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft]\n}\n\nfunction withPoints(next: Point[]): DocumentQuad {\n const [topLeft, topRight, bottomRight, bottomLeft] = next\n return {\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n edges: {\n top: { start: topLeft, end: topRight },\n right: { start: topRight, end: bottomRight },\n bottom: { start: bottomRight, end: bottomLeft },\n left: { start: bottomLeft, end: topLeft },\n },\n }\n}\n\nfunction cloneQuad(quad: DocumentQuad) {\n return withPoints(points(quad).map((point) => ({ ...point })))\n}\n\nexport interface QuadDisplaySmootherOptions {\n response?: number\n snapDistance?: number\n}\n\n/**\n * Smooths only the displayed quad. Detector stability must continue to use raw\n * detections and must never consume this animated output.\n */\nexport class QuadDisplaySmoother {\n private current?: DocumentQuad\n private target?: DocumentQuad\n private readonly response: number\n private readonly snapDistance: number\n\n constructor(options: QuadDisplaySmootherOptions = {}) {\n this.response = options.response ?? 14\n this.snapDistance = options.snapDistance ?? 0.1\n }\n\n setTarget(quad: DocumentQuad, frameWidth: number, frameHeight: number) {\n const diagonal = Math.max(1, Math.hypot(frameWidth, frameHeight))\n const shouldSnap = !this.current || points(quad).some((point, index) => {\n const previous = points(this.current!)[index]\n return Math.hypot(point.x - previous.x, point.y - previous.y) / diagonal > this.snapDistance\n })\n this.target = cloneQuad(quad)\n if (shouldSnap) this.current = cloneQuad(quad)\n return { quad: this.current, snapped: shouldSnap }\n }\n\n step(deltaMs: number) {\n if (!this.current || !this.target) return this.current\n const alpha = 1 - Math.exp(-this.response * Math.max(0, deltaMs) / 1000)\n this.current = withPoints(points(this.current).map((point, index) => {\n const target = points(this.target!)[index]\n return {\n x: point.x + (target.x - point.x) * alpha,\n y: point.y + (target.y - point.y) * alpha,\n }\n }))\n return this.current\n }\n\n clear() {\n this.current = undefined\n this.target = undefined\n }\n\n getCurrent() {\n return this.current\n }\n}\n","import { createContext } from 'react'\nimport type { ScannerApi, ScannerState } from './types'\n\nexport interface ScannerContextValue extends ScannerState, ScannerApi {\n bindPreview: (node: HTMLVideoElement | null) => void\n}\n\nexport const ScannerContext = createContext<ScannerContextValue | null>(null)\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport {\n formatCaptureDiagnosticsReport,\n hasTransientUserActivation,\n meanFrameLuminance,\n NEAR_BLACK_LUMINANCE,\n pickNativeCameraStill,\n shouldUseSystemCameraCapture,\n startCamera,\n type CameraDiagnostics,\n type CameraPhoto,\n type CameraSession,\n} from '../sdk/camera'\nimport {\n selectFinderHint,\n startFinder,\n type FinderSession,\n type FinderStatus,\n} from '../sdk/finder'\nimport { scanSystemCameraStill } from '../sdk/scan'\nimport {\n startDriverLicenseSession,\n type DriverLicenseSession,\n} from '../sdk/driver-license'\nimport { QuadDisplaySmoother } from '../sdk/display-quad'\nimport {\n subscribeModelDownloads,\n type ModelDownloadSnapshot,\n} from '../sdk/model-download'\nimport type { DocumentQuad } from '../sdk/types'\nimport type { ScannerApi, ScannerCapture, ScannerProviderProps, ScannerState } from './types'\nimport { ScannerContext, type ScannerContextValue } from './scanner-context'\n\nfunction revokePreviewUrl(url: string | undefined) {\n if (url?.startsWith('blob:')) URL.revokeObjectURL(url)\n}\n\nfunction stillUrlFromCanvas(canvas: HTMLCanvasElement): string | undefined {\n try {\n const url = canvas.toDataURL('image/jpeg', 0.92)\n return url.startsWith('data:image/') ? url : undefined\n } catch {\n return undefined\n }\n}\n\nfunction invokeIfFunction<T>(\n fn: ((value: T) => void | Promise<void>) | undefined,\n value: T,\n) {\n if (typeof fn === 'function') return fn(value)\n}\n\nexport function ScannerProvider({\n open,\n useCase = 'document',\n autoCapture = 'defaultOn',\n captureMode = 'auto',\n torch = 'defaultOff',\n onCapture,\n onDriverLicense,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n apiRef,\n children,\n}: ScannerProviderProps) {\n const usingSystemCamera = shouldUseSystemCameraCapture(captureMode)\n const cameraRef = useRef<CameraSession | undefined>(undefined)\n const finderRef = useRef<FinderSession | undefined>(undefined)\n const finderStatusRef = useRef<FinderStatus | undefined>(undefined)\n const latestPhotoRef = useRef<CameraPhoto | undefined>(undefined)\n const capturedDisplayRef = useRef<{\n quad?: DocumentQuad\n sourceWidth?: number\n sourceHeight?: number\n }>({})\n const displaySmootherRef = useRef(new QuadDisplaySmoother())\n const captureErrorRef = useRef(false)\n const systemCaptureInFlightRef = useRef(false)\n const callbacksRef = useRef({\n onCapture,\n onDriverLicense,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n useCase,\n })\n const licenseSessionRef = useRef<DriverLicenseSession | undefined>(undefined)\n const licenseReadyRef = useRef<Promise<DriverLicenseSession> | undefined>(undefined)\n const handleLicenseStillRef = useRef<(capture: ScannerCapture) => Promise<void>>(async () => undefined)\n const stateRef = useRef<ScannerState>(null!)\n const [preview, setPreview] = useState<HTMLVideoElement | null>(null)\n const [phase, setPhase] = useState<ScannerState['phase']>(\n usingSystemCamera && open ? 'capturing' : usingSystemCamera ? 'ready' : 'starting',\n )\n const [finderStatus, setFinderStatus] = useState<FinderStatus>()\n const [displayQuad, setDisplayQuad] = useState<DocumentQuad>()\n const [previewSize, setPreviewSize] = useState({ width: 1, height: 1 })\n const [settings, setSettings] = useState<MediaTrackSettings>()\n const [captureMethod, setCaptureMethod] = useState<CameraPhoto['method']>()\n const [error, setError] = useState('')\n const [attempt, setAttempt] = useState(0)\n const [diagnostics, setDiagnostics] = useState<CameraDiagnostics>()\n const [shutterDiagnostics, setShutterDiagnostics] = useState<CameraDiagnostics>()\n const [copyState, setCopyState] = useState<ScannerState['copyState']>('idle')\n const [frozenPreviewUrl, setFrozenPreviewUrl] = useState<string>()\n const frozenPreviewUrlRef = useRef<string | undefined>(undefined)\n const [licenseSide, setLicenseSide] = useState<'front' | 'back'>('front')\n const licenseSideRef = useRef<'front' | 'back'>('front')\n const [licenseBusy, setLicenseBusy] = useState(false)\n const [modelDownload, setModelDownload] = useState<ModelDownloadSnapshot>({\n downloading: false,\n loaded: 0,\n total: null,\n })\n\n const clearFrozenPreview = useCallback(() => {\n revokePreviewUrl(frozenPreviewUrlRef.current)\n frozenPreviewUrlRef.current = undefined\n setFrozenPreviewUrl(undefined)\n }, [])\n\n const freezePreview = useCallback((frame: HTMLCanvasElement, video?: HTMLVideoElement | null) => {\n const still = stillUrlFromCanvas(frame)\n revokePreviewUrl(frozenPreviewUrlRef.current)\n frozenPreviewUrlRef.current = still\n setFrozenPreviewUrl(still)\n video?.pause()\n }, [])\n\n useLayoutEffect(() => {\n callbacksRef.current = {\n onCapture,\n onDriverLicense,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n useCase,\n }\n }, [onCapture, onDriverLicense, onCancel, onError, onSettings, onFinderStatus, useCase])\n\n useEffect(() => subscribeModelDownloads(setModelDownload), [])\n\n useEffect(() => {\n if (!open || useCase !== 'drivers-license') {\n licenseReadyRef.current = undefined\n licenseSessionRef.current = undefined\n setLicenseSide('front')\n setLicenseBusy(false)\n return\n }\n const sessionPromise = startDriverLicenseSession({\n scan: { modelUrl, ortWasmPaths },\n })\n licenseReadyRef.current = sessionPromise\n void sessionPromise.then((session) => {\n licenseSessionRef.current = session\n })\n return () => {\n void sessionPromise.then((session) => session.cancel())\n if (licenseSessionRef.current) licenseSessionRef.current = undefined\n licenseReadyRef.current = undefined\n }\n }, [open, useCase, modelUrl, ortWasmPaths])\n\n const bindPreview = useCallback((node: HTMLVideoElement | null) => {\n setPreview(node)\n }, [])\n\n useEffect(() => {\n if (!open || !preview) return\n const updateSize = () => {\n const bounds = preview.getBoundingClientRect()\n setPreviewSize({ width: bounds.width, height: bounds.height })\n }\n updateSize()\n if (typeof ResizeObserver === 'undefined') {\n window.addEventListener('resize', updateSize)\n return () => window.removeEventListener('resize', updateSize)\n }\n const observer = new ResizeObserver(updateSize)\n observer.observe(preview)\n return () => observer.disconnect()\n }, [open, preview])\n\n useEffect(() => {\n if (!open) return\n const poll = window.setInterval(() => {\n const current = cameraRef.current?.getDiagnostics()\n if (current) setDiagnostics(current)\n }, 500)\n return () => window.clearInterval(poll)\n }, [open, attempt])\n\n useEffect(() => {\n if (!open) return\n let animationFrame = 0\n let previousTime = performance.now()\n const animate = (time: number) => {\n const next = displaySmootherRef.current.step(time - previousTime)\n previousTime = time\n if (next) setDisplayQuad(next)\n animationFrame = requestAnimationFrame(animate)\n }\n animationFrame = requestAnimationFrame(animate)\n return () => cancelAnimationFrame(animationFrame)\n }, [open])\n\n useEffect(() => {\n if (!open || usingSystemCamera) return\n if (!preview) return\n let cancelled = false\n\n const stop = () => {\n finderRef.current?.stop()\n finderRef.current = undefined\n cameraRef.current?.stop()\n cameraRef.current = undefined\n latestPhotoRef.current = undefined\n finderStatusRef.current = undefined\n capturedDisplayRef.current = {}\n clearFrozenPreview()\n }\n\n const start = async () => {\n stop()\n captureErrorRef.current = false\n setPhase('starting')\n setError('')\n setFinderStatus(undefined)\n setCaptureMethod(undefined)\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n clearFrozenPreview()\n try {\n const camera = await startCamera(preview, { torch })\n if (cancelled) {\n camera.stop()\n return\n }\n cameraRef.current = camera\n const actualSettings = camera.getSettings()\n setSettings(actualSettings)\n callbacksRef.current.onSettings?.(actualSettings)\n console.info('[ScannerProvider] camera settings', actualSettings)\n finderRef.current = await startFinder({\n source: preview,\n autoCapture,\n intervalMs: detectionIntervalMs,\n detection: {\n modelUrl,\n ortWasmPaths,\n },\n onStatus: (status) => {\n finderStatusRef.current = status\n setFinderStatus(status)\n callbacksRef.current.onFinderStatus?.(status)\n if (status.quad && status.sourceWidth && status.sourceHeight) {\n const update = displaySmootherRef.current.setTarget(\n status.quad,\n status.sourceWidth,\n status.sourceHeight,\n )\n setDisplayQuad(update.quad)\n } else {\n displaySmootherRef.current.clear()\n setDisplayQuad(undefined)\n }\n if (status.state !== 'captured' && !captureErrorRef.current) setPhase('ready')\n },\n captureFrame: async () => {\n setPhase('capturing')\n capturedDisplayRef.current = {\n quad: displaySmootherRef.current.getCurrent(),\n sourceWidth: finderStatusRef.current?.sourceWidth,\n sourceHeight: finderStatusRef.current?.sourceHeight,\n }\n const photo = await camera.capturePhoto()\n latestPhotoRef.current = photo\n setCaptureMethod(photo.method)\n setShutterDiagnostics(photo.diagnostics)\n setDiagnostics(photo.diagnostics)\n if (photo.luminance <= NEAR_BLACK_LUMINANCE) {\n throw new Error(\n `The captured frame was blank (luminance ${photo.luminance.toFixed(1)} via ${photo.method}). Keep the scanner visible while capturing and retake.`,\n )\n }\n freezePreview(photo.frame, preview)\n setPhase('captured')\n return photo.frame\n },\n onCaptureError: (captureError) => {\n captureErrorRef.current = true\n setPhase('error')\n setError(captureError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n callbacksRef.current.onError?.(captureError)\n },\n onCapture: async (capture) => {\n const photo = latestPhotoRef.current\n await new Promise((resolve) => window.setTimeout(resolve, 140))\n const nextCapture = {\n ...capture,\n method: photo?.method ?? 'video-frame',\n settings: photo?.settings ?? camera.getSettings(),\n fallbackReason: photo?.fallbackReason,\n luminance: photo?.luminance,\n diagnostics: photo?.diagnostics,\n displayedQuad: capturedDisplayRef.current.quad,\n displaySourceWidth: capturedDisplayRef.current.sourceWidth,\n displaySourceHeight: capturedDisplayRef.current.sourceHeight,\n }\n if (callbacksRef.current.useCase === 'drivers-license') {\n await handleLicenseStillRef.current(nextCapture)\n return\n }\n await invokeIfFunction(callbacksRef.current.onCapture, nextCapture)\n },\n })\n } catch (cause) {\n if (cancelled) return\n stop()\n const nextError = cause instanceof Error ? cause : new Error('Camera access failed.')\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }\n\n void start()\n return () => {\n cancelled = true\n stop()\n }\n }, [\n open,\n preview,\n usingSystemCamera,\n autoCapture,\n torch,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n attempt,\n clearFrozenPreview,\n freezePreview,\n ])\n\n const guidanceHint = finderStatus\n ? selectFinderHint(finderStatus.guidance, finderStatus.lighting)\n : undefined\n const detectorStatus = finderStatus?.modelStatus === 'failed'\n ? `ML failed${finderStatus.modelError ? `: ${finderStatus.modelError}` : ''}`\n : finderStatus?.detector === 'ml'\n ? `ML ${finderStatus.modelProvider ?? ''}`.trim()\n : 'ML loading'\n const state: ScannerState = {\n open,\n phase,\n autoCapture,\n captureMode,\n usingSystemCamera,\n finderStatus,\n displayQuad,\n previewSize,\n settings,\n captureMethod,\n error,\n diagnostics,\n shutterDiagnostics,\n copyState,\n guidanceHint,\n detectorStatus,\n modelDownload,\n frozenPreviewUrl,\n useCase,\n licenseSide: useCase === 'drivers-license' ? licenseSide : undefined,\n licenseBusy: useCase === 'drivers-license' ? licenseBusy : undefined,\n }\n useEffect(() => {\n stateRef.current = state\n })\n\n const cancel = useCallback(() => {\n callbacksRef.current.onCancel()\n }, [])\n\n const captureSystemStill = useCallback(async () => {\n if (systemCaptureInFlightRef.current) return\n systemCaptureInFlightRef.current = true\n captureErrorRef.current = false\n setError('')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n setPhase('capturing')\n try {\n const frame = await pickNativeCameraStill()\n freezePreview(frame)\n const settings = {\n width: frame.width,\n height: frame.height,\n } satisfies MediaTrackSettings\n setSettings(settings)\n callbacksRef.current.onSettings?.(settings)\n setCaptureMethod('system-camera')\n let luminance: number | undefined\n try {\n const pixels = frame.getContext('2d', { willReadFrequently: true })\n ?.getImageData(0, 0, frame.width, frame.height).data\n if (pixels) luminance = meanFrameLuminance(pixels)\n } catch {\n luminance = undefined\n }\n const detection = await scanSystemCameraStill(frame, {\n modelUrl,\n ortWasmPaths,\n })\n const licenseBack = callbacksRef.current.useCase === 'drivers-license'\n && licenseSideRef.current === 'back'\n if (!licenseBack && (detection.status !== 'success' || !detection.corners || !detection.quad)) {\n captureErrorRef.current = true\n setPhase('error')\n setError(detection.message)\n callbacksRef.current.onError?.(new Error(detection.message))\n return\n }\n capturedDisplayRef.current = {\n quad: detection.quad,\n sourceWidth: detection.sourceWidth,\n sourceHeight: detection.sourceHeight,\n }\n if (detection.quad) setDisplayQuad(detection.quad)\n setPhase('captured')\n const nextCapture = {\n frame,\n detection,\n reason: 'manual' as const,\n method: 'system-camera' as const,\n settings,\n luminance,\n displayedQuad: detection.quad,\n displaySourceWidth: detection.sourceWidth,\n displaySourceHeight: detection.sourceHeight,\n }\n if (callbacksRef.current.useCase === 'drivers-license') {\n await handleLicenseStillRef.current(nextCapture)\n return\n }\n await invokeIfFunction(callbacksRef.current.onCapture, nextCapture)\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Could not take a photo.')\n if (nextError.message === 'No photo was selected.') {\n if (frozenPreviewUrlRef.current) {\n setPhase('error')\n return\n }\n callbacksRef.current.onCancel()\n return\n }\n captureErrorRef.current = true\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n } finally {\n systemCaptureInFlightRef.current = false\n }\n }, [freezePreview, modelUrl, ortWasmPaths])\n\n const handleLicenseStill = useCallback(async (capture: ScannerCapture) => {\n const session = await licenseReadyRef.current\n if (!session) return\n setLicenseBusy(true)\n try {\n const step = await session.submitStill(capture.frame, capture.detection)\n if (step.kind === 'need-back') {\n licenseSideRef.current = 'back'\n setLicenseSide('back')\n captureErrorRef.current = false\n setError('')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n clearFrozenPreview()\n if (usingSystemCamera) {\n setPhase('ready')\n return\n }\n if (preview?.paused) void preview.play()\n setPhase('starting')\n setAttempt((value) => value + 1)\n return\n }\n if (step.kind === 'retry') {\n captureErrorRef.current = true\n setError(step.message)\n setPhase('error')\n return\n }\n await invokeIfFunction(callbacksRef.current.onDriverLicense, step.result)\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Driver’s license scan failed.')\n captureErrorRef.current = true\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n } finally {\n setLicenseBusy(false)\n }\n }, [clearFrozenPreview, preview, usingSystemCamera])\n\n useLayoutEffect(() => {\n handleLicenseStillRef.current = handleLicenseStill\n }, [handleLicenseStill])\n\n const capture = useCallback(async () => {\n if (usingSystemCamera) {\n await captureSystemStill()\n return\n }\n try {\n await finderRef.current?.capture()\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Could not capture the camera frame.')\n captureErrorRef.current = true\n setError(nextError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n if (latestPhotoRef.current?.diagnostics) setShutterDiagnostics(latestPhotoRef.current.diagnostics)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }, [captureSystemStill, usingSystemCamera])\n\n const captureSystemStillRef = useRef(captureSystemStill)\n captureSystemStillRef.current = captureSystemStill\n const openedSystemSessionRef = useRef(false)\n\n useLayoutEffect(() => {\n if (!open || !usingSystemCamera) {\n openedSystemSessionRef.current = false\n return\n }\n if (openedSystemSessionRef.current) return\n openedSystemSessionRef.current = true\n captureErrorRef.current = false\n setError('')\n setFinderStatus(undefined)\n setCaptureMethod(undefined)\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n clearFrozenPreview()\n if (!hasTransientUserActivation()) {\n setPhase('ready')\n return\n }\n void captureSystemStillRef.current()\n }, [open, usingSystemCamera, clearFrozenPreview])\n\n const retry = useCallback(() => {\n captureErrorRef.current = false\n setError('')\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n setDisplayQuad(undefined)\n displaySmootherRef.current.clear()\n if (usingSystemCamera) {\n void captureSystemStill()\n return\n }\n clearFrozenPreview()\n if (useCase === 'drivers-license') {\n setPhase('starting')\n setAttempt((value) => value + 1)\n return\n }\n const liveCamera = cameraRef.current\n if (preview?.paused) void preview.play()\n setPhase(liveCamera ? 'ready' : 'starting')\n if (!liveCamera) setAttempt((value) => value + 1)\n }, [captureSystemStill, clearFrozenPreview, preview, useCase, usingSystemCamera])\n\n const setTorch = useCallback(async (enabled: boolean) => {\n const camera = cameraRef.current\n if (!camera) return\n await camera.setTorch(enabled)\n setDiagnostics(camera.getDiagnostics())\n }, [])\n\n const setAutoCapture = useCallback((enabled: boolean) => {\n finderRef.current?.setAutoCapture(enabled)\n }, [])\n\n const copyReport = useCallback(async () => {\n const current = stateRef.current\n const live = cameraRef.current?.getDiagnostics() ?? current.diagnostics\n const finder = current.finderStatus\n const report = formatCaptureDiagnosticsReport({\n error: current.error || undefined,\n captureMethod: current.captureMethod,\n luminance: latestPhotoRef.current?.luminance,\n fallbackReason: latestPhotoRef.current?.fallbackReason,\n shutter: current.shutterDiagnostics ?? latestPhotoRef.current?.diagnostics,\n live,\n finder: finder\n ? {\n state: finder.state,\n confidence: finder.confidence,\n stableFrames: finder.stableFrames,\n requiredStableFrames: finder.requiredStableFrames,\n detector: finder.detector,\n modelStatus: finder.modelStatus,\n modelError: finder.modelError,\n modelProvider: finder.modelProvider,\n modelNote: finder.modelNote,\n inferenceMs: finder.inferenceMs,\n sourceWidth: finder.sourceWidth,\n sourceHeight: finder.sourceHeight,\n }\n : undefined,\n })\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(report)\n } else {\n const field = document.createElement('textarea')\n field.value = report\n field.setAttribute('readonly', '')\n field.style.position = 'fixed'\n field.style.left = '-9999px'\n document.body.append(field)\n field.select()\n const copied = document.execCommand('copy')\n field.remove()\n if (!copied) throw new Error('Clipboard copy is unavailable.')\n }\n setCopyState('copied')\n } catch {\n setCopyState('failed')\n }\n }, [])\n\n const getState = useCallback(() => stateRef.current, [])\n\n const api = useMemo<ScannerApi>(() => ({\n capture,\n cancel,\n retry,\n setTorch,\n setAutoCapture,\n copyReport,\n getState,\n }), [capture, cancel, retry, setTorch, setAutoCapture, copyReport, getState])\n\n useEffect(() => {\n if (!apiRef) return\n apiRef.current = api\n return () => {\n apiRef.current = null\n }\n }, [api, apiRef])\n\n const value: ScannerContextValue = {\n ...state,\n ...api,\n bindPreview,\n }\n\n return (\n <ScannerContext.Provider value={value}>\n {children}\n </ScannerContext.Provider>\n )\n}\n","import { useContext, useRef } from 'react'\nimport type { ScannerApi } from './types'\nimport { ScannerContext } from './scanner-context'\n\nexport function useScannerRef() {\n return useRef<ScannerApi | null>(null)\n}\n\nexport function useScanner() {\n const value = useContext(ScannerContext)\n if (!value) throw new Error('useScanner must be used within ScannerProvider.')\n return value\n}\n","import type { Point } from './sdk/types'\n\nexport type LivePreviewFit = 'contain' | 'cover'\n\nexport interface LiveOverlayTransform {\n viewBox: string\n preserveAspectRatio: 'none' | 'xMidYMid meet'\n scale: number\n offsetX: number\n offsetY: number\n}\n\nexport function liveOverlayTransform(\n sourceWidth: number,\n sourceHeight: number,\n renderedWidth: number,\n renderedHeight: number,\n fit: LivePreviewFit,\n): LiveOverlayTransform {\n const safeSourceWidth = Math.max(1, sourceWidth)\n const safeSourceHeight = Math.max(1, sourceHeight)\n const safeRenderedWidth = Math.max(1, renderedWidth)\n const safeRenderedHeight = Math.max(1, renderedHeight)\n const widthScale = safeRenderedWidth / safeSourceWidth\n const heightScale = safeRenderedHeight / safeSourceHeight\n const scale = fit === 'cover'\n ? Math.max(widthScale, heightScale)\n : Math.min(widthScale, heightScale)\n const offsetX = (safeRenderedWidth - safeSourceWidth * scale) / 2\n const offsetY = (safeRenderedHeight - safeSourceHeight * scale) / 2\n if (fit === 'contain') {\n return {\n viewBox: `0 0 ${safeSourceWidth} ${safeSourceHeight}`,\n preserveAspectRatio: 'xMidYMid meet',\n scale,\n offsetX,\n offsetY,\n }\n }\n const visibleWidth = safeRenderedWidth / scale\n const visibleHeight = safeRenderedHeight / scale\n return {\n viewBox: `${-offsetX / scale} ${-offsetY / scale} ${visibleWidth} ${visibleHeight}`,\n preserveAspectRatio: 'none',\n scale,\n offsetX,\n offsetY,\n }\n}\n\nexport function mapLiveSourcePoint(point: Point, transform: LiveOverlayTransform): Point {\n return {\n x: transform.offsetX + point.x * transform.scale,\n y: transform.offsetY + point.y * transform.scale,\n }\n}\n","import type { ModelDownloadSnapshot } from '../sdk/model-download'\n\nexport function ModelDownloadRing({ snapshot }: { snapshot: ModelDownloadSnapshot }) {\n if (!snapshot.downloading) return null\n const ratio = snapshot.total && snapshot.total > 0\n ? Math.min(1, snapshot.loaded / snapshot.total)\n : null\n const percent = ratio === null ? null : Math.round(ratio * 100)\n const radius = 28\n const circumference = 2 * Math.PI * radius\n return (\n <div\n className={`model-download-ring${ratio === null ? ' is-indeterminate' : ''}`}\n role=\"progressbar\"\n aria-label=\"Model download\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent ?? undefined}\n data-loaded={snapshot.loaded}\n data-total={snapshot.total ?? ''}\n >\n <svg viewBox=\"0 0 72 72\" aria-hidden=\"true\">\n <circle className=\"track\" cx=\"36\" cy=\"36\" r={radius} />\n <circle\n className=\"value\"\n cx=\"36\"\n cy=\"36\"\n r={radius}\n strokeDasharray={ratio === null ? undefined : `${circumference} ${circumference}`}\n strokeDashoffset={ratio === null ? undefined : circumference * (1 - ratio)}\n />\n </svg>\n {percent !== null ? <strong>{percent}%</strong> : <strong className=\"model-download-ring__pending\">…</strong>}\n </div>\n )\n}\n","import { holdStillCountdownLabel, type FinderGuidanceReason } from '../sdk/finder'\nimport type { ScannerPhase } from './types'\n\nexport function overlayGuidanceText(input: {\n usingSystemCamera: boolean\n phase: ScannerPhase\n licenseBusy?: boolean\n holdStillSeconds?: number\n guidanceHint?: string\n guidanceReason?: FinderGuidanceReason\n licenseHeadline?: string\n}) {\n if (input.usingSystemCamera || input.licenseBusy) return undefined\n if (input.phase === 'starting' || input.phase === 'error') return undefined\n if (input.phase === 'capturing') return 'Capturing full resolution…'\n if (input.phase === 'captured') return 'Document captured'\n if (input.holdStillSeconds && input.holdStillSeconds > 0) {\n return holdStillCountdownLabel(input.holdStillSeconds)\n }\n if (input.guidanceHint && input.guidanceReason && input.guidanceReason !== 'place-document') {\n return input.guidanceHint\n }\n return input.licenseHeadline ?? input.guidanceHint ?? 'Place the document in the frame'\n}\n","import { useCallback, useEffect, useRef, type CSSProperties } from 'react'\nimport { detectBrowserEngine } from '../sdk/camera'\nimport { liveOverlayTransform } from '../live-overlay-geometry'\nimport type { ModelDownloadSnapshot } from '../sdk/model-download'\nimport { ModelDownloadRing } from '../components/ModelDownloadRing'\nimport '../components/scanner-camera-overlay.css'\nimport { driverLicensePrompt } from '../sdk/driver-license'\nimport { overlayGuidanceText } from './guidance'\nimport { useScanner } from './hooks'\nimport type { ScannerFrameProps, ScannerTheme } from './types'\n\nconst themeProperties = {\n primaryColorHex: '--scanner-overlay-primary',\n seekingColorHex: '--scanner-overlay-seeking',\n detectingColorHex: '--scanner-overlay-detecting',\n unstableColorHex: '--scanner-overlay-unstable',\n readyColorHex: '--scanner-overlay-ready',\n capturedColorHex: '--scanner-overlay-captured',\n} as const\n\nfunction themeVars(theme: ScannerTheme | undefined) {\n if (!theme) return undefined\n const vars: Record<string, string> = {}\n for (const [field, property] of Object.entries(themeProperties)) {\n const color = theme[field as keyof ScannerTheme]?.trim()\n if (color) vars[property] = color\n }\n return Object.keys(vars).length > 0 ? vars : undefined\n}\n\nexport function ScannerFrame({ theme, style, title, children }: ScannerFrameProps) {\n const scanner = useScanner()\n if (!scanner.open) return null\n const frameTitle = title\n ?? (scanner.useCase === 'drivers-license' ? 'Scan a driver’s license' : 'Scan a document')\n const vars = themeVars(theme)\n const frameStyle: CSSProperties | undefined = vars ? { ...style, ...vars } : style\n return (\n <div\n className={`scanner-camera-overlay ${scanner.phase === 'captured' || scanner.finderStatus?.state === 'captured' ? 'is-captured' : ''} ${scanner.usingSystemCamera ? 'is-system-camera' : ''}`.trim()}\n style={frameStyle}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={frameTitle}\n >\n {children}\n <ScannerModelDownload />\n </div>\n )\n}\n\nexport function ScannerPreview() {\n const { bindPreview, frozenPreviewUrl, usingSystemCamera } = useScanner()\n const videoRef = useRef<HTMLVideoElement | null>(null)\n const setPreviewNode = useCallback((node: HTMLVideoElement | null) => {\n videoRef.current = node\n bindPreview(node)\n }, [bindPreview])\n\n useEffect(() => {\n if (frozenPreviewUrl) videoRef.current?.pause()\n }, [frozenPreviewUrl])\n\n if (usingSystemCamera) {\n return frozenPreviewUrl ? (\n <img\n src={frozenPreviewUrl}\n className=\"scanner-camera-overlay__video scanner-camera-overlay__still\"\n alt=\"\"\n aria-label=\"Captured document\"\n />\n ) : (\n <div className=\"scanner-camera-overlay__video\" aria-hidden=\"true\" />\n )\n }\n\n return (\n <>\n <video\n ref={setPreviewNode}\n className=\"scanner-camera-overlay__video\"\n muted\n autoPlay\n playsInline\n style={{ objectFit: 'cover' }}\n aria-hidden={Boolean(frozenPreviewUrl)}\n aria-label=\"Rear camera preview\"\n />\n {frozenPreviewUrl ? (\n <img\n src={frozenPreviewUrl}\n className=\"scanner-camera-overlay__video scanner-camera-overlay__still\"\n alt=\"\"\n aria-label=\"Captured document\"\n />\n ) : null}\n </>\n )\n}\n\nexport function ScannerQuad() {\n const { finderStatus, displayQuad, previewSize } = useScanner()\n if (!displayQuad || !finderStatus?.sourceWidth || !finderStatus.sourceHeight) {\n return null\n }\n const overlayTransform = liveOverlayTransform(\n finderStatus.sourceWidth,\n finderStatus.sourceHeight,\n previewSize.width,\n previewSize.height,\n 'cover',\n )\n return (\n <svg\n className={`scanner-camera-overlay__quad ${finderStatus.state}`}\n viewBox={overlayTransform.viewBox}\n preserveAspectRatio={overlayTransform.preserveAspectRatio}\n aria-label={`${finderStatus.state} document boundary`}\n >\n <polygon points={`${displayQuad.topLeft.x},${displayQuad.topLeft.y} ${displayQuad.topRight.x},${displayQuad.topRight.y} ${displayQuad.bottomRight.x},${displayQuad.bottomRight.y} ${displayQuad.bottomLeft.x},${displayQuad.bottomLeft.y}`} />\n </svg>\n )\n}\n\nexport function ScannerTopBar({ title }: { title?: string }) {\n const {\n phase,\n cancel,\n usingSystemCamera,\n useCase,\n licenseSide,\n licenseBusy,\n } = useScanner()\n const license = useCase === 'drivers-license'\n ? driverLicensePrompt(licenseSide ?? 'front', usingSystemCamera)\n : undefined\n const heading = title ?? license?.title ?? 'Scan a document'\n return (\n <div className=\"scanner-camera-overlay__topbar\">\n <div>\n <strong>{heading}</strong>\n <span aria-live=\"polite\">\n {licenseBusy && (licenseSide === 'back' ? 'Reading the barcode…' : 'Reading the front…')}\n {!licenseBusy && license && phase === 'error' && (\n licenseSide === 'back' ? 'Could not read the back' : 'Could not read the front'\n )}\n {!licenseBusy && !license && usingSystemCamera && (\n <>\n {phase === 'starting' && 'Preparing the system camera…'}\n {phase === 'ready' && 'Take a photo. There is no live document guide.'}\n {phase === 'capturing' && 'Looking for a document…'}\n {phase === 'captured' && 'Document captured'}\n {phase === 'error' && 'No document found'}\n </>\n )}\n {!licenseBusy && !license && !usingSystemCamera && phase === 'error' && 'Camera unavailable'}\n </span>\n </div>\n <button type=\"button\" onClick={cancel} aria-label=\"Close camera\">×</button>\n </div>\n )\n}\n\nexport function ScannerNotice() {\n const {\n phase,\n error,\n diagnostics,\n copyState,\n retry,\n copyReport,\n cancel,\n usingSystemCamera,\n frozenPreviewUrl,\n useCase,\n licenseSide,\n licenseBusy,\n } = useScanner()\n const license = useCase === 'drivers-license'\n ? driverLicensePrompt(licenseSide ?? 'front', usingSystemCamera)\n : undefined\n if (phase === 'error') {\n const title = license\n ? (licenseSide === 'back' ? 'Could not read the back' : 'Could not read the front')\n : usingSystemCamera\n ? frozenPreviewUrl ? 'No document found' : 'Could not take a photo'\n : diagnostics ? 'Capture failed' : 'Could not open the camera'\n return (\n <div className=\"scanner-camera-overlay__message\" role=\"alert\">\n <strong>{title}</strong>\n <p>{error}</p>\n <div>\n <button type=\"button\" onClick={retry}>Try again</button>\n <button type=\"button\" onClick={() => void copyReport()}>\n {copyState === 'copied' ? 'Copied' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n <button type=\"button\" onClick={cancel}>Cancel</button>\n </div>\n </div>\n )\n }\n if (licenseBusy) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>{licenseSide === 'back' ? 'Reading the barcode' : 'Reading the front'}</strong>\n <p>{licenseSide === 'back' ? 'Decoding the AAMVA PDF417 on the back.' : 'Finding the card and reading the front with OCR.'}</p>\n </div>\n )\n }\n if (usingSystemCamera && phase === 'capturing' && !frozenPreviewUrl) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>{license ? license.headline : 'Opening the system camera'}</strong>\n <p>{license ? license.detail : 'There is no live document guide. We find the page after you take the photo.'}</p>\n </div>\n )\n }\n if (usingSystemCamera && phase === 'ready' && !frozenPreviewUrl) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <strong>{license ? license.headline : 'System camera'}</strong>\n <p>{license ? license.detail : 'Tap the shutter to open the Camera app. There is no live document guide.'}</p>\n </div>\n )\n }\n if (phase === 'starting' && !usingSystemCamera) {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>Requesting the highest practical resolution</strong>\n <p>Allow camera access to continue.</p>\n </div>\n )\n }\n return null\n}\n\nexport function ScannerStatus() {\n const {\n finderStatus,\n detectorStatus,\n settings,\n usingSystemCamera,\n captureMethod,\n phase,\n useCase,\n licenseSide,\n } = useScanner()\n const width = settings?.width\n const height = settings?.height\n const licenseLabel = useCase === 'drivers-license'\n ? ` · ${licenseSide === 'back' ? 'back' : 'front'}`\n : ''\n if (usingSystemCamera) {\n return (\n <div className=\"scanner-camera-overlay__status\" aria-live=\"polite\">\n <div className=\"scanner-camera-overlay__status-line\">\n <span className={phase === 'captured' ? 'ready' : phase === 'error' ? 'seeking' : 'detecting'} />\n {captureMethod === 'system-camera' ? 'system camera' : 'system camera · waiting'}\n {licenseLabel}\n {width && height ? ` · ${width}×${height}` : ''}\n </div>\n </div>\n )\n }\n return (\n <div className=\"scanner-camera-overlay__status\" aria-live=\"polite\">\n <div className=\"scanner-camera-overlay__status-line\">\n <span className={finderStatus?.state ?? 'detecting'} />\n {finderStatus?.state ?? 'detecting'}\n {licenseLabel}\n {finderStatus ? ` · ${Math.round(finderStatus.confidence * 100)}% · ${finderStatus.stableFrames}/${finderStatus.requiredStableFrames}` : ''}\n {` · ${detectorStatus}`}\n {finderStatus?.inferenceMs !== undefined ? ` · ${Math.round(finderStatus.inferenceMs)}ms` : ''}\n {width && height ? ` · ${width}×${height}` : ''}\n </div>\n </div>\n )\n}\n\nexport function ScannerDiagnostics() {\n const {\n diagnostics,\n shutterDiagnostics,\n captureMethod,\n copyState,\n copyReport,\n } = useScanner()\n const engine = diagnostics?.engine ?? detectBrowserEngine()\n return (\n <dl className=\"scanner-camera-overlay__diagnostics\" aria-label=\"Camera diagnostics\">\n <div>\n <dt>engine</dt>\n <dd>{engine.engine}/{engine.browser}{engine.iosWebKit ? ' ios' : ''}</dd>\n </div>\n <div>\n <dt>video</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.videoWidth}×${diagnostics.videoHeight} rs${diagnostics.readyState}${diagnostics.paused ? ' paused' : ''}${diagnostics.rendered ? '' : ' hidden'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>track</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.trackReadyState}${diagnostics.trackMuted ? ' muted' : ''}${diagnostics.trackEnabled ? '' : ' disabled'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>torch</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.torch.mode} · ${diagnostics.torch.supported ? (diagnostics.torch.on ? 'on' : 'off') : 'unsupported'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>luma</dt>\n <dd>\n {diagnostics\n ? `live ${diagnostics.liveLuminance.toFixed(1)} · mirror ${diagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(diagnostics.mirrorAgeMs) ? ` (${Math.round(diagnostics.mirrorAgeMs)}ms)` : ' (none)'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>path</dt>\n <dd>{captureMethod ?? 'video-frame / live-mirror'}</dd>\n </div>\n {shutterDiagnostics ? (\n <div>\n <dt>shutter</dt>\n <dd>\n {`live ${shutterDiagnostics.liveLuminance.toFixed(1)} · mirror ${shutterDiagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(shutterDiagnostics.mirrorAgeMs) ? ` (${Math.round(shutterDiagnostics.mirrorAgeMs)}ms)` : ' (none)'}`}\n </dd>\n </div>\n ) : null}\n <div>\n <dt>share</dt>\n <dd>\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__copy\"\n onClick={() => void copyReport()}\n >\n {copyState === 'copied' ? 'Copied report' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n </dd>\n </div>\n </dl>\n )\n}\n\nexport function ScannerControls() {\n const {\n autoCapture,\n phase,\n finderStatus,\n diagnostics,\n captureMethod,\n settings,\n cancel,\n capture,\n setAutoCapture,\n setTorch,\n usingSystemCamera,\n licenseBusy,\n useCase,\n licenseSide,\n guidanceHint,\n } = useScanner()\n const width = settings?.width\n const height = settings?.height\n const showShutter = usingSystemCamera\n ? phase === 'ready'\n : autoCapture !== 'only'\n const license = useCase === 'drivers-license'\n ? driverLicensePrompt(licenseSide ?? 'front', usingSystemCamera)\n : undefined\n const guidance = overlayGuidanceText({\n usingSystemCamera,\n phase,\n licenseBusy,\n holdStillSeconds: finderStatus?.holdStillSeconds,\n guidanceHint,\n guidanceReason: finderStatus?.guidance.reason,\n licenseHeadline: license?.headline,\n })\n const holdStill = Boolean(finderStatus?.holdStillSeconds)\n return (\n <div className=\"scanner-camera-overlay__controls\">\n <button type=\"button\" className=\"scanner-camera-overlay__cancel\" onClick={cancel}>Cancel</button>\n <div className=\"scanner-camera-overlay__capture\">\n {guidance && (\n <p\n className={`scanner-camera-overlay__guidance${holdStill ? ' is-ready' : ''}`}\n aria-live=\"polite\"\n >\n {guidance}\n </p>\n )}\n {showShutter && (\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__shutter\"\n onClick={() => void capture()}\n disabled={phase !== 'ready' || Boolean(licenseBusy)}\n aria-label={usingSystemCamera ? 'Take a photo with the system camera' : 'Capture full-resolution photo'}\n >\n <span />\n </button>\n )}\n {!usingSystemCamera && (\n <div className=\"scanner-camera-overlay__toggles\">\n {finderStatus?.autoCapture.visible && (\n <label>\n <input\n type=\"checkbox\"\n checked={finderStatus.autoCapture.checked}\n onChange={(event) => setAutoCapture(event.target.checked)}\n />\n Auto-capture\n </label>\n )}\n {diagnostics?.torch.visible && (\n <label title={diagnostics.torch.automatic ? 'Torch is controlled automatically from scene brightness' : undefined}>\n <input\n type=\"checkbox\"\n checked={diagnostics.torch.on}\n disabled={!diagnostics.torch.mutable}\n onChange={(event) => void setTorch(event.target.checked)}\n />\n {diagnostics.torch.automatic ? 'Auto torch' : 'Torch'}\n </label>\n )}\n </div>\n )}\n </div>\n <div className=\"scanner-camera-overlay__quality\">\n <span>{usingSystemCamera ? 'System camera' : captureMethod === 'live-mirror' ? 'Mirror' : 'Camera'}</span>\n <strong>{width && height ? `${width} × ${height}` : usingSystemCamera ? 'Tap to photograph' : 'Measuring…'}</strong>\n </div>\n </div>\n )\n}\n\nexport function ScannerModelDownload({ snapshot }: { snapshot?: ModelDownloadSnapshot }) {\n const { modelDownload } = useScanner()\n return <ModelDownloadRing snapshot={snapshot ?? modelDownload} />\n}\n"],"mappings":"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"}
@@ -1,23 +1,23 @@
1
- import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as ee, P as m, R as h, S as g, T as _, U as v, V as y, W as b, X as x, Y as S, _ as C, a as w, b as T, c as E, d as D, f as O, g as k, h as A, i as j, j as M, k as N, l as te, m as P, n as F, o as I, p as L, q as R, r as z, s as B, t as V, u as H, v as U, w as W, x as G, y as K, z as q } from "./driver-license-DpjQqOKx.js";
1
+ import { $ as e, A as t, B as n, C as r, D as i, E as a, F as o, G as s, H as c, I as l, J as u, K as d, L as ee, M as te, N as ne, O as f, P as p, Q as m, R as h, S as g, T as _, U as v, V as y, W as b, X as x, Y as S, Z as C, _ as w, a as T, b as E, c as D, d as O, f as k, g as A, h as j, i as re, j as M, k as N, l as P, m as F, n as I, o as L, p as R, q as z, r as B, s as V, t as H, u as U, v as W, w as G, x as K, y as q, z as J } from "./driver-license-yM6pBkNk.js";
2
2
  //#region src/sdk/frame-geometry.ts
3
- function J(e, t, n) {
3
+ function Y(e, t, n) {
4
4
  let r = Math.max(1, t.width), i = Math.max(1, t.height), a = Math.max(1, n.width), o = Math.max(1, n.height), s = Math.max(r / a, i / o), c = (r - a * s) / 2, l = (i - o * s) / 2;
5
5
  return {
6
6
  x: (e.x - c) / s,
7
7
  y: (e.y - l) / s
8
8
  };
9
9
  }
10
- function Y(e, t, n) {
10
+ function X(e, t, n) {
11
11
  return {
12
- topLeft: J(e.topLeft, t, n),
13
- topRight: J(e.topRight, t, n),
14
- bottomRight: J(e.bottomRight, t, n),
15
- bottomLeft: J(e.bottomLeft, t, n)
12
+ topLeft: Y(e.topLeft, t, n),
13
+ topRight: Y(e.topRight, t, n),
14
+ bottomRight: Y(e.bottomRight, t, n),
15
+ bottomLeft: Y(e.bottomLeft, t, n)
16
16
  };
17
17
  }
18
18
  //#endregion
19
19
  //#region src/sdk/finder-simulator.ts
20
- function X(e, t = 960, n = 600) {
20
+ function Z(e, t = 960, n = 600) {
21
21
  let r = t * .86, i = n * .86;
22
22
  if (e < 1200) {
23
23
  let a = e / 1200;
@@ -50,15 +50,15 @@ function X(e, t = 960, n = 600) {
50
50
  phase: "settled"
51
51
  };
52
52
  }
53
- function Z(e, t, n) {
53
+ function Q(e, t, n) {
54
54
  let r = Math.cos(n.rotation), i = Math.sin(n.rotation);
55
55
  return {
56
56
  x: n.centerX + e * r - t * i,
57
57
  y: n.centerY + e * i + t * r
58
58
  };
59
59
  }
60
- function Q(e) {
61
- let t = Z(-e.width / 2, -e.height / 2, e), n = Z(e.width / 2, -e.height / 2, e), r = Z(e.width / 2, e.height / 2, e), i = Z(-e.width / 2, e.height / 2, e);
60
+ function ie(e) {
61
+ let t = Q(-e.width / 2, -e.height / 2, e), n = Q(e.width / 2, -e.height / 2, e), r = Q(e.width / 2, e.height / 2, e), i = Q(-e.width / 2, e.height / 2, e);
62
62
  return {
63
63
  topLeft: t,
64
64
  topRight: n,
@@ -84,20 +84,20 @@ function Q(e) {
84
84
  }
85
85
  };
86
86
  }
87
- function $(e, t) {
88
- let n = e.getContext("2d");
89
- if (!n) throw x();
90
- let r = n.createLinearGradient(0, 0, e.width, e.height);
91
- r.addColorStop(0, "#16231c"), r.addColorStop(1, "#32443a"), n.fillStyle = r, n.fillRect(0, 0, e.width, e.height), n.save(), n.translate(t.centerX, t.centerY), n.rotate(t.rotation), n.shadowColor = "rgba(0,0,0,.45)", n.shadowBlur = 24, n.fillStyle = "#fffdf4", n.strokeStyle = "#111914", n.lineWidth = 7, n.fillRect(-t.width / 2, -t.height / 2, t.width, t.height), n.strokeRect(-t.width / 2, -t.height / 2, t.width, t.height), n.shadowColor = "transparent";
92
- let i = -t.width / 2, a = -t.height / 2;
93
- n.fillStyle = "#d7ded8", n.fillRect(i + 38, a + 84, 145, 190), n.fillStyle = "#617269", n.beginPath(), n.arc(i + 110, a + 140, 38, 0, Math.PI * 2), n.fill(), n.fillRect(i + 70, a + 185, 80, 65), n.fillStyle = "#17231c", n.font = "700 25px Arial", n.fillText("IDENTITY CARD", i + 38, a + 48), n.font = "700 31px Arial", n.fillText("TAYLOR MORGAN", i + 220, a + 118), n.font = "23px Arial", n.fillText("01/02/1990", i + 220, a + 166), n.fillText("A1234567", i + 220, a + 208), n.fillText("123 MAIN ST", i + 220, a + 270), n.fillText("AUSTIN TX 78701", i + 220, a + 307), n.restore();
87
+ function $(t, n) {
88
+ let r = t.getContext("2d");
89
+ if (!r) throw e();
90
+ let i = r.createLinearGradient(0, 0, t.width, t.height);
91
+ i.addColorStop(0, "#16231c"), i.addColorStop(1, "#32443a"), r.fillStyle = i, r.fillRect(0, 0, t.width, t.height), r.save(), r.translate(n.centerX, n.centerY), r.rotate(n.rotation), r.shadowColor = "rgba(0,0,0,.45)", r.shadowBlur = 24, r.fillStyle = "#fffdf4", r.strokeStyle = "#111914", r.lineWidth = 7, r.fillRect(-n.width / 2, -n.height / 2, n.width, n.height), r.strokeRect(-n.width / 2, -n.height / 2, n.width, n.height), r.shadowColor = "transparent";
92
+ let a = -n.width / 2, o = -n.height / 2;
93
+ r.fillStyle = "#d7ded8", r.fillRect(a + 38, o + 84, 145, 190), r.fillStyle = "#617269", r.beginPath(), r.arc(a + 110, o + 140, 38, 0, Math.PI * 2), r.fill(), r.fillRect(a + 70, o + 185, 80, 65), r.fillStyle = "#17231c", r.font = "700 25px Arial", r.fillText("IDENTITY CARD", a + 38, o + 48), r.font = "700 31px Arial", r.fillText("TAYLOR MORGAN", a + 220, o + 118), r.font = "23px Arial", r.fillText("01/02/1990", a + 220, o + 166), r.fillText("A1234567", a + 220, o + 208), r.fillText("123 MAIN ST", a + 220, o + 270), r.fillText("AUSTIN TX 78701", a + 220, o + 307), r.restore();
94
94
  }
95
- function ne(e) {
95
+ function ae(e) {
96
96
  e.width ||= 960, e.height ||= 600;
97
97
  let t = !1, n = 0, r = 0, i = (a) => {
98
- t && (n ||= a, $(e, X(a - n, e.width, e.height)), r = requestAnimationFrame(i));
98
+ t && (n ||= a, $(e, Z(a - n, e.width, e.height)), r = requestAnimationFrame(i));
99
99
  }, a = () => {
100
- n = 0, $(e, X(0, e.width, e.height));
100
+ n = 0, $(e, Z(0, e.width, e.height));
101
101
  };
102
102
  return a(), {
103
103
  start() {
@@ -110,6 +110,6 @@ function ne(e) {
110
110
  };
111
111
  }
112
112
  //#endregion
113
- export { r as AutoTorchController, T as DEFAULT_DOCUMENT_MODEL_URL, b as DEV_LICENSE_HOSTS, o as LicenseError, ee as NEAR_BLACK_LUMINANCE, L as QuadStabilityTracker, N as STILL_MAX_EDGE, S as ScannerError, B as applyRedactions, u as assertLicense, P as autoCaptureControl, e as captureVideoFrame, ne as createFinderSimulator, G as cropDocument, H as decodePdf417, M as detectBrowserEngine, g as detectDocument, V as driverLicenseFieldsFromOcr, F as driverLicensePrompt, f as formatCaptureDiagnosticsReport, R as getLicense, p as hasTransientUserActivation, m as isAndroidBrowser, a as isNearBlackFrame, A as limitingFillTarget, Y as mapDocumentCornersToFrame, w as matchRedactionRules, c as meanFrameLuminance, k as measureQuadFill, z as mergeDriverLicenseFields, d as mobileCameraConstraints, E as parseAamvaDate, te as parseAamvaPayload, D as pdf417BarcodeDetectorSupported, h as pickNativeCameraStill, O as recognizeText, I as redactProgrammatically, n as resolveDocumentModelUrl, W as scanDocument, _ as scanSystemCameraStill, C as selectFinderGuidance, U as selectFinderHint, l as setLicenseKey, q as shouldPreferWebGpuForDocumentModel, t as shouldUseSystemCameraCapture, Q as simulatorQuad, y as startCamera, j as startDriverLicenseSession, K as startFinder, v as subscribeModelDownloads, i as systemCameraFindMessage, s as torchControl };
113
+ export { t as AutoTorchController, r as DEFAULT_DOCUMENT_MODEL_URL, R as DEFAULT_HOLD_STILL_MS, z as DEV_LICENSE_HOSTS, u as LicenseError, M as NEAR_BLACK_LUMINANCE, F as QuadStabilityTracker, te as STILL_MAX_EDGE, m as ScannerError, V as applyRedactions, S as assertLicense, j as autoCaptureControl, ne as captureVideoFrame, ae as createFinderSimulator, G as cropDocument, U as decodePdf417, p as detectBrowserEngine, _ as detectDocument, H as driverLicenseFieldsFromOcr, I as driverLicensePrompt, o as formatCaptureDiagnosticsReport, x as getLicense, l as hasTransientUserActivation, A as holdStillCountdownLabel, w as holdStillSecondsRemaining, ee as isAndroidBrowser, h as isNearBlackFrame, W as limitingFillTarget, X as mapDocumentCornersToFrame, T as matchRedactionRules, J as meanFrameLuminance, q as measureQuadFill, B as mergeDriverLicenseFields, n as mobileCameraConstraints, D as parseAamvaDate, P as parseAamvaPayload, O as pdf417BarcodeDetectorSupported, y as pickNativeCameraStill, k as recognizeText, L as redactProgrammatically, a as resolveDocumentModelUrl, i as scanDocument, f as scanSystemCameraStill, E as selectFinderGuidance, K as selectFinderHint, C as setLicenseKey, c as shouldPreferWebGpuForDocumentModel, v as shouldUseSystemCameraCapture, ie as simulatorQuad, b as startCamera, re as startDriverLicenseSession, g as startFinder, d as subscribeModelDownloads, N as systemCameraFindMessage, s as torchControl };
114
114
 
115
115
  //# sourceMappingURL=scanner-sdk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanner-sdk.js","names":[],"sources":["../src/sdk/frame-geometry.ts","../src/sdk/finder-simulator.ts"],"sourcesContent":["import type { DocumentCorners, Point } from './types'\n\nexport interface FrameSize {\n width: number\n height: number\n}\n\nfunction mapPointFromVisibleSourceToTarget(\n point: Point,\n source: FrameSize,\n target: FrameSize,\n): Point {\n const sourceWidth = Math.max(1, source.width)\n const sourceHeight = Math.max(1, source.height)\n const targetWidth = Math.max(1, target.width)\n const targetHeight = Math.max(1, target.height)\n // The analysis frame is the center-cropped view of a differently-shaped\n // still. Invert object-fit: cover so source pixels map into the full still.\n const scale = Math.max(sourceWidth / targetWidth, sourceHeight / targetHeight)\n const offsetX = (sourceWidth - targetWidth * scale) / 2\n const offsetY = (sourceHeight - targetHeight * scale) / 2\n return {\n x: (point.x - offsetX) / scale,\n y: (point.y - offsetY) / scale,\n }\n}\n\nexport function mapDocumentCornersToFrame(\n corners: DocumentCorners,\n source: FrameSize,\n target: FrameSize,\n): DocumentCorners {\n return {\n topLeft: mapPointFromVisibleSourceToTarget(corners.topLeft, source, target),\n topRight: mapPointFromVisibleSourceToTarget(corners.topRight, source, target),\n bottomRight: mapPointFromVisibleSourceToTarget(corners.bottomRight, source, target),\n bottomLeft: mapPointFromVisibleSourceToTarget(corners.bottomLeft, source, target),\n }\n}\n","import { canvasUnavailable } from './errors'\nimport type { DocumentQuad, Point } from './types'\n\nexport interface SimulatorPose {\n centerX: number\n centerY: number\n rotation: number\n width: number\n height: number\n phase: 'entering' | 'jittering' | 'settled'\n}\n\nexport interface FinderSimulator {\n start: () => void\n stop: () => void\n reset: () => void\n}\n\nexport function simulatorPose(elapsedMs: number, canvasWidth = 960, canvasHeight = 600): SimulatorPose {\n // Settle comfortably above the finder's default 72% limiting-axis fill target so\n // the simulator demonstrates Move closer before becoming eligible for auto-capture.\n const width = canvasWidth * 0.86\n const height = canvasHeight * 0.86\n if (elapsedMs < 1200) {\n const progress = elapsedMs / 1200\n return {\n centerX: -width / 2 + (canvasWidth / 2 + width / 2) * (1 - Math.pow(1 - progress, 3)),\n centerY: canvasHeight / 2,\n rotation: -0.14 + progress * 0.08,\n width,\n height,\n phase: 'entering',\n }\n }\n if (elapsedMs < 3600) {\n const progress = (elapsedMs - 1200) / 2400\n const amplitude = (1 - progress) * 18\n return {\n centerX: canvasWidth / 2 + Math.sin(elapsedMs / 85) * amplitude,\n centerY: canvasHeight / 2 + Math.cos(elapsedMs / 110) * amplitude * 0.55,\n rotation: -0.055 + Math.sin(elapsedMs / 125) * (1 - progress) * 0.045,\n width,\n height,\n phase: 'jittering',\n }\n }\n return {\n centerX: canvasWidth / 2,\n centerY: canvasHeight / 2,\n rotation: 0,\n width,\n height,\n phase: 'settled',\n }\n}\n\nfunction rotatePoint(x: number, y: number, pose: SimulatorPose): Point {\n const cosine = Math.cos(pose.rotation)\n const sine = Math.sin(pose.rotation)\n return {\n x: pose.centerX + x * cosine - y * sine,\n y: pose.centerY + x * sine + y * cosine,\n }\n}\n\nexport function simulatorQuad(pose: SimulatorPose): DocumentQuad {\n const topLeft = rotatePoint(-pose.width / 2, -pose.height / 2, pose)\n const topRight = rotatePoint(pose.width / 2, -pose.height / 2, pose)\n const bottomRight = rotatePoint(pose.width / 2, pose.height / 2, pose)\n const bottomLeft = rotatePoint(-pose.width / 2, pose.height / 2, pose)\n return {\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n edges: {\n top: { start: topLeft, end: topRight },\n right: { start: topRight, end: bottomRight },\n bottom: { start: bottomRight, end: bottomLeft },\n left: { start: bottomLeft, end: topLeft },\n },\n }\n}\n\nfunction drawFrame(canvas: HTMLCanvasElement, pose: SimulatorPose) {\n const context = canvas.getContext('2d')\n if (!context) throw canvasUnavailable()\n const background = context.createLinearGradient(0, 0, canvas.width, canvas.height)\n background.addColorStop(0, '#16231c')\n background.addColorStop(1, '#32443a')\n context.fillStyle = background\n context.fillRect(0, 0, canvas.width, canvas.height)\n context.save()\n context.translate(pose.centerX, pose.centerY)\n context.rotate(pose.rotation)\n context.shadowColor = 'rgba(0,0,0,.45)'\n context.shadowBlur = 24\n context.fillStyle = '#fffdf4'\n context.strokeStyle = '#111914'\n context.lineWidth = 7\n context.fillRect(-pose.width / 2, -pose.height / 2, pose.width, pose.height)\n context.strokeRect(-pose.width / 2, -pose.height / 2, pose.width, pose.height)\n context.shadowColor = 'transparent'\n const left = -pose.width / 2\n const top = -pose.height / 2\n context.fillStyle = '#d7ded8'\n context.fillRect(left + 38, top + 84, 145, 190)\n context.fillStyle = '#617269'\n context.beginPath()\n context.arc(left + 110, top + 140, 38, 0, Math.PI * 2)\n context.fill()\n context.fillRect(left + 70, top + 185, 80, 65)\n context.fillStyle = '#17231c'\n context.font = '700 25px Arial'\n context.fillText('IDENTITY CARD', left + 38, top + 48)\n context.font = '700 31px Arial'\n context.fillText('TAYLOR MORGAN', left + 220, top + 118)\n context.font = '23px Arial'\n context.fillText('01/02/1990', left + 220, top + 166)\n context.fillText('A1234567', left + 220, top + 208)\n context.fillText('123 MAIN ST', left + 220, top + 270)\n context.fillText('AUSTIN TX 78701', left + 220, top + 307)\n context.restore()\n}\n\nexport function createFinderSimulator(canvas: HTMLCanvasElement): FinderSimulator {\n if (!canvas.width) canvas.width = 960\n if (!canvas.height) canvas.height = 600\n let running = false\n let startedAt = 0\n let animationFrame = 0\n const render = (time: number) => {\n if (!running) return\n if (!startedAt) startedAt = time\n drawFrame(canvas, simulatorPose(time - startedAt, canvas.width, canvas.height))\n animationFrame = requestAnimationFrame(render)\n }\n const reset = () => {\n startedAt = 0\n drawFrame(canvas, simulatorPose(0, canvas.width, canvas.height))\n }\n reset()\n return {\n start() {\n if (running) return\n running = true\n animationFrame = requestAnimationFrame(render)\n },\n stop() {\n running = false\n cancelAnimationFrame(animationFrame)\n },\n reset,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scanner-sdk.js","names":[],"sources":["../src/sdk/frame-geometry.ts","../src/sdk/finder-simulator.ts"],"sourcesContent":["import type { DocumentCorners, Point } from './types'\n\nexport interface FrameSize {\n width: number\n height: number\n}\n\nfunction mapPointFromVisibleSourceToTarget(\n point: Point,\n source: FrameSize,\n target: FrameSize,\n): Point {\n const sourceWidth = Math.max(1, source.width)\n const sourceHeight = Math.max(1, source.height)\n const targetWidth = Math.max(1, target.width)\n const targetHeight = Math.max(1, target.height)\n // The analysis frame is the center-cropped view of a differently-shaped\n // still. Invert object-fit: cover so source pixels map into the full still.\n const scale = Math.max(sourceWidth / targetWidth, sourceHeight / targetHeight)\n const offsetX = (sourceWidth - targetWidth * scale) / 2\n const offsetY = (sourceHeight - targetHeight * scale) / 2\n return {\n x: (point.x - offsetX) / scale,\n y: (point.y - offsetY) / scale,\n }\n}\n\nexport function mapDocumentCornersToFrame(\n corners: DocumentCorners,\n source: FrameSize,\n target: FrameSize,\n): DocumentCorners {\n return {\n topLeft: mapPointFromVisibleSourceToTarget(corners.topLeft, source, target),\n topRight: mapPointFromVisibleSourceToTarget(corners.topRight, source, target),\n bottomRight: mapPointFromVisibleSourceToTarget(corners.bottomRight, source, target),\n bottomLeft: mapPointFromVisibleSourceToTarget(corners.bottomLeft, source, target),\n }\n}\n","import { canvasUnavailable } from './errors'\nimport type { DocumentQuad, Point } from './types'\n\nexport interface SimulatorPose {\n centerX: number\n centerY: number\n rotation: number\n width: number\n height: number\n phase: 'entering' | 'jittering' | 'settled'\n}\n\nexport interface FinderSimulator {\n start: () => void\n stop: () => void\n reset: () => void\n}\n\nexport function simulatorPose(elapsedMs: number, canvasWidth = 960, canvasHeight = 600): SimulatorPose {\n // Settle comfortably above the finder's default 72% limiting-axis fill target so\n // the simulator demonstrates Move closer before becoming eligible for auto-capture.\n const width = canvasWidth * 0.86\n const height = canvasHeight * 0.86\n if (elapsedMs < 1200) {\n const progress = elapsedMs / 1200\n return {\n centerX: -width / 2 + (canvasWidth / 2 + width / 2) * (1 - Math.pow(1 - progress, 3)),\n centerY: canvasHeight / 2,\n rotation: -0.14 + progress * 0.08,\n width,\n height,\n phase: 'entering',\n }\n }\n if (elapsedMs < 3600) {\n const progress = (elapsedMs - 1200) / 2400\n const amplitude = (1 - progress) * 18\n return {\n centerX: canvasWidth / 2 + Math.sin(elapsedMs / 85) * amplitude,\n centerY: canvasHeight / 2 + Math.cos(elapsedMs / 110) * amplitude * 0.55,\n rotation: -0.055 + Math.sin(elapsedMs / 125) * (1 - progress) * 0.045,\n width,\n height,\n phase: 'jittering',\n }\n }\n return {\n centerX: canvasWidth / 2,\n centerY: canvasHeight / 2,\n rotation: 0,\n width,\n height,\n phase: 'settled',\n }\n}\n\nfunction rotatePoint(x: number, y: number, pose: SimulatorPose): Point {\n const cosine = Math.cos(pose.rotation)\n const sine = Math.sin(pose.rotation)\n return {\n x: pose.centerX + x * cosine - y * sine,\n y: pose.centerY + x * sine + y * cosine,\n }\n}\n\nexport function simulatorQuad(pose: SimulatorPose): DocumentQuad {\n const topLeft = rotatePoint(-pose.width / 2, -pose.height / 2, pose)\n const topRight = rotatePoint(pose.width / 2, -pose.height / 2, pose)\n const bottomRight = rotatePoint(pose.width / 2, pose.height / 2, pose)\n const bottomLeft = rotatePoint(-pose.width / 2, pose.height / 2, pose)\n return {\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n edges: {\n top: { start: topLeft, end: topRight },\n right: { start: topRight, end: bottomRight },\n bottom: { start: bottomRight, end: bottomLeft },\n left: { start: bottomLeft, end: topLeft },\n },\n }\n}\n\nfunction drawFrame(canvas: HTMLCanvasElement, pose: SimulatorPose) {\n const context = canvas.getContext('2d')\n if (!context) throw canvasUnavailable()\n const background = context.createLinearGradient(0, 0, canvas.width, canvas.height)\n background.addColorStop(0, '#16231c')\n background.addColorStop(1, '#32443a')\n context.fillStyle = background\n context.fillRect(0, 0, canvas.width, canvas.height)\n context.save()\n context.translate(pose.centerX, pose.centerY)\n context.rotate(pose.rotation)\n context.shadowColor = 'rgba(0,0,0,.45)'\n context.shadowBlur = 24\n context.fillStyle = '#fffdf4'\n context.strokeStyle = '#111914'\n context.lineWidth = 7\n context.fillRect(-pose.width / 2, -pose.height / 2, pose.width, pose.height)\n context.strokeRect(-pose.width / 2, -pose.height / 2, pose.width, pose.height)\n context.shadowColor = 'transparent'\n const left = -pose.width / 2\n const top = -pose.height / 2\n context.fillStyle = '#d7ded8'\n context.fillRect(left + 38, top + 84, 145, 190)\n context.fillStyle = '#617269'\n context.beginPath()\n context.arc(left + 110, top + 140, 38, 0, Math.PI * 2)\n context.fill()\n context.fillRect(left + 70, top + 185, 80, 65)\n context.fillStyle = '#17231c'\n context.font = '700 25px Arial'\n context.fillText('IDENTITY CARD', left + 38, top + 48)\n context.font = '700 31px Arial'\n context.fillText('TAYLOR MORGAN', left + 220, top + 118)\n context.font = '23px Arial'\n context.fillText('01/02/1990', left + 220, top + 166)\n context.fillText('A1234567', left + 220, top + 208)\n context.fillText('123 MAIN ST', left + 220, top + 270)\n context.fillText('AUSTIN TX 78701', left + 220, top + 307)\n context.restore()\n}\n\nexport function createFinderSimulator(canvas: HTMLCanvasElement): FinderSimulator {\n if (!canvas.width) canvas.width = 960\n if (!canvas.height) canvas.height = 600\n let running = false\n let startedAt = 0\n let animationFrame = 0\n const render = (time: number) => {\n if (!running) return\n if (!startedAt) startedAt = time\n drawFrame(canvas, simulatorPose(time - startedAt, canvas.width, canvas.height))\n animationFrame = requestAnimationFrame(render)\n }\n const reset = () => {\n startedAt = 0\n drawFrame(canvas, simulatorPose(0, canvas.width, canvas.height))\n }\n reset()\n return {\n start() {\n if (running) return\n running = true\n animationFrame = requestAnimationFrame(render)\n },\n stop() {\n running = false\n cancelAnimationFrame(animationFrame)\n },\n reset,\n }\n}\n"],"mappings":"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"}
@@ -36,6 +36,9 @@ export interface FinderLighting {
36
36
  hint?: string;
37
37
  }
38
38
  export declare function selectFinderHint(guidance: FinderGuidance, lighting: FinderLighting): string;
39
+ /** Wall-clock seconds remaining in the auto-capture hold-still. `0` means fire. */
40
+ export declare function holdStillSecondsRemaining(startedAt: number, now: number, holdStillMs: number): number;
41
+ export declare function holdStillCountdownLabel(seconds: number): string;
39
42
  export interface AutoCaptureControl {
40
43
  visible: boolean;
41
44
  checked: boolean;
@@ -50,6 +53,12 @@ export interface FinderStatus {
50
53
  stableFrames: number;
51
54
  requiredStableFrames: number;
52
55
  autoCapture: AutoCaptureControl;
56
+ /**
57
+ * Seconds left in the auto-capture hold-still (3, then 2, then 1).
58
+ * Absent when the document is not ready, auto-capture is off, or the
59
+ * countdown finished and capture is starting.
60
+ */
61
+ holdStillSeconds?: number;
53
62
  sourceWidth?: number;
54
63
  sourceHeight?: number;
55
64
  detector?: DocumentDetectionResult['detector'];
@@ -73,6 +82,12 @@ export interface FinderOptions {
73
82
  onCapture?: (capture: FinderCapture) => void | Promise<void>;
74
83
  /** Reports capture failures, including automatic captures, instead of swallowing them. */
75
84
  onCaptureError?: (error: Error) => void;
85
+ /**
86
+ * After the document is ready, wait this long before auto-capture so the
87
+ * end user can settle. The overlay counts down 3… 2… 1…. Defaults to 3000ms.
88
+ * Manual `capture()` does not wait. Lost or unstable quads reset the timer.
89
+ */
90
+ holdStillMs?: number;
76
91
  /** Consecutive stable raw detections required. Defaults to 4. */
77
92
  stableFrames?: number;
78
93
  /** Minimum detector confidence on the normalized 0–1 scale. Defaults to 0.72. */
@@ -131,6 +146,7 @@ export interface FinderGuidanceOptions {
131
146
  /** Opposite-edge ratio allowed after ready. Defaults to 0.4. */
132
147
  exitMinPerspectiveRatio?: number;
133
148
  }
149
+ export declare const DEFAULT_HOLD_STILL_MS = 3000;
134
150
  export declare const DEFAULT_FINDER_STABLE_FRAMES = 4;
135
151
  export declare const DEFAULT_FINDER_CONFIDENCE_THRESHOLD = 0.72;
136
152
  export declare const DEFAULT_FINDER_CORNER_TOLERANCE = 0.024;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exige/web-scanner-sdk",
3
- "version": "0.2.30",
3
+ "version": "0.2.31",
4
4
  "description": "@exige/web-scanner-sdk is a client-side web document scanner SDK. ML document finding, OCR, and redaction run in the browser. The public demo is the only path that does not need an account. A hostname you control needs a signed license key.",
5
5
  "type": "module",
6
6
  "license": "MIT",