Real-time webcam
For continuous detection (every N ms, or every animation frame) you want a
warm instance (one Quadscan that holds the ORT session across calls).
The static Quadscan.scan would also work, but exposing the instance lets
you dispose() it when the user stops the camera.
mode: 'detect' skips the perspective-warp step (which can be the most
expensive part on large frames). Draw the corners yourself on an overlay
canvas; only warp when the user hits “capture”.
Pattern
import { Quadscan } from 'quadscan';
const video = document.querySelector('video')!;
const overlay = document.querySelector('canvas')!;
const ctx = overlay.getContext('2d')!;
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.srcObject = stream;
await video.play();
overlay.width = video.videoWidth;
overlay.height = video.videoHeight;
const q = new Quadscan();
await q.initialize(); // download model up front while showing a spinner
const timer = setInterval(async () => {
const r = await q.scan(video, { mode: 'detect' });
ctx.clearRect(0, 0, overlay.width, overlay.height);
if (!r.success) return;
const { topLeft, topRight, bottomRight, bottomLeft } = r.corners!;
ctx.strokeStyle = 'oklch(0.65 0.18 142)';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(topLeft.x, topLeft.y);
ctx.lineTo(topRight.x, topRight.y);
ctx.lineTo(bottomRight.x, bottomRight.y);
ctx.lineTo(bottomLeft.x, bottomLeft.y);
ctx.closePath();
ctx.stroke();
}, 500);
// Tear-down
addEventListener('beforeunload', () => {
clearInterval(timer);
for (const track of stream.getTracks()) track.stop();
q.dispose();
});
Tips
- Throttle to ~2 Hz. 500 ms is plenty for “frame the doc and hold still” UX; faster than that and you’ll fight your own queued scans.
- Don’t call inside
requestAnimationFrameunless you also gate it with anisBusyflag. Inference takes 30–80 ms on WebGPU. - Capture pipeline: when the user taps “scan”, do one final
q.scan(video, { mode: 'extract' })to get the warped output. - Confidence threshold: filter weak detections with
minDetectionConfidence: 0.4to avoid jittery overlays on empty scenes.
See the live webcam example for a complete implementation with start/stop controls and an FPS counter.