Calibration Example
A complete calibration flow using both the CalibrationScreen component and the useCalibration hook.
Using CalibrationScreen (Drop-in Component)
The easiest approach — CalibrationScreen handles everything automatically:
tsx
import { useState } from 'react';
import { WebgazerProvider, CalibrationScreen } from '@webgazer-ts/react';
import type { CalibrationResult } from '@webgazer-ts/react';
function App() {
const [calibrated, setCalibrated] = useState(false);
return (
<WebgazerProvider autoStart>
{!calibrated ? (
<CalibrationScreen
pointCount={9}
pointDuration={1500}
autoAdvance={true}
onComplete={(result: CalibrationResult) => {
console.log(`Calibrated ${result.pointsCalibrated} points`);
setCalibrated(true);
}}
onCancel={() => console.log('Cancelled')}
theme={{
backgroundColor: 'rgba(0,0,0,0.9)',
pointColor: '#6366f1',
progressColor: '#22c55e',
textColor: '#ffffff',
}}
/>
) : (
<TrackingUI onRecalibrate={() => setCalibrated(false)} />
)}
</WebgazerProvider>
);
}Using useCalibration (Full Control)
For custom calibration UIs, use the hook directly:
tsx
import { useCalibration } from '@webgazer-ts/react';
function MyCalibrationUI() {
const {
isCalibrating,
progress, // 0–100
currentPoint, // { x, y, index } | null
startCalibration,
stopCalibration,
nextPoint, // Manually advance (when autoAdvance: false)
} = useCalibration({
pointCount: 9,
pointDuration: 1500, // ms per point when autoAdvance is on
autoAdvance: true,
onComplete: (result) => {
console.log('Done!', result.pointsCalibrated, 'points');
},
onPointComplete: (index) => {
console.log(`Point ${index} done`);
},
});
return (
<div style={{ position: 'fixed', inset: 0, background: '#000' }}>
{/* Progress bar */}
<div style={{ position: 'absolute', top: 20, left: '50%', transform: 'translateX(-50%)' }}>
<progress value={progress} max={100} />
<span>{progress}%</span>
</div>
{/* Active calibration point */}
{currentPoint && (
<div
style={{
position: 'absolute',
left: currentPoint.x,
top: currentPoint.y,
width: 20,
height: 20,
background: 'red',
borderRadius: '50%',
transform: 'translate(-50%, -50%)',
}}
onClick={nextPoint} // In manual mode: click to advance
/>
)}
{/* Controls */}
{!isCalibrating ? (
<button onClick={startCalibration}>Start</button>
) : (
<button onClick={stopCalibration}>Cancel</button>
)}
</div>
);
}Click-to-Advance (Manual Mode)
Disable auto-advance and let the user click on each point:
tsx
const calibration = useCalibration({
pointCount: 9,
autoAdvance: false, // User must click each point
onComplete: (r) => setCalibrated(true),
});
// In your render:
{currentPoint && (
<CalibrationDot
x={currentPoint.x}
y={currentPoint.y}
onClick={() => {
// Record the point click to webgazer
webgazer.recordScreenPosition(currentPoint.x, currentPoint.y, 'click');
nextPoint();
}}
/>
)}Vanilla JS Calibration
Without React, use webgazer.recordScreenPosition() directly. Each click on a known screen location trains the regressor:
html
<!DOCTYPE html>
<html>
<body>
<script src="https://unpkg.com/@webgazer-ts/core@latest/dist/webgazer.js"></script>
<script>
const points = [
[10, 10], [50, 10], [90, 10],
[10, 50], [50, 50], [90, 50],
[10, 90], [50, 90], [90, 90],
].map(([xPct, yPct]) => ({
x: Math.round(window.innerWidth * xPct / 100),
y: Math.round(window.innerHeight * yPct / 100),
}));
let idx = 0;
const dot = document.createElement('div');
dot.style.cssText = `
position: fixed; width: 20px; height: 20px;
background: red; border-radius: 50%;
transform: translate(-50%, -50%); cursor: pointer;
`;
document.body.appendChild(dot);
function showPoint() {
if (idx >= points.length) {
dot.remove();
console.log('Calibration complete!');
return;
}
dot.style.left = points[idx].x + 'px';
dot.style.top = points[idx].y + 'px';
}
dot.onclick = () => {
webgazer.recordScreenPosition(points[idx].x, points[idx].y, 'click');
idx++;
showPoint();
};
webgazer.begin().then(showPoint);
</script>
</body>
</html>Saving Calibration Across Sessions
typescript
webgazer.saveDataAcrossSessions(true);When enabled, regression training data is persisted in IndexedDB (via LocalForage) and restored automatically on the next begin() call. Users won't need to re-calibrate on every page load.
To clear stored data:
typescript
await webgazer.clearData();