@jspsych/plugin-tobii-validation 0.1.1 → 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.
@@ -1,7 +1,7 @@
1
1
  var jsPsychTobiiValidation = (function (jspsych) {
2
2
  'use strict';
3
3
 
4
- var version = "0.1.1";
4
+ var version = "0.2.1";
5
5
 
6
6
  class ValidationDisplay {
7
7
  constructor(displayElement, params) {
@@ -321,7 +321,7 @@ var jsPsychTobiiValidation = (function (jspsych) {
321
321
  /** Show progress indicator */
322
322
  show_progress: {
323
323
  type: jspsych.ParameterType.BOOL,
324
- default: true
324
+ default: false
325
325
  },
326
326
  /** Custom validation points */
327
327
  custom_points: {
@@ -445,6 +445,7 @@ var jsPsychTobiiValidation = (function (jspsych) {
445
445
  background-color: ${trial.background_color};
446
446
  font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
447
447
  z-index: 9999;
448
+ cursor: none;
448
449
  }
449
450
 
450
451
  .tobii-validation-instructions {
@@ -458,6 +459,7 @@ var jsPsychTobiiValidation = (function (jspsych) {
458
459
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
459
460
  text-align: center;
460
461
  max-width: 600px;
462
+ cursor: auto;
461
463
  }
462
464
 
463
465
  .tobii-validation-instructions h2 {
@@ -560,6 +562,7 @@ var jsPsychTobiiValidation = (function (jspsych) {
560
562
  max-width: 800px;
561
563
  max-height: 85vh;
562
564
  overflow-y: auto;
565
+ cursor: auto;
563
566
  }
564
567
 
565
568
  .tobii-validation-result-content h2 {
@@ -1000,4 +1003,4 @@ var jsPsychTobiiValidation = (function (jspsych) {
1000
1003
  return TobiiValidationPlugin;
1001
1004
 
1002
1005
  })(jsPsychModule);
1003
- //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-validation@0.1.1/dist/index.browser.js.map
1006
+ //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-validation@0.2.1/dist/index.browser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","sources":["../package.json","../src/validation-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-validation\",\n \"version\": \"0.1.1\",\n \"description\": \"jsPsych plugin for Tobii eye tracker validation\",\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-validation\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"validation\"\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-validation#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 * Validation display component\n */\nexport class ValidationDisplay {\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 createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-validation-container';\n return container;\n }\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-validation-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-validation-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker validation instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Validation';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point to validate calibration accuracy.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'validation-start-btn';\n button.textContent = 'Start Validation';\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-validation-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Validation 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 || '#00ff00',\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', `Validation 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-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-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 * Reset point state after data collection (keeps element for continued travel)\n */\n async resetPointForTravel() {\n if (!this.currentPoint)\n return;\n // Reset to normal size for next travel\n this.currentPoint.classList.remove('animation-zoom-out', 'animation-zoom-in');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n await this.delay(50);\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 * Show validation result\n * @param success Whether validation passed\n * @param averageAccuracyNorm Average accuracy in normalized units\n * @param averagePrecisionNorm Average precision in normalized units\n * @param pointData Per-point validation data\n * @param tolerance Tolerance threshold\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, averageAccuracyNorm, _averagePrecisionNorm, pointData, tolerance, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-validation-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n let feedbackHTML = '';\n if (this.params.show_feedback && pointData) {\n feedbackHTML = this.createVisualFeedback(pointData, tolerance);\n }\n const statusClass = success ? 'success' : 'error';\n const statusText = success ? 'Validation Passed' : 'Validation Failed';\n let buttonsHTML;\n if (success) {\n buttonsHTML = `<button class=\"validation-continue-btn\">Continue</button>`;\n }\n else if (canRetry) {\n buttonsHTML = `<button class=\"validation-retry-btn\">Retry</button>\n <button class=\"validation-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`;\n }\n else {\n buttonsHTML = `<button class=\"validation-continue-btn\">Continue</button>`;\n }\n result.innerHTML = `\n <div class=\"tobii-validation-result-content ${statusClass}\">\n <h2>${statusText}</h2>\n <p>Average error: ${((averageAccuracyNorm || 0) * 100).toFixed(1)}% (tolerance: ${((tolerance || 0) * 100).toFixed(0)}%)</p>\n ${feedbackHTML}\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.validation-retry-btn');\n const continueBtn = result.querySelector('.validation-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 createVisualFeedback(pointData, tolerance) {\n const tol = tolerance || 0.05;\n // Create full-screen visualization showing actual screen positions\n const targetMarkers = pointData\n .map((data, idx) => {\n const x = data.point.x * 100;\n const y = data.point.y * 100;\n return `\n <div class=\"feedback-target\" style=\"\n left: ${x}%;\n top: ${y}%;\n \" title=\"Target ${idx + 1}\">\n <span class=\"target-label\">${idx + 1}</span>\n </div>\n `;\n })\n .join('');\n // Mean gaze positions - color coded based on tolerance with non-color indicators\n const gazeMarkers = pointData\n .map((data, idx) => {\n if (!data.meanGaze)\n return '';\n const x = data.meanGaze.x * 100;\n const y = data.meanGaze.y * 100;\n const withinTolerance = data.accuracyNorm <= tol;\n const colorClass = withinTolerance ? 'gaze-pass' : 'gaze-fail';\n const statusSymbol = withinTolerance ? '\\u2713' : '\\u2717';\n const statusLabel = withinTolerance ? 'pass' : 'fail';\n return `\n <div class=\"feedback-gaze ${colorClass}\" style=\"\n left: ${x}%;\n top: ${y}%;\n \" title=\"Point ${idx + 1}: ${statusLabel}, error ${(data.accuracyNorm * 100).toFixed(1)}%\"\n aria-label=\"Point ${idx + 1}: ${statusLabel}, error ${(data.accuracyNorm * 100).toFixed(1)}%\">\n <span class=\"gaze-label\">${statusSymbol}</span>\n </div>\n `;\n })\n .join('');\n // Draw lines connecting targets to mean gaze positions - color coded\n const connectionLines = pointData\n .map((data) => {\n if (!data.meanGaze)\n return '';\n const x1 = data.point.x * 100;\n const y1 = data.point.y * 100;\n const x2 = data.meanGaze.x * 100;\n const y2 = data.meanGaze.y * 100;\n const withinTolerance = data.accuracyNorm <= tol;\n const lineColor = withinTolerance ? '#4ade80' : '#f87171';\n return `\n <svg class=\"feedback-line\" style=\"position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none;\">\n <line x1=\"${x1}%\" y1=\"${y1}%\" x2=\"${x2}%\" y2=\"${y2}%\"\n stroke=\"${lineColor}\" stroke-width=\"2\" stroke-dasharray=\"5,3\" opacity=\"0.7\"/>\n </svg>\n `;\n })\n .join('');\n // Show all individual gaze samples as small dots - color coded per point\n const gazeSampleDots = pointData\n .map((data) => {\n if (!data.gazeSamples)\n return '';\n const withinTolerance = data.accuracyNorm <= tol;\n const sampleClass = withinTolerance ? 'sample-pass' : 'sample-fail';\n return data.gazeSamples\n .map((sample) => {\n const x = sample.x * 100;\n const y = sample.y * 100;\n return `<div class=\"feedback-sample ${sampleClass}\" style=\"left: ${x}%; top: ${y}%;\"></div>`;\n })\n .join('');\n })\n .join('');\n // Calculate aspect ratio from viewport\n const aspectRatio = window.innerWidth / window.innerHeight;\n const canvas = `\n <div class=\"validation-feedback\">\n <div class=\"feedback-canvas-fullscreen\" style=\"aspect-ratio: ${aspectRatio.toFixed(3)};\">\n ${connectionLines}\n ${gazeSampleDots}\n ${targetMarkers}\n ${gazeMarkers}\n </div>\n <div class=\"feedback-legend\">\n <span><span class=\"legend-color target-legend\"></span> Target</span>\n <span><span class=\"legend-color gaze-pass-legend\"></span> Pass (\\u2713)</span>\n <span><span class=\"legend-color gaze-fail-legend\"></span> Fail (\\u2717)</span>\n </div>\n </div>\n `;\n return canvas;\n }\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=validation-display.js.map","/**\n * @title Tobii Validation\n * @description jsPsych plugin for Tobii eye tracker validation. Validates calibration\n * accuracy by measuring gaze error at target points and provides detailed feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-validation#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 { ValidationResult } from '@jspsych/extension-tobii';\nimport { ValidationDisplay } from './validation-display';\nimport type { ValidationParameters, ValidationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-validation',\n version: version,\n parameters: {\n /** Number of validation points (5 or 9) */\n validation_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Size of validation points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of validation points */\n point_color: {\n type: ParameterType.STRING,\n default: '#00ff00',\n },\n /** Duration to collect data at each point (ms) */\n collection_duration: {\n type: ParameterType.INT,\n default: 1000,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: true,\n },\n /** Custom validation points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Show visual feedback */\n show_feedback: {\n type: ParameterType.BOOL,\n default: true,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default: 'Look at each point as it appears on the screen to validate calibration accuracy.',\n },\n /** Background color of the validation 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: '#28a745',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#218838',\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 /** Normalized tolerance for acceptable accuracy (0-1 scale, validation passes if average error <= this) */\n tolerance: {\n type: ParameterType.FLOAT,\n default: 0.05,\n },\n /** Maximum number of retry attempts allowed on validation 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 },\n data: {\n /** Validation success status */\n validation_success: {\n type: ParameterType.BOOL,\n },\n /** Average accuracy */\n average_accuracy: {\n type: ParameterType.FLOAT,\n },\n /** Average precision */\n average_precision: {\n type: ParameterType.FLOAT,\n },\n /** Number of validation points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Full validation result data */\n validation_data: {\n type: ParameterType.COMPLEX,\n },\n /** Normalized tolerance used for pass/fail determination */\n tolerance: {\n type: ParameterType.FLOAT,\n },\n /** Number of validation attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiValidationPlugin 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-validation-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 TobiiValidationPlugin.removeStyles();\n\n const css = `\n .tobii-validation-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 }\n\n .tobii-validation-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 }\n\n .tobii-validation-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-validation-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .validation-start-btn,\n .validation-continue-btn,\n .validation-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 .validation-start-btn:hover,\n .validation-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .validation-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .validation-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-validation-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-validation-point.animation-zoom-out {\n animation: tobii-validation-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-validation-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-validation-point.animation-zoom-in {\n animation: tobii-validation-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-validation-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-validation-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-validation-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 30px 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n width: 60vw;\n max-width: 800px;\n max-height: 85vh;\n overflow-y: auto;\n }\n\n .tobii-validation-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-validation-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-validation-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-validation-result-content p {\n margin-bottom: 15px;\n font-size: 16px;\n color: #666;\n }\n\n .validation-feedback {\n margin: 30px 0;\n }\n\n .validation-feedback h3 {\n margin-bottom: 15px;\n font-size: 18px;\n color: #333;\n }\n\n .feedback-canvas {\n position: relative;\n width: 100%;\n height: 300px;\n background-color: #f0f0f0;\n border: 2px solid #ddd;\n border-radius: 5px;\n margin-bottom: 15px;\n }\n\n .feedback-point {\n position: absolute;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n border: 2px solid #333;\n cursor: help;\n }\n\n .feedback-legend {\n display: flex;\n justify-content: center;\n gap: 20px;\n font-size: 14px;\n color: #666;\n }\n\n .feedback-legend span {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .legend-color {\n display: inline-block;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n border: 1px solid #333;\n }\n\n .target-legend {\n background-color: transparent;\n border: 3px solid #333;\n }\n\n .feedback-canvas-fullscreen {\n position: relative;\n width: 100%;\n background-color: #2a2a2a;\n border: 2px solid #444;\n border-radius: 5px;\n margin-bottom: 15px;\n overflow: hidden;\n }\n\n .feedback-target {\n position: absolute;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n border: 3px solid #fff;\n background-color: transparent;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .target-label {\n color: #fff;\n font-size: 10px;\n font-weight: bold;\n }\n\n .feedback-gaze {\n position: absolute;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n border: 2px solid;\n z-index: 11;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: help;\n }\n\n .gaze-label {\n color: #000;\n font-size: 9px;\n font-weight: bold;\n }\n\n .feedback-sample {\n position: absolute;\n width: 4px;\n height: 4px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n background-color: rgba(100, 100, 255, 0.4);\n z-index: 5;\n }\n\n .accuracy-table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 15px;\n font-size: 13px;\n text-align: left;\n }\n\n .accuracy-table th,\n .accuracy-table td {\n padding: 8px 12px;\n border: 1px solid #ddd;\n }\n\n .accuracy-table th {\n background-color: #f5f5f5;\n font-weight: 600;\n color: #333;\n }\n\n .accuracy-table tr:nth-child(even) {\n background-color: #fafafa;\n }\n\n .accuracy-table td {\n color: #555;\n }\n\n .saccade-note {\n font-size: 12px;\n color: #888;\n font-style: italic;\n margin-top: 10px;\n }\n\n .tolerance-info {\n font-size: 14px;\n color: #666;\n }\n\n .gaze-pass-legend {\n background-color: #4ade80;\n }\n\n .gaze-fail-legend {\n background-color: #f87171;\n }\n\n .feedback-gaze.gaze-pass {\n background-color: #4ade80;\n border-color: #22c55e;\n }\n\n .feedback-gaze.gaze-fail {\n background-color: #f87171;\n border-color: #ef4444;\n }\n\n .feedback-sample.sample-pass {\n background-color: rgba(74, 222, 128, 0.5);\n }\n\n .feedback-sample.sample-fail {\n background-color: rgba(248, 113, 113, 0.5);\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-validation-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 validation display\n const validationDisplay = new ValidationDisplay(\n display_element,\n trial as unknown as ValidationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await validationDisplay.showInstructions();\n\n // Get validation points and validate custom points\n let points: ValidationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getValidationPoints(trial.validation_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let validationPassed = false;\n let avgAccuracyNorm = 0;\n let avgPrecisionNorm = 0;\n let validationResult: ValidationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start validation on server (resets server-side state on each call)\n await tobiiExt.startValidation();\n\n // Start tracking to collect gaze data\n await tobiiExt.startTracking();\n\n // Initialize point at screen center (with brief pause)\n await validationDisplay.initializePoint();\n\n // Show each point and collect validation 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 validationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await validationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await validationDisplay.playZoomIn();\n\n // Capture start time before collection period for precise time-range query\n const collectionStartTime = performance.now();\n\n // Wait for data collection\n await this.delay(trial.collection_duration!);\n\n // Capture end time after collection period\n const collectionEndTime = performance.now();\n\n // Get gaze samples collected during exactly this point's display period\n const gazeSamples = await tobiiExt.getGazeData(collectionStartTime, collectionEndTime);\n\n // Collect validation data for this point with the gaze samples\n await tobiiExt.collectValidationPoint(point.x, point.y, gazeSamples);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await validationDisplay.resetPointForTravel();\n }\n }\n\n // Hide point after final data collection\n await validationDisplay.hidePoint();\n\n // Stop tracking\n await tobiiExt.stopTracking();\n\n // Compute validation on server\n validationResult = await tobiiExt.computeValidation();\n\n // Get normalized accuracy values from server\n avgAccuracyNorm = validationResult.averageAccuracyNorm || 0;\n avgPrecisionNorm = validationResult.averagePrecisionNorm || 0;\n\n // Determine if validation passes based on normalized tolerance\n validationPassed = validationResult.success && avgAccuracyNorm <= trial.tolerance!;\n\n // Show result with retry option if retries remain\n const userChoice = await validationDisplay.showResult(\n validationPassed,\n avgAccuracyNorm,\n avgPrecisionNorm,\n validationResult.pointData || [],\n trial.tolerance,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n validationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n validationDisplay.clear();\n display_element.innerHTML = '';\n TobiiValidationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n validation_success: validationPassed,\n average_accuracy: avgAccuracyNorm,\n average_precision: avgPrecisionNorm,\n tolerance: trial.tolerance,\n num_points: points.length,\n validation_data: validationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom validation points\n */\n private validateCustomPoints(points: unknown[]): ValidationPoint[] {\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: ValidationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i] as Record<string, unknown>;\n if (\n typeof point !== 'object' ||\n point === null ||\n typeof point.x !== 'number' ||\n typeof point.y !== 'number'\n ) {\n throw new Error(`Invalid validation point at index ${i}: must have numeric x and y`);\n }\n if (point.x < 0 || point.x > 1 || point.y < 0 || point.y > 1) {\n throw new Error(\n `Validation point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: point.x, y: point.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard validation points for the given grid size\n */\n private getValidationPoints(count: number): ValidationPoint[] {\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 validation_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 TobiiValidationPlugin;\n"],"names":["ParameterType"],"mappings":"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"}
1
+ {"version":3,"file":"index.browser.js","sources":["../package.json","../src/validation-display.js","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-tobii-validation\",\n \"version\": \"0.2.1\",\n \"description\": \"jsPsych plugin for Tobii eye tracker validation\",\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-validation\"\n },\n \"keywords\": [\n \"jsPsych\",\n \"eye-tracking\",\n \"tobii\",\n \"validation\"\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-validation#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 * Validation display component\n */\nexport class ValidationDisplay {\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 createContainer() {\n const container = document.createElement('div');\n container.className = 'tobii-validation-container';\n return container;\n }\n createProgressIndicator() {\n const progress = document.createElement('div');\n progress.className = 'tobii-validation-progress';\n progress.setAttribute('role', 'status');\n progress.setAttribute('aria-live', 'polite');\n return progress;\n }\n async showInstructions() {\n const wrapper = document.createElement('div');\n wrapper.className = 'tobii-validation-instructions';\n wrapper.setAttribute('role', 'dialog');\n wrapper.setAttribute('aria-label', 'Eye tracker validation instructions');\n const content = document.createElement('div');\n content.className = 'instructions-content';\n const heading = document.createElement('h2');\n heading.textContent = 'Eye Tracker Validation';\n content.appendChild(heading);\n const paragraph = document.createElement('p');\n paragraph.innerHTML =\n this.params.instructions || 'Look at each point to validate calibration accuracy.';\n content.appendChild(paragraph);\n const button = document.createElement('button');\n button.className = 'validation-start-btn';\n button.textContent = 'Start Validation';\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-validation-point';\n this.currentPoint.setAttribute('role', 'img');\n this.currentPoint.setAttribute('aria-label', 'Validation 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 || '#00ff00',\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', `Validation 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-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-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 * Reset point state after data collection (keeps element for continued travel)\n */\n async resetPointForTravel() {\n if (!this.currentPoint)\n return;\n // Reset to normal size for next travel\n this.currentPoint.classList.remove('animation-zoom-out', 'animation-zoom-in');\n this.currentPoint.style.transform = 'translate(-50%, -50%) scale(1)';\n await this.delay(50);\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 * Show validation result\n * @param success Whether validation passed\n * @param averageAccuracyNorm Average accuracy in normalized units\n * @param averagePrecisionNorm Average precision in normalized units\n * @param pointData Per-point validation data\n * @param tolerance Tolerance threshold\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, averageAccuracyNorm, _averagePrecisionNorm, pointData, tolerance, canRetry = false) {\n const result = document.createElement('div');\n result.className = 'tobii-validation-result';\n result.setAttribute('role', 'alert');\n result.setAttribute('aria-live', 'assertive');\n let feedbackHTML = '';\n if (this.params.show_feedback && pointData) {\n feedbackHTML = this.createVisualFeedback(pointData, tolerance);\n }\n const statusClass = success ? 'success' : 'error';\n const statusText = success ? 'Validation Passed' : 'Validation Failed';\n let buttonsHTML;\n if (success) {\n buttonsHTML = `<button class=\"validation-continue-btn\">Continue</button>`;\n }\n else if (canRetry) {\n buttonsHTML = `<button class=\"validation-retry-btn\">Retry</button>\n <button class=\"validation-continue-btn\" style=\"margin-left: 10px;\">Continue</button>`;\n }\n else {\n buttonsHTML = `<button class=\"validation-continue-btn\">Continue</button>`;\n }\n result.innerHTML = `\n <div class=\"tobii-validation-result-content ${statusClass}\">\n <h2>${statusText}</h2>\n <p>Average error: ${((averageAccuracyNorm || 0) * 100).toFixed(1)}% (tolerance: ${((tolerance || 0) * 100).toFixed(0)}%)</p>\n ${feedbackHTML}\n ${buttonsHTML}\n </div>\n `;\n this.container.appendChild(result);\n return new Promise((resolve) => {\n const retryBtn = result.querySelector('.validation-retry-btn');\n const continueBtn = result.querySelector('.validation-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 createVisualFeedback(pointData, tolerance) {\n const tol = tolerance || 0.05;\n // Create full-screen visualization showing actual screen positions\n const targetMarkers = pointData\n .map((data, idx) => {\n const x = data.point.x * 100;\n const y = data.point.y * 100;\n return `\n <div class=\"feedback-target\" style=\"\n left: ${x}%;\n top: ${y}%;\n \" title=\"Target ${idx + 1}\">\n <span class=\"target-label\">${idx + 1}</span>\n </div>\n `;\n })\n .join('');\n // Mean gaze positions - color coded based on tolerance with non-color indicators\n const gazeMarkers = pointData\n .map((data, idx) => {\n if (!data.meanGaze)\n return '';\n const x = data.meanGaze.x * 100;\n const y = data.meanGaze.y * 100;\n const withinTolerance = data.accuracyNorm <= tol;\n const colorClass = withinTolerance ? 'gaze-pass' : 'gaze-fail';\n const statusSymbol = withinTolerance ? '\\u2713' : '\\u2717';\n const statusLabel = withinTolerance ? 'pass' : 'fail';\n return `\n <div class=\"feedback-gaze ${colorClass}\" style=\"\n left: ${x}%;\n top: ${y}%;\n \" title=\"Point ${idx + 1}: ${statusLabel}, error ${(data.accuracyNorm * 100).toFixed(1)}%\"\n aria-label=\"Point ${idx + 1}: ${statusLabel}, error ${(data.accuracyNorm * 100).toFixed(1)}%\">\n <span class=\"gaze-label\">${statusSymbol}</span>\n </div>\n `;\n })\n .join('');\n // Draw lines connecting targets to mean gaze positions - color coded\n const connectionLines = pointData\n .map((data) => {\n if (!data.meanGaze)\n return '';\n const x1 = data.point.x * 100;\n const y1 = data.point.y * 100;\n const x2 = data.meanGaze.x * 100;\n const y2 = data.meanGaze.y * 100;\n const withinTolerance = data.accuracyNorm <= tol;\n const lineColor = withinTolerance ? '#4ade80' : '#f87171';\n return `\n <svg class=\"feedback-line\" style=\"position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none;\">\n <line x1=\"${x1}%\" y1=\"${y1}%\" x2=\"${x2}%\" y2=\"${y2}%\"\n stroke=\"${lineColor}\" stroke-width=\"2\" stroke-dasharray=\"5,3\" opacity=\"0.7\"/>\n </svg>\n `;\n })\n .join('');\n // Show all individual gaze samples as small dots - color coded per point\n const gazeSampleDots = pointData\n .map((data) => {\n if (!data.gazeSamples)\n return '';\n const withinTolerance = data.accuracyNorm <= tol;\n const sampleClass = withinTolerance ? 'sample-pass' : 'sample-fail';\n return data.gazeSamples\n .map((sample) => {\n const x = sample.x * 100;\n const y = sample.y * 100;\n return `<div class=\"feedback-sample ${sampleClass}\" style=\"left: ${x}%; top: ${y}%;\"></div>`;\n })\n .join('');\n })\n .join('');\n // Calculate aspect ratio from viewport\n const aspectRatio = window.innerWidth / window.innerHeight;\n const canvas = `\n <div class=\"validation-feedback\">\n <div class=\"feedback-canvas-fullscreen\" style=\"aspect-ratio: ${aspectRatio.toFixed(3)};\">\n ${connectionLines}\n ${gazeSampleDots}\n ${targetMarkers}\n ${gazeMarkers}\n </div>\n <div class=\"feedback-legend\">\n <span><span class=\"legend-color target-legend\"></span> Target</span>\n <span><span class=\"legend-color gaze-pass-legend\"></span> Pass (\\u2713)</span>\n <span><span class=\"legend-color gaze-fail-legend\"></span> Fail (\\u2717)</span>\n </div>\n </div>\n `;\n return canvas;\n }\n clear() {\n this.container.innerHTML = '';\n if (this.progressElement) {\n this.progressElement.textContent = '';\n }\n }\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n//# sourceMappingURL=validation-display.js.map","/**\n * @title Tobii Validation\n * @description jsPsych plugin for Tobii eye tracker validation. Validates calibration\n * accuracy by measuring gaze error at target points and provides detailed feedback.\n * @version 1.0.0\n * @author jsPsych Team\n * @see {@link https://github.com/jspsych/jspsych-tobii/tree/main/packages/plugin-tobii-validation#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 { ValidationResult } from '@jspsych/extension-tobii';\nimport { ValidationDisplay } from './validation-display';\nimport type { ValidationParameters, ValidationPoint } from './types';\n\nconst info = <const>{\n name: 'tobii-validation',\n version: version,\n parameters: {\n /** Number of validation points (5 or 9) */\n validation_points: {\n type: ParameterType.INT,\n default: 9,\n },\n /** Size of validation points in pixels */\n point_size: {\n type: ParameterType.INT,\n default: 20,\n },\n /** Color of validation points */\n point_color: {\n type: ParameterType.STRING,\n default: '#00ff00',\n },\n /** Duration to collect data at each point (ms) */\n collection_duration: {\n type: ParameterType.INT,\n default: 1000,\n },\n /** Show progress indicator */\n show_progress: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Custom validation points */\n custom_points: {\n type: ParameterType.COMPLEX,\n default: null,\n },\n /** Show visual feedback */\n show_feedback: {\n type: ParameterType.BOOL,\n default: true,\n },\n /** Instructions text */\n instructions: {\n type: ParameterType.STRING,\n default: 'Look at each point as it appears on the screen to validate calibration accuracy.',\n },\n /** Background color of the validation 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: '#28a745',\n },\n /** Primary button hover color */\n button_hover_color: {\n type: ParameterType.STRING,\n default: '#218838',\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 /** Normalized tolerance for acceptable accuracy (0-1 scale, validation passes if average error <= this) */\n tolerance: {\n type: ParameterType.FLOAT,\n default: 0.05,\n },\n /** Maximum number of retry attempts allowed on validation 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 },\n data: {\n /** Validation success status */\n validation_success: {\n type: ParameterType.BOOL,\n },\n /** Average accuracy */\n average_accuracy: {\n type: ParameterType.FLOAT,\n },\n /** Average precision */\n average_precision: {\n type: ParameterType.FLOAT,\n },\n /** Number of validation points used */\n num_points: {\n type: ParameterType.INT,\n },\n /** Full validation result data */\n validation_data: {\n type: ParameterType.COMPLEX,\n },\n /** Normalized tolerance used for pass/fail determination */\n tolerance: {\n type: ParameterType.FLOAT,\n },\n /** Number of validation attempts made */\n num_attempts: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\nclass TobiiValidationPlugin 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-validation-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 TobiiValidationPlugin.removeStyles();\n\n const css = `\n .tobii-validation-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-validation-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-validation-instructions h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n color: #333;\n }\n\n .tobii-validation-instructions p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n color: #666;\n }\n\n .validation-start-btn,\n .validation-continue-btn,\n .validation-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 .validation-start-btn:hover,\n .validation-continue-btn:hover {\n background-color: ${trial.button_hover_color};\n }\n\n .validation-retry-btn {\n background-color: ${trial.retry_button_color};\n }\n\n .validation-retry-btn:hover {\n background-color: ${trial.retry_button_hover_color};\n }\n\n .tobii-validation-point {\n position: absolute;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .tobii-validation-point.animation-zoom-out {\n animation: tobii-validation-zoom-out ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-validation-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-validation-point.animation-zoom-in {\n animation: tobii-validation-zoom-in ${(trial.zoom_duration as number) / 1000}s ease-out forwards;\n }\n\n @keyframes tobii-validation-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-validation-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-validation-result {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 30px 40px;\n border-radius: 10px;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n text-align: center;\n width: 60vw;\n max-width: 800px;\n max-height: 85vh;\n overflow-y: auto;\n cursor: auto;\n }\n\n .tobii-validation-result-content h2 {\n margin-top: 0;\n margin-bottom: 20px;\n font-size: 24px;\n }\n\n .tobii-validation-result-content.success h2 {\n color: ${trial.success_color};\n }\n\n .tobii-validation-result-content.error h2 {\n color: ${trial.error_color};\n }\n\n .tobii-validation-result-content p {\n margin-bottom: 15px;\n font-size: 16px;\n color: #666;\n }\n\n .validation-feedback {\n margin: 30px 0;\n }\n\n .validation-feedback h3 {\n margin-bottom: 15px;\n font-size: 18px;\n color: #333;\n }\n\n .feedback-canvas {\n position: relative;\n width: 100%;\n height: 300px;\n background-color: #f0f0f0;\n border: 2px solid #ddd;\n border-radius: 5px;\n margin-bottom: 15px;\n }\n\n .feedback-point {\n position: absolute;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n border: 2px solid #333;\n cursor: help;\n }\n\n .feedback-legend {\n display: flex;\n justify-content: center;\n gap: 20px;\n font-size: 14px;\n color: #666;\n }\n\n .feedback-legend span {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .legend-color {\n display: inline-block;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n border: 1px solid #333;\n }\n\n .target-legend {\n background-color: transparent;\n border: 3px solid #333;\n }\n\n .feedback-canvas-fullscreen {\n position: relative;\n width: 100%;\n background-color: #2a2a2a;\n border: 2px solid #444;\n border-radius: 5px;\n margin-bottom: 15px;\n overflow: hidden;\n }\n\n .feedback-target {\n position: absolute;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n border: 3px solid #fff;\n background-color: transparent;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .target-label {\n color: #fff;\n font-size: 10px;\n font-weight: bold;\n }\n\n .feedback-gaze {\n position: absolute;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n border: 2px solid;\n z-index: 11;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: help;\n }\n\n .gaze-label {\n color: #000;\n font-size: 9px;\n font-weight: bold;\n }\n\n .feedback-sample {\n position: absolute;\n width: 4px;\n height: 4px;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n background-color: rgba(100, 100, 255, 0.4);\n z-index: 5;\n }\n\n .accuracy-table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 15px;\n font-size: 13px;\n text-align: left;\n }\n\n .accuracy-table th,\n .accuracy-table td {\n padding: 8px 12px;\n border: 1px solid #ddd;\n }\n\n .accuracy-table th {\n background-color: #f5f5f5;\n font-weight: 600;\n color: #333;\n }\n\n .accuracy-table tr:nth-child(even) {\n background-color: #fafafa;\n }\n\n .accuracy-table td {\n color: #555;\n }\n\n .saccade-note {\n font-size: 12px;\n color: #888;\n font-style: italic;\n margin-top: 10px;\n }\n\n .tolerance-info {\n font-size: 14px;\n color: #666;\n }\n\n .gaze-pass-legend {\n background-color: #4ade80;\n }\n\n .gaze-fail-legend {\n background-color: #f87171;\n }\n\n .feedback-gaze.gaze-pass {\n background-color: #4ade80;\n border-color: #22c55e;\n }\n\n .feedback-gaze.gaze-fail {\n background-color: #f87171;\n border-color: #ef4444;\n }\n\n .feedback-sample.sample-pass {\n background-color: rgba(74, 222, 128, 0.5);\n }\n\n .feedback-sample.sample-fail {\n background-color: rgba(248, 113, 113, 0.5);\n }\n `;\n\n const styleElement = document.createElement('style');\n styleElement.id = 'tobii-validation-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 validation display\n const validationDisplay = new ValidationDisplay(\n display_element,\n trial as unknown as ValidationParameters\n );\n\n // Show instructions (only once, before retry loop)\n await validationDisplay.showInstructions();\n\n // Get validation points and validate custom points\n let points: ValidationPoint[];\n if (trial.custom_points) {\n points = this.validateCustomPoints(trial.custom_points);\n } else {\n points = this.getValidationPoints(trial.validation_points!);\n }\n\n const maxAttempts = 1 + (trial.max_retries as number);\n let attempt = 0;\n let validationPassed = false;\n let avgAccuracyNorm = 0;\n let avgPrecisionNorm = 0;\n let validationResult: ValidationResult = { success: false };\n\n try {\n // Retry loop\n while (attempt < maxAttempts) {\n attempt++;\n const retriesRemaining = maxAttempts - attempt;\n\n // Start validation on server (resets server-side state on each call)\n await tobiiExt.startValidation();\n\n // Start tracking to collect gaze data\n await tobiiExt.startTracking();\n\n // Initialize point at screen center (with brief pause)\n await validationDisplay.initializePoint();\n\n // Show each point and collect validation 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 validationDisplay.travelToPoint(point, i, points.length);\n\n // Zoom out (point grows larger to attract attention)\n await validationDisplay.playZoomOut();\n\n // Zoom in (point shrinks to fixation size)\n await validationDisplay.playZoomIn();\n\n // Capture start time before collection period for precise time-range query\n const collectionStartTime = performance.now();\n\n // Wait for data collection\n await this.delay(trial.collection_duration!);\n\n // Capture end time after collection period\n const collectionEndTime = performance.now();\n\n // Get gaze samples collected during exactly this point's display period\n const gazeSamples = await tobiiExt.getGazeData(collectionStartTime, collectionEndTime);\n\n // Collect validation data for this point with the gaze samples\n await tobiiExt.collectValidationPoint(point.x, point.y, gazeSamples);\n\n // Reset point for next travel (don't remove element)\n if (i < points.length - 1) {\n await validationDisplay.resetPointForTravel();\n }\n }\n\n // Hide point after final data collection\n await validationDisplay.hidePoint();\n\n // Stop tracking\n await tobiiExt.stopTracking();\n\n // Compute validation on server\n validationResult = await tobiiExt.computeValidation();\n\n // Get normalized accuracy values from server\n avgAccuracyNorm = validationResult.averageAccuracyNorm || 0;\n avgPrecisionNorm = validationResult.averagePrecisionNorm || 0;\n\n // Determine if validation passes based on normalized tolerance\n validationPassed = validationResult.success && avgAccuracyNorm <= trial.tolerance!;\n\n // Show result with retry option if retries remain\n const userChoice = await validationDisplay.showResult(\n validationPassed,\n avgAccuracyNorm,\n avgPrecisionNorm,\n validationResult.pointData || [],\n trial.tolerance,\n retriesRemaining > 0\n );\n\n if (userChoice === 'continue') {\n break;\n }\n\n // User chose retry — reset display for next attempt\n validationDisplay.resetForRetry();\n }\n } finally {\n // Clear display and remove injected styles\n validationDisplay.clear();\n display_element.innerHTML = '';\n TobiiValidationPlugin.removeStyles();\n }\n\n // Finish trial\n const trial_data = {\n validation_success: validationPassed,\n average_accuracy: avgAccuracyNorm,\n average_precision: avgPrecisionNorm,\n tolerance: trial.tolerance,\n num_points: points.length,\n validation_data: validationResult,\n num_attempts: attempt,\n };\n\n this.jsPsych.finishTrial(trial_data);\n }\n\n /**\n * Validate custom validation points\n */\n private validateCustomPoints(points: unknown[]): ValidationPoint[] {\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: ValidationPoint[] = [];\n for (let i = 0; i < points.length; i++) {\n const point = points[i] as Record<string, unknown>;\n if (\n typeof point !== 'object' ||\n point === null ||\n typeof point.x !== 'number' ||\n typeof point.y !== 'number'\n ) {\n throw new Error(`Invalid validation point at index ${i}: must have numeric x and y`);\n }\n if (point.x < 0 || point.x > 1 || point.y < 0 || point.y > 1) {\n throw new Error(\n `Validation point at index ${i} out of range: x and y must be between 0 and 1`\n );\n }\n validated.push({ x: point.x, y: point.y });\n }\n\n return validated;\n }\n\n /**\n * Get standard validation points for the given grid size\n */\n private getValidationPoints(count: number): ValidationPoint[] {\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 validation_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 TobiiValidationPlugin;\n"],"names":["ParameterType"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- var jsPsychTobiiValidation=function(s){"use strict";var v="0.1.1",m=(b,t,e)=>new Promise((a,i)=>{var l=o=>{try{n(e.next(o))}catch(r){i(r)}},d=o=>{try{n(e.throw(o))}catch(r){i(r)}},n=o=>o.done?a(o.value):Promise.resolve(o.value).then(l,d);n((e=e.apply(b,t)).next())});class P{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-validation-container",t}createProgressIndicator(){const t=document.createElement("div");return t.className="tobii-validation-progress",t.setAttribute("role","status"),t.setAttribute("aria-live","polite"),t}showInstructions(){return m(this,null,function*(){const t=document.createElement("div");t.className="tobii-validation-instructions",t.setAttribute("role","dialog"),t.setAttribute("aria-label","Eye tracker validation instructions");const e=document.createElement("div");e.className="instructions-content";const a=document.createElement("h2");a.textContent="Eye Tracker Validation",e.appendChild(a);const i=document.createElement("p");i.innerHTML=this.params.instructions||"Look at each point to validate calibration accuracy.",e.appendChild(i);const l=document.createElement("button");return l.className="validation-start-btn",l.textContent="Start Validation",e.appendChild(l),t.appendChild(e),this.container.appendChild(t),new Promise(d=>{l.addEventListener("click",()=>{t.remove(),d()})})})}initializePoint(){return m(this,null,function*(){if(this.currentPoint)return;this.currentPoint=document.createElement("div"),this.currentPoint.className="tobii-validation-point",this.currentPoint.setAttribute("role","img"),this.currentPoint.setAttribute("aria-label","Validation 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||"#00ff00",transition:"none"}),this.container.appendChild(this.currentPoint),yield this.delay(this.params.zoom_duration||300)})}travelToPoint(t,e,a){return m(this,null,function*(){this.currentPoint||(yield this.initializePoint()),this.progressElement&&(this.progressElement.textContent=`Point ${e+1} of ${a}`),this.currentPoint.setAttribute("aria-label",`Validation target point ${e+1} of ${a}`);const i=t.x-this.currentX,l=t.y-this.currentY,d=Math.sqrt(i*i+l*l),n=Math.max(150,Math.min(400,150+d*200)),o=t.x*window.innerWidth,r=t.y*window.innerHeight;this.currentPoint.style.transition=`left ${n}ms ease-in-out, top ${n}ms ease-in-out`,this.currentPoint.classList.remove("animation-zoom-out","animation-zoom-in"),this.currentPoint.style.left=`${o}px`,this.currentPoint.style.top=`${r}px`,this.currentX=t.x,this.currentY=t.y,yield this.delay(n)})}playZoomOut(){return m(this,null,function*(){this.currentPoint&&(this.currentPoint.style.transition="none",this.currentPoint.classList.remove("animation-zoom-in"),this.currentPoint.classList.add("animation-zoom-out"),yield this.delay(this.params.zoom_duration||300))})}playZoomIn(){return m(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))})}resetPointForTravel(){return m(this,null,function*(){this.currentPoint&&(this.currentPoint.classList.remove("animation-zoom-out","animation-zoom-in"),this.currentPoint.style.transform="translate(-50%, -50%) scale(1)",yield this.delay(50))})}hidePoint(){return m(this,null,function*(){this.currentPoint&&(this.currentPoint.remove(),this.currentPoint=null),yield this.delay(200)})}showResult(t,e,a,i,l,d=!1){return m(this,null,function*(){const n=document.createElement("div");n.className="tobii-validation-result",n.setAttribute("role","alert"),n.setAttribute("aria-live","assertive");let o="";this.params.show_feedback&&i&&(o=this.createVisualFeedback(i,l));const r=t?"success":"error",u=t?"Validation Passed":"Validation Failed";let c;return t?c='<button class="validation-continue-btn">Continue</button>':d?c=`<button class="validation-retry-btn">Retry</button>
1
+ var jsPsychTobiiValidation=function(s){"use strict";var v="0.2.1",m=(b,t,e)=>new Promise((a,i)=>{var l=o=>{try{n(e.next(o))}catch(r){i(r)}},d=o=>{try{n(e.throw(o))}catch(r){i(r)}},n=o=>o.done?a(o.value):Promise.resolve(o.value).then(l,d);n((e=e.apply(b,t)).next())});class P{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-validation-container",t}createProgressIndicator(){const t=document.createElement("div");return t.className="tobii-validation-progress",t.setAttribute("role","status"),t.setAttribute("aria-live","polite"),t}showInstructions(){return m(this,null,function*(){const t=document.createElement("div");t.className="tobii-validation-instructions",t.setAttribute("role","dialog"),t.setAttribute("aria-label","Eye tracker validation instructions");const e=document.createElement("div");e.className="instructions-content";const a=document.createElement("h2");a.textContent="Eye Tracker Validation",e.appendChild(a);const i=document.createElement("p");i.innerHTML=this.params.instructions||"Look at each point to validate calibration accuracy.",e.appendChild(i);const l=document.createElement("button");return l.className="validation-start-btn",l.textContent="Start Validation",e.appendChild(l),t.appendChild(e),this.container.appendChild(t),new Promise(d=>{l.addEventListener("click",()=>{t.remove(),d()})})})}initializePoint(){return m(this,null,function*(){if(this.currentPoint)return;this.currentPoint=document.createElement("div"),this.currentPoint.className="tobii-validation-point",this.currentPoint.setAttribute("role","img"),this.currentPoint.setAttribute("aria-label","Validation 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||"#00ff00",transition:"none"}),this.container.appendChild(this.currentPoint),yield this.delay(this.params.zoom_duration||300)})}travelToPoint(t,e,a){return m(this,null,function*(){this.currentPoint||(yield this.initializePoint()),this.progressElement&&(this.progressElement.textContent=`Point ${e+1} of ${a}`),this.currentPoint.setAttribute("aria-label",`Validation target point ${e+1} of ${a}`);const i=t.x-this.currentX,l=t.y-this.currentY,d=Math.sqrt(i*i+l*l),n=Math.max(150,Math.min(400,150+d*200)),o=t.x*window.innerWidth,r=t.y*window.innerHeight;this.currentPoint.style.transition=`left ${n}ms ease-in-out, top ${n}ms ease-in-out`,this.currentPoint.classList.remove("animation-zoom-out","animation-zoom-in"),this.currentPoint.style.left=`${o}px`,this.currentPoint.style.top=`${r}px`,this.currentX=t.x,this.currentY=t.y,yield this.delay(n)})}playZoomOut(){return m(this,null,function*(){this.currentPoint&&(this.currentPoint.style.transition="none",this.currentPoint.classList.remove("animation-zoom-in"),this.currentPoint.classList.add("animation-zoom-out"),yield this.delay(this.params.zoom_duration||300))})}playZoomIn(){return m(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))})}resetPointForTravel(){return m(this,null,function*(){this.currentPoint&&(this.currentPoint.classList.remove("animation-zoom-out","animation-zoom-in"),this.currentPoint.style.transform="translate(-50%, -50%) scale(1)",yield this.delay(50))})}hidePoint(){return m(this,null,function*(){this.currentPoint&&(this.currentPoint.remove(),this.currentPoint=null),yield this.delay(200)})}showResult(t,e,a,i,l,d=!1){return m(this,null,function*(){const n=document.createElement("div");n.className="tobii-validation-result",n.setAttribute("role","alert"),n.setAttribute("aria-live","assertive");let o="";this.params.show_feedback&&i&&(o=this.createVisualFeedback(i,l));const r=t?"success":"error",u=t?"Validation Passed":"Validation Failed";let c;return t?c='<button class="validation-continue-btn">Continue</button>':d?c=`<button class="validation-retry-btn">Retry</button>
2
2
  <button class="validation-continue-btn" style="margin-left: 10px;">Continue</button>`:c='<button class="validation-continue-btn">Continue</button>',n.innerHTML=`
3
3
  <div class="tobii-validation-result-content ${r}">
4
4
  <h2>${u}</h2>
@@ -40,7 +40,7 @@ var jsPsychTobiiValidation=function(s){"use strict";var v="0.1.1",m=(b,t,e)=>new
40
40
  <span><span class="legend-color gaze-fail-legend"></span> Fail (\u2717)</span>
41
41
  </div>
42
42
  </div>
43
- `}clear(){this.container.innerHTML="",this.progressElement&&(this.progressElement.textContent="")}delay(t){return new Promise(e=>setTimeout(e,t))}}var w=(b,t,e)=>new Promise((a,i)=>{var l=o=>{try{n(e.next(o))}catch(r){i(r)}},d=o=>{try{n(e.throw(o))}catch(r){i(r)}},n=o=>o.done?a(o.value):Promise.resolve(o.value).then(l,d);n((e=e.apply(b,t)).next())});const k={name:"tobii-validation",version:v,parameters:{validation_points:{type:s.ParameterType.INT,default:9},point_size:{type:s.ParameterType.INT,default:20},point_color:{type:s.ParameterType.STRING,default:"#00ff00"},collection_duration:{type:s.ParameterType.INT,default:1e3},show_progress:{type:s.ParameterType.BOOL,default:!0},custom_points:{type:s.ParameterType.COMPLEX,default:null},show_feedback:{type:s.ParameterType.BOOL,default:!0},instructions:{type:s.ParameterType.STRING,default:"Look at each point as it appears on the screen to validate calibration accuracy."},background_color:{type:s.ParameterType.STRING,default:"#808080"},button_color:{type:s.ParameterType.STRING,default:"#28a745"},button_hover_color:{type:s.ParameterType.STRING,default:"#218838"},retry_button_color:{type:s.ParameterType.STRING,default:"#dc3545"},retry_button_hover_color:{type:s.ParameterType.STRING,default:"#c82333"},success_color:{type:s.ParameterType.STRING,default:"#28a745"},error_color:{type:s.ParameterType.STRING,default:"#dc3545"},tolerance:{type:s.ParameterType.FLOAT,default:.05},max_retries:{type:s.ParameterType.INT,default:1},zoom_duration:{type:s.ParameterType.INT,default:300}},data:{validation_success:{type:s.ParameterType.BOOL},average_accuracy:{type:s.ParameterType.FLOAT},average_precision:{type:s.ParameterType.FLOAT},num_points:{type:s.ParameterType.INT},validation_data:{type:s.ParameterType.COMPLEX},tolerance:{type:s.ParameterType.FLOAT},num_attempts:{type:s.ParameterType.INT}}},g=class f{constructor(t){this.jsPsych=t}static removeStyles(){const t=document.getElementById("tobii-validation-styles");t&&t.remove()}injectStyles(t){f.removeStyles();const e=`
43
+ `}clear(){this.container.innerHTML="",this.progressElement&&(this.progressElement.textContent="")}delay(t){return new Promise(e=>setTimeout(e,t))}}var w=(b,t,e)=>new Promise((a,i)=>{var l=o=>{try{n(e.next(o))}catch(r){i(r)}},d=o=>{try{n(e.throw(o))}catch(r){i(r)}},n=o=>o.done?a(o.value):Promise.resolve(o.value).then(l,d);n((e=e.apply(b,t)).next())});const k={name:"tobii-validation",version:v,parameters:{validation_points:{type:s.ParameterType.INT,default:9},point_size:{type:s.ParameterType.INT,default:20},point_color:{type:s.ParameterType.STRING,default:"#00ff00"},collection_duration:{type:s.ParameterType.INT,default:1e3},show_progress:{type:s.ParameterType.BOOL,default:!1},custom_points:{type:s.ParameterType.COMPLEX,default:null},show_feedback:{type:s.ParameterType.BOOL,default:!0},instructions:{type:s.ParameterType.STRING,default:"Look at each point as it appears on the screen to validate calibration accuracy."},background_color:{type:s.ParameterType.STRING,default:"#808080"},button_color:{type:s.ParameterType.STRING,default:"#28a745"},button_hover_color:{type:s.ParameterType.STRING,default:"#218838"},retry_button_color:{type:s.ParameterType.STRING,default:"#dc3545"},retry_button_hover_color:{type:s.ParameterType.STRING,default:"#c82333"},success_color:{type:s.ParameterType.STRING,default:"#28a745"},error_color:{type:s.ParameterType.STRING,default:"#dc3545"},tolerance:{type:s.ParameterType.FLOAT,default:.05},max_retries:{type:s.ParameterType.INT,default:1},zoom_duration:{type:s.ParameterType.INT,default:300}},data:{validation_success:{type:s.ParameterType.BOOL},average_accuracy:{type:s.ParameterType.FLOAT},average_precision:{type:s.ParameterType.FLOAT},num_points:{type:s.ParameterType.INT},validation_data:{type:s.ParameterType.COMPLEX},tolerance:{type:s.ParameterType.FLOAT},num_attempts:{type:s.ParameterType.INT}}},g=class f{constructor(t){this.jsPsych=t}static removeStyles(){const t=document.getElementById("tobii-validation-styles");t&&t.remove()}injectStyles(t){f.removeStyles();const e=`
44
44
  .tobii-validation-container {
45
45
  position: fixed;
46
46
  top: 0;
@@ -50,6 +50,7 @@ var jsPsychTobiiValidation=function(s){"use strict";var v="0.1.1",m=(b,t,e)=>new
50
50
  background-color: ${t.background_color};
51
51
  font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
52
52
  z-index: 9999;
53
+ cursor: none;
53
54
  }
54
55
 
55
56
  .tobii-validation-instructions {
@@ -63,6 +64,7 @@ var jsPsychTobiiValidation=function(s){"use strict";var v="0.1.1",m=(b,t,e)=>new
63
64
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
64
65
  text-align: center;
65
66
  max-width: 600px;
67
+ cursor: auto;
66
68
  }
67
69
 
68
70
  .tobii-validation-instructions h2 {
@@ -165,6 +167,7 @@ var jsPsychTobiiValidation=function(s){"use strict";var v="0.1.1",m=(b,t,e)=>new
165
167
  max-width: 800px;
166
168
  max-height: 85vh;
167
169
  overflow-y: auto;
170
+ cursor: auto;
168
171
  }
169
172
 
170
173
  .tobii-validation-result-content h2 {
@@ -370,4 +373,4 @@ var jsPsychTobiiValidation=function(s){"use strict";var v="0.1.1",m=(b,t,e)=>new
370
373
  background-color: rgba(248, 113, 113, 0.5);
371
374
  }
372
375
  `,a=document.createElement("style");a.id="tobii-validation-styles",a.textContent=e,document.head.appendChild(a)}trial(t,e){return w(this,null,function*(){this.injectStyles(e);const a=this.jsPsych.extensions.tobii;if(!a)throw new Error("Tobii extension not initialized");if(!a.isConnected())throw new Error("Not connected to Tobii server");const i=new P(t,e);yield i.showInstructions();let l;e.custom_points?l=this.validateCustomPoints(e.custom_points):l=this.getValidationPoints(e.validation_points);const d=1+e.max_retries;let n=0,o=!1,r=0,u=0,c={success:!1};try{for(;n<d;){n++;const x=d-n;yield a.startValidation(),yield a.startTracking(),yield i.initializePoint();for(let y=0;y<l.length;y++){const h=l[y];yield i.travelToPoint(h,y,l.length),yield i.playZoomOut(),yield i.playZoomIn();const z=performance.now();yield this.delay(e.collection_duration);const T=performance.now(),_=yield a.getGazeData(z,T);yield a.collectValidationPoint(h.x,h.y,_),y<l.length-1&&(yield i.resetPointForTravel())}if(yield i.hidePoint(),yield a.stopTracking(),c=yield a.computeValidation(),r=c.averageAccuracyNorm||0,u=c.averagePrecisionNorm||0,o=c.success&&r<=e.tolerance,(yield i.showResult(o,r,u,c.pointData||[],e.tolerance,x>0))==="continue")break;i.resetForRetry()}}finally{i.clear(),t.innerHTML="",f.removeStyles()}const p={validation_success:o,average_accuracy:r,average_precision:u,tolerance:e.tolerance,num_points:l.length,validation_data:c,num_attempts:n};this.jsPsych.finishTrial(p)})}validateCustomPoints(t){if(!Array.isArray(t)||t.length===0)throw new Error("custom_points must be a non-empty array");const e=[];for(let a=0;a<t.length;a++){const i=t[a];if(typeof i!="object"||i===null||typeof i.x!="number"||typeof i.y!="number")throw new Error(`Invalid validation point at index ${a}: must have numeric x and y`);if(i.x<0||i.x>1||i.y<0||i.y>1)throw new Error(`Validation point at index ${a} out of range: x and y must be between 0 and 1`);e.push({x:i.x,y:i.y})}return e}getValidationPoints(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 validation_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 g.info=k,g}(jsPsychModule);
373
- //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-validation@0.1.1/dist/index.browser.min.js.map
376
+ //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-tobii-validation@0.2.1/dist/index.browser.min.js.map