@jspsych/extension-tobii 0.1.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/README.md +220 -0
- package/dist/index.browser.js +1005 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.browser.min.js +3 -0
- package/dist/index.browser.min.js.map +1 -0
- package/dist/index.cjs +1004 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +410 -0
- package/dist/index.js +1002 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
- package/src/coordinate-utils.d.ts +33 -0
- package/src/coordinate-utils.d.ts.map +1 -0
- package/src/coordinate-utils.js +70 -0
- package/src/coordinate-utils.js.map +1 -0
- package/src/coordinate-utils.ts +80 -0
- package/src/data-export.d.ts +12 -0
- package/src/data-export.d.ts.map +1 -0
- package/src/data-export.js +75 -0
- package/src/data-export.js.map +1 -0
- package/src/data-export.spec.d.ts +2 -0
- package/src/data-export.spec.d.ts.map +1 -0
- package/src/data-export.spec.js +95 -0
- package/src/data-export.spec.js.map +1 -0
- package/src/data-export.spec.ts +111 -0
- package/src/data-export.ts +84 -0
- package/src/data-manager.d.ts +57 -0
- package/src/data-manager.d.ts.map +1 -0
- package/src/data-manager.js +107 -0
- package/src/data-manager.js.map +1 -0
- package/src/data-manager.spec.d.ts +2 -0
- package/src/data-manager.spec.d.ts.map +1 -0
- package/src/data-manager.spec.js +162 -0
- package/src/data-manager.spec.js.map +1 -0
- package/src/data-manager.spec.ts +195 -0
- package/src/data-manager.ts +123 -0
- package/src/device-time-sync.d.ts +69 -0
- package/src/device-time-sync.d.ts.map +1 -0
- package/src/device-time-sync.js +150 -0
- package/src/device-time-sync.js.map +1 -0
- package/src/device-time-sync.ts +173 -0
- package/src/index.d.ts +200 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +431 -0
- package/src/index.js.map +1 -0
- package/src/index.spec.d.ts +2 -0
- package/src/index.spec.d.ts.map +1 -0
- package/src/index.spec.js +212 -0
- package/src/index.spec.js.map +1 -0
- package/src/index.spec.ts +257 -0
- package/src/index.ts +535 -0
- package/src/time-sync.d.ts +39 -0
- package/src/time-sync.d.ts.map +1 -0
- package/src/time-sync.js +76 -0
- package/src/time-sync.js.map +1 -0
- package/src/time-sync.ts +91 -0
- package/src/types.d.ts +222 -0
- package/src/types.d.ts.map +1 -0
- package/src/types.js +5 -0
- package/src/types.js.map +1 -0
- package/src/types.ts +251 -0
- package/src/validation.d.ts +25 -0
- package/src/validation.d.ts.map +1 -0
- package/src/validation.js +54 -0
- package/src/validation.js.map +1 -0
- package/src/validation.ts +60 -0
- package/src/websocket-client.d.ts +55 -0
- package/src/websocket-client.d.ts.map +1 -0
- package/src/websocket-client.js +189 -0
- package/src/websocket-client.js.map +1 -0
- package/src/websocket-client.ts +227 -0
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# @jspsych/extension-tobii
|
|
2
|
+
|
|
3
|
+
Core jsPsych extension for Tobii eye tracker integration via WebSocket. Provides real-time gaze data streaming, calibration control, time synchronization, and coordinate utilities for eye tracking experiments.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @jspsych/extension-tobii
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Compatibility
|
|
12
|
+
|
|
13
|
+
This extension requires jsPsych v8.0.0 or later.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Loading the Extension
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
import { initJsPsych } from 'jspsych';
|
|
21
|
+
import TobiiExtension from '@jspsych/extension-tobii';
|
|
22
|
+
|
|
23
|
+
const jsPsych = initJsPsych({
|
|
24
|
+
extensions: [
|
|
25
|
+
{
|
|
26
|
+
type: TobiiExtension,
|
|
27
|
+
params: {
|
|
28
|
+
connection: {
|
|
29
|
+
url: 'ws://localhost:8080',
|
|
30
|
+
autoConnect: true,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Enabling Eye Tracking on Trials
|
|
39
|
+
|
|
40
|
+
Add the extension to any trial to collect gaze data during that trial:
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
const trial = {
|
|
44
|
+
type: jsPsychHtmlKeyboardResponse,
|
|
45
|
+
stimulus: '<p>Look at this text</p>',
|
|
46
|
+
extensions: [{ type: TobiiExtension }],
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Initialization Parameters
|
|
51
|
+
|
|
52
|
+
Parameters passed to the extension in the `params` object when initializing jsPsych.
|
|
53
|
+
|
|
54
|
+
| Parameter | Type | Default | Description |
|
|
55
|
+
|-----------|------|---------|-------------|
|
|
56
|
+
| connection | object | `{}` | Connection settings (see below) |
|
|
57
|
+
| connection.url | string | `undefined` | WebSocket server URL (e.g., `'ws://localhost:8080'`) |
|
|
58
|
+
| connection.autoConnect | boolean | `undefined` | Automatically connect on initialization |
|
|
59
|
+
| connection.reconnectAttempts | number | `undefined` | Number of reconnection attempts |
|
|
60
|
+
| connection.reconnectDelay | number | `undefined` | Delay between reconnection attempts in ms |
|
|
61
|
+
|
|
62
|
+
## On Start Parameters
|
|
63
|
+
|
|
64
|
+
Parameters passed to the extension in the `extensions` array on individual trials.
|
|
65
|
+
|
|
66
|
+
| Parameter | Type | Default | Description |
|
|
67
|
+
|-----------|------|---------|-------------|
|
|
68
|
+
| trialId | string \| number | `undefined` | Trial ID or index |
|
|
69
|
+
|
|
70
|
+
## Data Generated
|
|
71
|
+
|
|
72
|
+
When the extension is added to a trial, the following data is appended to the trial's data object.
|
|
73
|
+
|
|
74
|
+
| Name | Type | Description |
|
|
75
|
+
|------|------|-------------|
|
|
76
|
+
| tobii_data | array | Array of gaze data samples collected during the trial. Each sample is a `GazeData` object (see below). |
|
|
77
|
+
|
|
78
|
+
### GazeData Object
|
|
79
|
+
|
|
80
|
+
Each element in the `tobii_data` array contains:
|
|
81
|
+
|
|
82
|
+
| Field | Type | Description |
|
|
83
|
+
|-------|------|-------------|
|
|
84
|
+
| x | number | X coordinate (normalized 0-1 or pixels, depending on config) |
|
|
85
|
+
| y | number | Y coordinate (normalized 0-1 or pixels, depending on config) |
|
|
86
|
+
| timestamp | number | Timestamp in ms (Tobii device clock) |
|
|
87
|
+
| browserTimestamp | number | Device timestamp mapped to `performance.now()` domain |
|
|
88
|
+
| leftValid | boolean | Whether the left eye data is valid |
|
|
89
|
+
| rightValid | boolean | Whether the right eye data is valid |
|
|
90
|
+
| leftPupilDiameter | number | Left eye pupil diameter |
|
|
91
|
+
| rightPupilDiameter | number | Right eye pupil diameter |
|
|
92
|
+
|
|
93
|
+
## Extension API
|
|
94
|
+
|
|
95
|
+
All methods are accessible via `jsPsych.extensions.tobii.*`. See the [full API reference](../../README.md#extension-api-reference) for detailed documentation.
|
|
96
|
+
|
|
97
|
+
### Connection
|
|
98
|
+
|
|
99
|
+
| Method | Returns | Description |
|
|
100
|
+
|--------|---------|-------------|
|
|
101
|
+
| `connect()` | `Promise<void>` | Connect to WebSocket server |
|
|
102
|
+
| `disconnect()` | `Promise<void>` | Disconnect from server |
|
|
103
|
+
| `isConnected()` | `boolean` | Check connection status |
|
|
104
|
+
| `getConnectionStatus()` | `ConnectionStatus` | Get detailed connection status |
|
|
105
|
+
|
|
106
|
+
### Eye Tracking Control
|
|
107
|
+
|
|
108
|
+
| Method | Returns | Description |
|
|
109
|
+
|--------|---------|-------------|
|
|
110
|
+
| `startTracking()` | `Promise<void>` | Start gaze data collection |
|
|
111
|
+
| `stopTracking()` | `Promise<void>` | Stop gaze data collection |
|
|
112
|
+
| `isTracking()` | `boolean` | Check tracking status |
|
|
113
|
+
|
|
114
|
+
### Calibration
|
|
115
|
+
|
|
116
|
+
| Method | Returns | Description |
|
|
117
|
+
|--------|---------|-------------|
|
|
118
|
+
| `startCalibration()` | `Promise<void>` | Start calibration procedure |
|
|
119
|
+
| `collectCalibrationPoint(x, y)` | `Promise<{ success }>` | Collect data for a point (0-1) |
|
|
120
|
+
| `computeCalibration()` | `Promise<CalibrationResult>` | Compute calibration |
|
|
121
|
+
| `getCalibrationData()` | `Promise<CalibrationResult>` | Get calibration quality metrics |
|
|
122
|
+
|
|
123
|
+
### Validation
|
|
124
|
+
|
|
125
|
+
| Method | Returns | Description |
|
|
126
|
+
|--------|---------|-------------|
|
|
127
|
+
| `startValidation()` | `Promise<void>` | Start validation procedure |
|
|
128
|
+
| `collectValidationPoint(x, y, samples?)` | `Promise<void>` | Collect data for a point (0-1) |
|
|
129
|
+
| `computeValidation()` | `Promise<ValidationResult>` | Compute validation metrics |
|
|
130
|
+
|
|
131
|
+
### Data Access
|
|
132
|
+
|
|
133
|
+
| Method | Returns | Description |
|
|
134
|
+
|--------|---------|-------------|
|
|
135
|
+
| `getCurrentGaze()` | `Promise<GazeData \| null>` | Get current gaze position |
|
|
136
|
+
| `getGazeData(start, end)` | `Promise<GazeData[]>` | Get gaze data for a time range |
|
|
137
|
+
| `getRecentGazeData(durationMs)` | `GazeData[]` | Get recent data from buffer |
|
|
138
|
+
| `getUserPosition()` | `Promise<UserPositionData \| null>` | Get head position data |
|
|
139
|
+
| `clearGazeData()` | `void` | Clear stored gaze data |
|
|
140
|
+
|
|
141
|
+
### Coordinate Utilities
|
|
142
|
+
|
|
143
|
+
| Method | Returns | Description |
|
|
144
|
+
|--------|---------|-------------|
|
|
145
|
+
| `normalizedToPixels(x, y)` | `Coordinates` | Convert normalized (0-1) to pixels |
|
|
146
|
+
| `pixelsToNormalized(x, y)` | `Coordinates` | Convert pixels to normalized (0-1) |
|
|
147
|
+
| `windowToContainer(x, y, el?)` | `Coordinates` | Convert window to container-relative coords |
|
|
148
|
+
| `getScreenDimensions()` | `ScreenDimensions` | Get window dimensions |
|
|
149
|
+
| `getContainerDimensions(el?)` | `ScreenDimensions` | Get container dimensions |
|
|
150
|
+
| `isWithinContainer(x, y, el?)` | `boolean` | Check if point is inside container |
|
|
151
|
+
| `calculateDistance(p1, p2)` | `number` | Euclidean distance between two points |
|
|
152
|
+
|
|
153
|
+
### Data Export
|
|
154
|
+
|
|
155
|
+
| Method | Returns | Description |
|
|
156
|
+
|--------|---------|-------------|
|
|
157
|
+
| `exportToCSV(data, filename)` | `void` | Export data to CSV file |
|
|
158
|
+
| `exportToJSON(data, filename)` | `void` | Export data to JSON file |
|
|
159
|
+
|
|
160
|
+
### Time Synchronization
|
|
161
|
+
|
|
162
|
+
| Method | Returns | Description |
|
|
163
|
+
|--------|---------|-------------|
|
|
164
|
+
| `getTimeOffset()` | `number` | Get browser-server time offset (ms) |
|
|
165
|
+
| `isTimeSynced()` | `boolean` | Check if time is synced with server |
|
|
166
|
+
| `toDeviceTime(performanceNow)` | `number` | Convert `performance.now()` to device time |
|
|
167
|
+
| `toLocalTime(deviceTime)` | `number` | Convert device time to `performance.now()` |
|
|
168
|
+
| `isDeviceTimeSynced()` | `boolean` | Check if device time sync is established |
|
|
169
|
+
| `getTimeSyncStatus()` | `DeviceTimeSyncStatus` | Get full sync status and diagnostics |
|
|
170
|
+
| `validateTimestampAlignment(samples)` | `TimestampAlignmentResult \| null` | Validate timestamp alignment |
|
|
171
|
+
|
|
172
|
+
### Configuration
|
|
173
|
+
|
|
174
|
+
| Method | Returns | Description |
|
|
175
|
+
|--------|---------|-------------|
|
|
176
|
+
| `setConfig(config)` | `void` | Update extension configuration |
|
|
177
|
+
| `getConfig()` | `InitializeParameters` | Get current configuration |
|
|
178
|
+
|
|
179
|
+
## Example
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
import { initJsPsych } from 'jspsych';
|
|
183
|
+
import TobiiExtension from '@jspsych/extension-tobii';
|
|
184
|
+
import TobiiCalibrationPlugin from '@jspsych/plugin-tobii-calibration';
|
|
185
|
+
import HtmlKeyboardResponsePlugin from '@jspsych/plugin-html-keyboard-response';
|
|
186
|
+
|
|
187
|
+
const jsPsych = initJsPsych({
|
|
188
|
+
extensions: [
|
|
189
|
+
{
|
|
190
|
+
type: TobiiExtension,
|
|
191
|
+
params: {
|
|
192
|
+
connection: { url: 'ws://localhost:8080', autoConnect: true },
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
on_finish: () => {
|
|
197
|
+
const data = jsPsych.data.get().values();
|
|
198
|
+
jsPsych.extensions.tobii.exportToCSV(data, 'gaze_data.csv');
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const timeline = [];
|
|
203
|
+
|
|
204
|
+
timeline.push({
|
|
205
|
+
type: TobiiCalibrationPlugin,
|
|
206
|
+
calibration_points: 9,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
timeline.push({
|
|
210
|
+
type: HtmlKeyboardResponsePlugin,
|
|
211
|
+
stimulus: '<p>Look at this stimulus</p>',
|
|
212
|
+
extensions: [{ type: TobiiExtension }],
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
jsPsych.run(timeline);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Citation
|
|
219
|
+
|
|
220
|
+
If you use this extension in your research, please cite it. See [CITATION.cff](CITATION.cff).
|