diff --git a/packages/web/assets/app.css b/packages/web/assets/app.css index ef4d32b..5600ec5 100644 --- a/packages/web/assets/app.css +++ b/packages/web/assets/app.css @@ -143,3 +143,77 @@ html, body { margin: 0; height: 100%; background: var(--bg); color: var(--text); font-size: 0.9rem; margin-top: 12px; } + +/* PD calibration wizard */ +.calibrate-btn { + margin-top: 8px; + width: 100%; + font-size: 12px; + padding: 6px 10px; + border-color: var(--accent2); + color: var(--accent2); + background: #0d1528; +} +.calibrate-btn.active { + background: #1a2744; + border-color: var(--accent); + color: var(--accent); +} +.cal-info { + margin-top: 8px; + padding: 8px 10px; + background: #0d1528; + border: 1px solid var(--line); + border-radius: 8px; + font-size: 11px; + line-height: 1.5; +} +.cal-info.hidden { display: none; } +.cal-info .cal-row { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 4px; +} +.cal-info .cal-label { color: var(--muted); } +.cal-info .cal-value { color: var(--accent); font-weight: 600; } +.cal-info .cal-hint { + color: var(--muted); + font-size: 10px; + margin-top: 4px; + font-style: italic; +} +.cal-info .cal-actions { + display: flex; + gap: 6px; + margin-top: 8px; +} +.cal-info .cal-actions .btn { + font-size: 10px; + padding: 4px 8px; + flex: 1; +} +/* Calibration card overlay on stage */ +#cal-overlay { + position: absolute; + border: 2px dashed var(--accent); + border-radius: 8px; + background: rgba(245,197,24,0.08); + pointer-events: none; + display: none; + z-index: 3; + transition: none; +} +#cal-overlay.visible { display: block; } +#cal-overlay .cal-card-label { + position: absolute; + bottom: -22px; + left: 50%; + transform: translateX(-50%); + font-size: 10px; + color: var(--accent); + background: #000a; + padding: 2px 6px; + border-radius: 4px; + white-space: nowrap; +} diff --git a/packages/web/assets/app.js b/packages/web/assets/app.js index 06f0731..5cf2da4 100644 --- a/packages/web/assets/app.js +++ b/packages/web/assets/app.js @@ -37,6 +37,13 @@ try { } let sessionId = null; +// --- PD Calibration Wizard state --- +let calMode = false; +let cardPx = 200; // credit card width in pixels (adjustable) +const CARD_WIDTH_MM = 85.6; // standard ISO/IEC 7810 ID-1 credit card +const CARD_HEIGHT_MM = 54.0; +const CARD_ASPECT = CARD_WIDTH_MM / CARD_HEIGHT_MM; + function isStaticDemo() { return !!(globalThis.BeeARStatic && globalThis.BeeARStatic.detectStatic()); } @@ -856,6 +863,102 @@ function renderGallery() { // UI element event binding configuration document.getElementById("btn-cam").onclick = startCamera; + +// --- PD Calibration Wizard --- +function measurePdPx() { + const lx = face.left[0] * canvas.width; + const ly = face.left[1] * canvas.height; + const rx = face.right[0] * canvas.width; + const ry = face.right[1] * canvas.height; + return Math.hypot(rx - lx, ry - ly) || 100; +} + +function pdToFitScale(frameWidthMm, pdMmVal, pdPxVal) { + const pd = Math.max(50, Math.min(80, Number(pdMmVal) || 64)); + const pdPixels = Number(pdPxVal) || 100; + return (Number(frameWidthMm) || 140) / pd * pdPixels * 1.15; +} + +function computePdFromCard(cardPxWidth, pupilPx) { + if (!cardPxWidth || cardPxWidth <= 0) return null; + return Math.round(pupilPx / (cardPxWidth / CARD_WIDTH_MM)); +} + +function toggleCalibration() { + calMode = !calMode; + const btn = document.getElementById("btn-calibrate"); + const info = document.getElementById("cal-info"); + const overlay = document.getElementById("cal-overlay"); + if (calMode) { + btn.classList.add("active"); + btn.textContent = "📏 Exit Calibration"; + info.classList.remove("hidden"); + if (mode === "idle") startDemo(); + updateCalInfo(); + } else { + btn.classList.remove("active"); + btn.textContent = "📏 Calibrate PD"; + info.classList.add("hidden"); + if (overlay) overlay.classList.remove("visible"); + } +} + +function updateCalInfo() { + if (!calMode) return; + const pdPx = measurePdPx(); + const pxPerMm = cardPx / CARD_WIDTH_MM; + const estimatedPd = computePdFromCard(cardPx, pdPx) || pdMm; + const info = document.getElementById("cal-info"); + if (!info) return; + info.innerHTML = + '
Hold a credit card (85.6×54mm) to your forehead. Adjust the slider until the outline matches your card.
' + + 'Calibrate pupil distance for better fit scale
+ +