@jspsych/plugin-tobii-calibration 0.2.0 → 0.2.1
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/index.browser.js +2 -2
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.min.js +2 -2
- package/dist/index.browser.min.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.browser.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var jsPsychTobiiCalibration = (function (jspsych) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var version = "0.2.
|
|
4
|
+
var version = "0.2.1";
|
|
5
5
|
|
|
6
6
|
class CalibrationDisplay {
|
|
7
7
|
constructor(displayElement, params) {
|
|
@@ -823,4 +823,4 @@ var jsPsychTobiiCalibration = (function (jspsych) {
|
|
|
823
823
|
return TobiiCalibrationPlugin;
|
|
824
824
|
|
|
825
825
|
})(jsPsychModule);
|
|
826
|
-
//# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-calibration@0.2.
|
|
826
|
+
//# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-calibration@0.2.1/dist/index.browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.js","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.0\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":["ParameterType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.browser.js","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.1\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":["ParameterType"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var jsPsychTobiiCalibration=function(r){"use strict";var h="0.2.
|
|
1
|
+
var jsPsychTobiiCalibration=function(r){"use strict";var h="0.2.1",u=(p,t,e)=>new Promise((i,o)=>{var n=a=>{try{s(e.next(a))}catch(c){o(c)}},l=a=>{try{s(e.throw(a))}catch(c){o(c)}},s=a=>a.done?i(a.value):Promise.resolve(a.value).then(n,l);s((e=e.apply(p,t)).next())});class x{constructor(t,e){this.displayElement=t,this.params=e,this.currentPoint=null,this.progressElement=null,this.currentX=.5,this.currentY=.5,this.container=this.createContainer(),this.displayElement.appendChild(this.container),e.show_progress&&(this.progressElement=this.createProgressIndicator(),this.displayElement.appendChild(this.progressElement))}createContainer(){const t=document.createElement("div");return t.className="tobii-calibration-container",t}createProgressIndicator(){const t=document.createElement("div");return t.className="tobii-calibration-progress",t.setAttribute("role","status"),t.setAttribute("aria-live","polite"),t}showInstructions(){return u(this,null,function*(){const t=document.createElement("div");t.className="tobii-calibration-instructions",t.setAttribute("role","dialog"),t.setAttribute("aria-label","Eye tracker calibration instructions");const e=document.createElement("div");e.className="instructions-content";const i=document.createElement("h2");i.textContent="Eye Tracker Calibration",e.appendChild(i);const o=document.createElement("p");o.innerHTML=this.params.instructions||"Look at each point and follow the instructions.",e.appendChild(o);const n=document.createElement("button");return n.className="calibration-start-btn",n.textContent=this.params.button_text||"Start Calibration",e.appendChild(n),t.appendChild(e),this.container.appendChild(t),new Promise(l=>{n.addEventListener("click",()=>{t.remove(),l()})})})}initializePoint(){return u(this,null,function*(){if(this.currentPoint)return;this.currentPoint=document.createElement("div"),this.currentPoint.className="tobii-calibration-point",this.currentPoint.setAttribute("role","img"),this.currentPoint.setAttribute("aria-label","Calibration target point");const t=.5*window.innerWidth,e=.5*window.innerHeight;this.currentX=.5,this.currentY=.5,Object.assign(this.currentPoint.style,{left:`${t}px`,top:`${e}px`,width:`${this.params.point_size||20}px`,height:`${this.params.point_size||20}px`,backgroundColor:this.params.point_color||"#ff0000",transition:"none"}),this.container.appendChild(this.currentPoint),yield this.delay(this.params.zoom_duration||300)})}travelToPoint(t,e,i){return u(this,null,function*(){this.currentPoint||(yield this.initializePoint()),this.progressElement&&(this.progressElement.textContent=`Point ${e+1} of ${i}`),this.currentPoint.setAttribute("aria-label",`Calibration target point ${e+1} of ${i}`);const o=t.x-this.currentX,n=t.y-this.currentY,l=Math.sqrt(o*o+n*n),s=Math.max(150,Math.min(400,150+l*200)),a=t.x*window.innerWidth,c=t.y*window.innerHeight;this.currentPoint.style.transition=`left ${s}ms ease-in-out, top ${s}ms ease-in-out`,this.currentPoint.classList.remove("animation-explosion","animation-shrink","animation-pulse","animation-zoom-out","animation-zoom-in"),this.currentPoint.style.left=`${a}px`,this.currentPoint.style.top=`${c}px`,this.currentX=t.x,this.currentY=t.y,yield this.delay(s)})}playZoomOut(){return u(this,null,function*(){this.currentPoint&&(this.currentPoint.style.transition="none",this.currentPoint.classList.remove("animation-shrink","animation-pulse","animation-explosion","animation-zoom-in"),this.currentPoint.classList.add("animation-zoom-out"),yield this.delay(this.params.zoom_duration||300))})}playZoomIn(){return u(this,null,function*(){this.currentPoint&&(this.currentPoint.classList.remove("animation-zoom-out"),this.currentPoint.classList.add("animation-zoom-in"),yield this.delay(this.params.zoom_duration||300))})}playExplosion(t){return u(this,null,function*(){this.currentPoint&&(this.currentPoint.classList.remove("animation-pulse","animation-shrink"),this.currentPoint.classList.add("animation-explosion"),t?this.currentPoint.style.backgroundColor="#4ade80":this.currentPoint.style.backgroundColor="#f87171",yield this.delay(this.params.explosion_duration||400))})}hidePoint(){return u(this,null,function*(){this.currentPoint&&(this.currentPoint.remove(),this.currentPoint=null),yield this.delay(200)})}resetPointAfterExplosion(){return u(this,null,function*(){this.currentPoint&&(this.currentPoint.classList.remove("animation-explosion"),this.currentPoint.style.transform="translate(-50%, -50%) scale(1)",this.currentPoint.style.opacity="1",this.currentPoint.style.backgroundColor=this.params.point_color||"#ff0000",yield this.delay(50))})}waitForClick(){return new Promise(t=>{const e=()=>{document.removeEventListener("click",e),t()};document.addEventListener("click",e)})}showResult(t,e=!1){return u(this,null,function*(){const i=document.createElement("div");if(i.className="tobii-calibration-result",i.setAttribute("role","alert"),i.setAttribute("aria-live","assertive"),t)return i.innerHTML=`
|
|
2
2
|
<div class="tobii-calibration-result-content success">
|
|
3
3
|
<h2>Calibration Successful!</h2>
|
|
4
4
|
<p>Continuing automatically...</p>
|
|
@@ -206,4 +206,4 @@ var jsPsychTobiiCalibration=function(r){"use strict";var h="0.2.0",u=(p,t,e)=>ne
|
|
|
206
206
|
color: #666;
|
|
207
207
|
}
|
|
208
208
|
`,i=document.createElement("style");i.id="tobii-calibration-styles",i.textContent=e,document.head.appendChild(i)}trial(t,e){return f(this,null,function*(){this.injectStyles(e);const i=this.jsPsych.extensions.tobii;if(!i)throw new Error("Tobii extension not initialized");if(!i.isConnected())throw new Error("Not connected to Tobii server");const o=new x(t,e);yield o.showInstructions();let n;e.custom_points?n=this.validateCustomPoints(e.custom_points):n=this.getCalibrationPoints(e.calibration_points);const l=1+e.max_retries;let s=0,a={success:!1};try{for(;s<l;){s++;const g=l-s;yield i.startCalibration(),yield o.initializePoint();for(let y=0;y<n.length;y++){const d=n[y];yield o.travelToPoint(d,y,n.length),yield o.playZoomOut(),yield o.playZoomIn(),e.calibration_mode==="click"?yield o.waitForClick():yield this.delay(e.point_duration);const _=yield i.collectCalibrationPoint(d.x,d.y);yield o.playExplosion(_.success),y<n.length-1&&(yield o.resetPointAfterExplosion())}if(yield o.hidePoint(),a=yield i.computeCalibration(),(yield o.showResult(a.success,g>0))==="continue")break;o.resetForRetry()}}finally{o.clear(),t.innerHTML="",m.removeStyles()}const c={calibration_success:a.success,num_points:n.length,mode:e.calibration_mode,calibration_data:a,num_attempts:s};this.jsPsych.finishTrial(c)})}validateCustomPoints(t){if(!Array.isArray(t)||t.length===0)throw new Error("custom_points must be a non-empty array");const e=[];for(let i=0;i<t.length;i++){const o=t[i];if(typeof o!="object"||o===null)throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);const n=o;if(typeof n.x!="number"||typeof n.y!="number")throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);if(n.x<0||n.x>1||n.y<0||n.y>1)throw new Error(`Calibration point at index ${i} out of range: x and y must be between 0 and 1`);e.push({x:n.x,y:n.y})}return e}getCalibrationPoints(t){switch(t){case 5:return[{x:.1,y:.1},{x:.9,y:.1},{x:.5,y:.5},{x:.1,y:.9},{x:.9,y:.9}];case 9:return[{x:.1,y:.1},{x:.5,y:.1},{x:.9,y:.1},{x:.1,y:.5},{x:.5,y:.5},{x:.9,y:.5},{x:.1,y:.9},{x:.5,y:.9},{x:.9,y:.9}];case 13:return[{x:.1,y:.1},{x:.5,y:.1},{x:.9,y:.1},{x:.3,y:.3},{x:.7,y:.3},{x:.1,y:.5},{x:.5,y:.5},{x:.9,y:.5},{x:.3,y:.7},{x:.7,y:.7},{x:.1,y:.9},{x:.5,y:.9},{x:.9,y:.9}];case 15:return[{x:.1,y:.1},{x:.5,y:.1},{x:.9,y:.1},{x:.1,y:.3},{x:.5,y:.3},{x:.9,y:.3},{x:.1,y:.5},{x:.5,y:.5},{x:.9,y:.5},{x:.1,y:.7},{x:.5,y:.7},{x:.9,y:.7},{x:.1,y:.9},{x:.5,y:.9},{x:.9,y:.9}];case 19:return[{x:.1,y:.1},{x:.5,y:.1},{x:.9,y:.1},{x:.1,y:.3},{x:.3,y:.3},{x:.5,y:.3},{x:.7,y:.3},{x:.9,y:.3},{x:.1,y:.5},{x:.5,y:.5},{x:.9,y:.5},{x:.1,y:.7},{x:.3,y:.7},{x:.5,y:.7},{x:.7,y:.7},{x:.9,y:.7},{x:.1,y:.9},{x:.5,y:.9},{x:.9,y:.9}];case 25:return[{x:.1,y:.1},{x:.3,y:.1},{x:.5,y:.1},{x:.7,y:.1},{x:.9,y:.1},{x:.1,y:.3},{x:.3,y:.3},{x:.5,y:.3},{x:.7,y:.3},{x:.9,y:.3},{x:.1,y:.5},{x:.3,y:.5},{x:.5,y:.5},{x:.7,y:.5},{x:.9,y:.5},{x:.1,y:.7},{x:.3,y:.7},{x:.5,y:.7},{x:.7,y:.7},{x:.9,y:.7},{x:.1,y:.9},{x:.3,y:.9},{x:.5,y:.9},{x:.7,y:.9},{x:.9,y:.9}];default:throw new Error(`Unsupported calibration_points value: ${t}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`)}}delay(t){return new Promise(e=>setTimeout(e,t))}};return b.info=P,b}(jsPsychModule);
|
|
209
|
-
//# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-calibration@0.2.
|
|
209
|
+
//# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-calibration@0.2.1/dist/index.browser.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.min.js","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.0\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":["version","o","u","i","n","s","e","c","r","l","a","CalibrationDisplay","displayElement","params","container","progress","__async","wrapper","content","heading","paragraph","button","resolve","x","y","point","index","total","dx","dy","distance","travelDuration","success","handleClick","canRetry","result","buttonsHTML","retryBtn","continueBtn","ms","info","ParameterType","_TobiiCalibrationPlugin","jsPsych","el","trial","css","styleElement","display_element","tobiiExt","calibrationDisplay","points","maxAttempts","attempt","calibrationResult","retriesRemaining","trial_data","validated","p","count"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.browser.min.js","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.1\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":["version","o","u","i","n","s","e","c","r","l","a","CalibrationDisplay","displayElement","params","container","progress","__async","wrapper","content","heading","paragraph","button","resolve","x","y","point","index","total","dx","dy","distance","travelDuration","success","handleClick","canRetry","result","buttonsHTML","retryBtn","continueBtn","ms","info","ParameterType","_TobiiCalibrationPlugin","jsPsych","el","trial","css","styleElement","display_element","tobiiExt","calibrationDisplay","points","maxAttempts","attempt","calibrationResult","retriesRemaining","trial_data","validated","p","count"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.0\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":["ParameterType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.1\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":["ParameterType"],"mappings":"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"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.0\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.1.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../package.json","../src/calibration-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-calibration\",\n \"version\": \"0.2.1\",\n \"description\": \"jsPsych plugin for Tobii eye tracker calibration\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/jspsych/jspsych-tobii.git\",\n \"directory\": \"packages/plugin-tobii-calibration\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"calibration\"\n ],\n \"author\": {\n \"name\": \"Josh de Leeuw\",\n \"url\": \"https://github.com/jodeleeuw\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jspsych-tobii/issues\"\n },\n \"homepage\": \"https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme\",\n \"peerDependencies\": {\n \"jspsych\": \">=8.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.2\",\n \"@jspsych/test-utils\": \"^1.0.0\",\n \"@jspsych/extension-tobii\": \"^0.2.1\",\n \"jspsych\": \"^8.0.0\"\n }\n}\n","/**\n * Calibration display component\n */\nexport class CalibrationDisplay {\n constructor(displayElement, params) {\n this.displayElement = displayElement;\n this.params = params;\n this.currentPoint = null;\n this.progressElement = null;\n this.currentX = 0.5; // Start at center\n this.currentY = 0.5;\n this.container = this.createContainer();\n this.displayElement.appendChild(this.container);\n if (params.show_progress) {\n this.progressElement = this.createProgressIndicator();\n this.displayElement.appendChild(this.progressElement);\n }\n }\n /**\n * Create container element\n */\n createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-calibration-container';\n return container;\n }\n /**\n * Create progress indicator\n */\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-calibration-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n /**\n * Show instructions\n */\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-calibration-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker calibration instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Calibration';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point and follow the instructions.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'calibration-start-btn';\n button.textContent = this.params.button_text || 'Start Calibration';\n content.appendChild(button);\n wrapper.appendChild(content);\n this.container.appendChild(wrapper);\n return new Promise((resolve) => {\n button.addEventListener('click', () => {\n wrapper.remove();\n resolve();\n });\n });\n }\n /**\n * Initialize the traveling point at screen center\n */\n async initializePoint() {\n if (this.currentPoint)\n return;\n this.currentPoint = document.createElement('div');\n this.currentPoint.className = 'tobii-calibration-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Calibration target point');\n // Start at center\n const x = 0.5 * window.innerWidth;\n const y = 0.5 * window.innerHeight;\n this.currentX = 0.5;\n this.currentY = 0.5;\n Object.assign(this.currentPoint.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${this.params.point_size || 20}px`,\n height: `${this.params.point_size || 20}px`,\n backgroundColor: this.params.point_color || '#ff0000',\n transition: 'none',\n });\n this.container.appendChild(this.currentPoint);\n // Brief pause to show point at center before traveling\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Travel to the next point location with smooth animation\n */\n async travelToPoint(point, index, total) {\n if (!this.currentPoint) {\n await this.initializePoint();\n }\n // Update progress\n if (this.progressElement) {\n this.progressElement.textContent = `Point ${index + 1} of ${total}`;\n }\n // Update aria-label with current point number\n this.currentPoint.setAttribute('aria-label', `Calibration target point ${index + 1} of ${total}`);\n // Calculate travel distance for dynamic duration\n const dx = point.x - this.currentX;\n const dy = point.y - this.currentY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n // Travel duration: 150ms base + 200ms per normalized unit distance (quick travel)\n const travelDuration = Math.max(150, Math.min(400, 150 + distance * 200));\n // Convert normalized coordinates to pixels\n const x = point.x * window.innerWidth;\n const y = point.y * window.innerHeight;\n // Set up travel transition\n this.currentPoint.style.transition = `left ${travelDuration}ms ease-in-out, top ${travelDuration}ms ease-in-out`;\n this.currentPoint.classList.remove('animation-explosion', 'animation-shrink', 'animation-pulse', 'animation-zoom-out', 'animation-zoom-in');\n // Move to new position\n this.currentPoint.style.left = `${x}px`;\n this.currentPoint.style.top = `${y}px`;\n // Update current position\n this.currentX = point.x;\n this.currentY = point.y;\n // Wait for travel to complete\n await this.delay(travelDuration);\n }\n /**\n * Play zoom out animation (point grows larger)\n */\n async playZoomOut() {\n if (!this.currentPoint)\n return;\n this.currentPoint.style.transition = 'none';\n this.currentPoint.classList.remove('animation-shrink', 'animation-pulse', 'animation-explosion', 'animation-zoom-in');\n this.currentPoint.classList.add('animation-zoom-out');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play zoom in animation (point shrinks to fixation size)\n */\n async playZoomIn() {\n if (!this.currentPoint)\n return;\n this.currentPoint.classList.remove('animation-zoom-out');\n this.currentPoint.classList.add('animation-zoom-in');\n await this.delay(this.params.zoom_duration || 300);\n }\n /**\n * Play explosion animation on the current point\n */\n async playExplosion(success) {\n if (!this.currentPoint)\n return;\n // Remove any existing animation classes\n this.currentPoint.classList.remove('animation-pulse', 'animation-shrink');\n // Add explosion animation class\n this.currentPoint.classList.add('animation-explosion');\n // Change color based on success\n if (success) {\n this.currentPoint.style.backgroundColor = '#4ade80'; // green\n }\n else {\n this.currentPoint.style.backgroundColor = '#f87171'; // red\n }\n // Wait for animation to complete\n await this.delay(this.params.explosion_duration || 400);\n }\n /**\n * Hide current calibration point (removes element)\n */\n async hidePoint() {\n if (this.currentPoint) {\n this.currentPoint.remove();\n this.currentPoint = null;\n }\n await this.delay(200);\n }\n /**\n * Reset point state after explosion (keeps element for continued travel)\n */\n async resetPointAfterExplosion() {\n if (!this.currentPoint)\n return;\n // Reset to normal size and opacity for next travel\n this.currentPoint.classList.remove('animation-explosion');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n this.currentPoint.style.opacity = '1';\n this.currentPoint.style.backgroundColor = this.params.point_color || '#ff0000';\n await this.delay(50);\n }\n /**\n * Wait for user click (in click mode)\n */\n waitForClick() {\n return new Promise((resolve) => {\n const handleClick = () => {\n document.removeEventListener('click', handleClick);\n resolve();\n };\n document.addEventListener('click', handleClick);\n });\n }\n /**\n * Show calibration result\n * @param success Whether calibration succeeded\n * @param canRetry Whether a retry button should be shown on failure\n * @returns 'retry' if user chose to retry, 'continue' otherwise\n */\n async showResult(success, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-calibration-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n if (success) {\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content success\">\n <h2>Calibration Successful!</h2>\n <p>Continuing automatically...</p>\n </div>\n `;\n this.container.appendChild(result);\n // Auto-advance after showing result\n await this.delay(this.params.success_display_duration || 2000);\n result.remove();\n return 'continue';\n }\n // Failure case: show buttons\n const buttonsHTML = canRetry\n ? `<button class=\"calibration-retry-btn\">Retry</button>\n <button class=\"calibration-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`\n : `<button class=\"calibration-continue-btn\">Continue</button>`;\n result.innerHTML = `\n <div class=\"tobii-calibration-result-content error\">\n <h2>Calibration Failed</h2>\n <p>Please try again or continue.</p>\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.calibration-retry-btn');\n const continueBtn = result.querySelector('.calibration-continue-btn');\n retryBtn?.addEventListener('click', () => {\n result.remove();\n resolve('retry');\n });\n continueBtn?.addEventListener('click', () => {\n result.remove();\n resolve('continue');\n });\n });\n }\n /**\n * Reset display state for a retry attempt\n */\n resetForRetry() {\n this.container.innerHTML = '';\n this.currentPoint = null;\n this.currentX = 0.5;\n this.currentY = 0.5;\n }\n /**\n * Clear display\n */\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n /**\n * Delay helper\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=calibration-display.js.map","/**\n * @title Tobii Calibration\n * @description jsPsych plugin for Tobii eye tracker calibration. Provides a visual\n * calibration procedure with animated points and real-time feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme Documentation}\n */\n\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from 'jspsych';\nimport { version } from '../package.json';\nimport type TobiiExtension from '@jspsych/extension-tobii';\nimport type { CalibrationResult } from '@jspsych/extension-tobii';\nimport { CalibrationDisplay } from './calibration-display';\nimport type { CalibrationParameters, CalibrationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-calibration',\n version: version,\n parameters: {\n /** Number of calibration points (5 or 9) */\n calibration_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Calibration mode: click or view */\n calibration_mode: {\n type: ParameterType.STRING,\n default: 'view',\n },\n /** Size of calibration points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of calibration points */\n point_color: {\n type: ParameterType.STRING,\n default: '#ff0000',\n },\n /** Duration to show each point before data collection (ms) - allows user to fixate */\n point_duration: {\n type: ParameterType.INT,\n default: 500,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom calibration points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default:\n 'Look at each point as it appears on the screen. Keep your gaze fixed on each point until it disappears.',\n },\n /** Button text for click mode */\n button_text: {\n type: ParameterType.STRING,\n default: 'Start Calibration',\n },\n /** Background color of the calibration container */\n background_color: {\n type: ParameterType.STRING,\n default: '#808080',\n },\n /** Primary button color */\n button_color: {\n type: ParameterType.STRING,\n default: '#007bff',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#0056b3',\n },\n /** Retry button color */\n retry_button_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Retry button hover color */\n retry_button_hover_color: {\n type: ParameterType.STRING,\n default: '#c82333',\n },\n /** Success message color */\n success_color: {\n type: ParameterType.STRING,\n default: '#28a745',\n },\n /** Error message color */\n error_color: {\n type: ParameterType.STRING,\n default: '#dc3545',\n },\n /** Maximum number of retry attempts allowed on calibration failure */\n max_retries: {\n type: ParameterType.INT,\n default: 1,\n },\n /** Duration of zoom in/out animations in ms */\n zoom_duration: {\n type: ParameterType.INT,\n default: 300,\n },\n /** Duration of explosion animation in ms */\n explosion_duration: {\n type: ParameterType.INT,\n default: 400,\n },\n /** Duration to show success result before auto-advancing in ms */\n success_display_duration: {\n type: ParameterType.INT,\n default: 2000,\n },\n },\n data: {\n /** Calibration success status */\n calibration_success: {\n type: ParameterType.BOOL,\n },\n /** Number of calibration points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Calibration mode used */\n mode: {\n type: ParameterType.STRING,\n },\n /** Full calibration result data */\n calibration_data: {\n type: ParameterType.COMPLEX,\n },\n /** Number of calibration attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiCalibrationPlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n private static removeStyles(): void {\n const el = document.getElementById('tobii-calibration-styles');\n if (el) {\n el.remove();\n }\n }\n\n private injectStyles(trial: TrialType<Info>): void {\n // Remove existing styles so each trial gets its own colors\n TobiiCalibrationPlugin.removeStyles();\n\n const css = `\n .tobii-calibration-container {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: ${trial.background_color};\n font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n z-index: 9999;\n cursor: none;\n }\n\n .tobii-calibration-instructions {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n max-width: 600px;\n cursor: auto;\n }\n\n .tobii-calibration-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-calibration-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .calibration-start-btn,\n .calibration-continue-btn,\n .calibration-retry-btn {\n background-color: ${trial.button_color};\n color: white;\n border: none;\n padding: 12px 30px;\n font-size: 16px;\n border-radius: 5px;\n cursor: pointer;\n transition: background-color 0.3s;\n }\n\n .calibration-start-btn:hover,\n .calibration-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .calibration-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .calibration-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-calibration-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-calibration-point.animation-pulse {\n animation: tobii-calibration-pulse 1s infinite;\n }\n\n @keyframes tobii-calibration-pulse {\n 0%, 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(1.2);\n opacity: 0.8;\n }\n }\n\n .tobii-calibration-point.animation-shrink {\n animation: tobii-calibration-shrink 1s ease-out;\n }\n\n @keyframes tobii-calibration-shrink {\n 0% {\n transform: translate(-50%, -50%) scale(3);\n opacity: 0.5;\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n }\n\n .tobii-calibration-point.animation-explosion {\n animation: tobii-calibration-explosion ${(trial.explosion_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-explosion {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n 50% {\n transform: translate(-50%, -50%) scale(2);\n opacity: 0.8;\n }\n 100% {\n transform: translate(-50%, -50%) scale(0);\n opacity: 0;\n }\n }\n\n .tobii-calibration-point.animation-zoom-out {\n animation: tobii-calibration-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-out {\n 0% {\n transform: translate(-50%, -50%) scale(1);\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n }\n\n .tobii-calibration-point.animation-zoom-in {\n animation: tobii-calibration-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-calibration-zoom-in {\n 0% {\n transform: translate(-50%, -50%) scale(2.5);\n }\n 100% {\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .tobii-calibration-progress {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 10px 20px;\n border-radius: 5px;\n font-size: 14px;\n z-index: 10000;\n }\n\n .tobii-calibration-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n cursor: auto;\n }\n\n .tobii-calibration-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-calibration-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-calibration-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-calibration-result-content p {\n margin-bottom: 20px;\n font-size: 16px;\n color: #666;\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-calibration-styles';\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>): Promise<void> {\n // Inject styles\n this.injectStyles(trial);\n // Get extension instance\n const tobiiExt = this.jsPsych.extensions.tobii as unknown as TobiiExtension;\n\n if (!tobiiExt) {\n throw new Error('Tobii extension not initialized');\n }\n\n // Check connection\n if (!tobiiExt.isConnected()) {\n throw new Error('Not connected to Tobii server');\n }\n\n // Create calibration display\n const calibrationDisplay = new CalibrationDisplay(\n display_element,\n trial as unknown as CalibrationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await calibrationDisplay.showInstructions();\n\n // Get calibration points and validate custom points\n let points: CalibrationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getCalibrationPoints(trial.calibration_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let calibrationResult: CalibrationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start calibration on server (resets server-side state on each call)\n await tobiiExt.startCalibration();\n\n // Initialize point at screen center (with brief pause)\n await calibrationDisplay.initializePoint();\n\n // Show each point and collect calibration data with smooth path animation\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n\n // Travel to the point location (smooth animation from current position)\n await calibrationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await calibrationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await calibrationDisplay.playZoomIn();\n\n if (trial.calibration_mode === 'click') {\n // Wait for user to click\n await calibrationDisplay.waitForClick();\n } else {\n // Wait for user to fixate on the point\n await this.delay(trial.point_duration!);\n }\n\n // Collect calibration data for this point (blocks until SDK finishes)\n const result = await tobiiExt.collectCalibrationPoint(point.x, point.y);\n\n // Play explosion animation based on result\n await calibrationDisplay.playExplosion(result.success);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await calibrationDisplay.resetPointAfterExplosion();\n }\n }\n\n // Hide point after final explosion\n await calibrationDisplay.hidePoint();\n\n // Compute calibration on server\n calibrationResult = await tobiiExt.computeCalibration();\n\n // Show result with retry option if retries remain\n const userChoice = await calibrationDisplay.showResult(\n calibrationResult.success,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n calibrationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n calibrationDisplay.clear();\n display_element.innerHTML = '';\n TobiiCalibrationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n calibration_success: calibrationResult.success,\n num_points: points.length,\n mode: trial.calibration_mode,\n calibration_data: calibrationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom calibration points\n */\n private validateCustomPoints(points: unknown[]): CalibrationPoint[] {\n if (!Array.isArray(points) || points.length === 0) {\n throw new Error('custom_points must be a non-empty array');\n }\n\n const validated: CalibrationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i];\n if (typeof point !== 'object' || point === null) {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n const p = point as Record<string, unknown>;\n if (typeof p.x !== 'number' || typeof p.y !== 'number') {\n throw new Error(`Invalid calibration point at index ${i}: must have numeric x and y`);\n }\n if (p.x < 0 || p.x > 1 || p.y < 0 || p.y > 1) {\n throw new Error(\n `Calibration point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: p.x, y: p.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard calibration points for the given grid size\n */\n private getCalibrationPoints(count: number): CalibrationPoint[] {\n switch (count) {\n case 5:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.5, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 9:\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 13:\n // 3x3 outer grid + 4 diagonal midpoints\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.3, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.3, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 15:\n // 5 rows x 3 columns\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 19:\n // Symmetric 3-5-3-5-3 pattern\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n case 25:\n // 5x5 full grid\n return [\n { x: 0.1, y: 0.1 },\n { x: 0.3, y: 0.1 },\n { x: 0.5, y: 0.1 },\n { x: 0.7, y: 0.1 },\n { x: 0.9, y: 0.1 },\n { x: 0.1, y: 0.3 },\n { x: 0.3, y: 0.3 },\n { x: 0.5, y: 0.3 },\n { x: 0.7, y: 0.3 },\n { x: 0.9, y: 0.3 },\n { x: 0.1, y: 0.5 },\n { x: 0.3, y: 0.5 },\n { x: 0.5, y: 0.5 },\n { x: 0.7, y: 0.5 },\n { x: 0.9, y: 0.5 },\n { x: 0.1, y: 0.7 },\n { x: 0.3, y: 0.7 },\n { x: 0.5, y: 0.7 },\n { x: 0.7, y: 0.7 },\n { x: 0.9, y: 0.7 },\n { x: 0.1, y: 0.9 },\n { x: 0.3, y: 0.9 },\n { x: 0.5, y: 0.9 },\n { x: 0.7, y: 0.9 },\n { x: 0.9, y: 0.9 },\n ];\n default:\n throw new Error(\n `Unsupported calibration_points value: ${count}. Use 5, 9, 13, 15, 19, or 25, or provide custom_points.`\n );\n }\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nexport default TobiiCalibrationPlugin;\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jspsych/plugin-tobii-calibration",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "jsPsych plugin for Tobii eye tracker calibration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"homepage": "https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-calibration#readme",
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"jspsych": ">=8.0.0",
|
|
46
|
-
"@jspsych/extension-tobii": "^0.1
|
|
46
|
+
"@jspsych/extension-tobii": "^0.2.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@jspsych/config": "^3.2.2",
|
|
50
50
|
"@jspsych/test-utils": "^1.0.0",
|
|
51
|
-
"@jspsych/extension-tobii": "^0.
|
|
51
|
+
"@jspsych/extension-tobii": "^0.2.1",
|
|
52
52
|
"jspsych": "^8.0.0"
|
|
53
53
|
}
|
|
54
54
|
}
|