https://github.com/hci-lab-um/web-ssvep-stimuli-generators
CSS and WebGL were adopted to implement four cross-platform Steady State Visually Evoked Potential (SSVEP) stimuli-generator libraries, whose stimuli are produced via constant-period and square wave approximation techniques, for use in a Brain-Computer Interface (BCI) context. These libraries are configured to run as spellers, yet can easily be altered to cater for a wide range of use cases.
https://github.com/hci-lab-um/web-ssvep-stimuli-generators
css3 javascript ssvep ssvep-bci webgl
Last synced: 2 months ago
JSON representation
CSS and WebGL were adopted to implement four cross-platform Steady State Visually Evoked Potential (SSVEP) stimuli-generator libraries, whose stimuli are produced via constant-period and square wave approximation techniques, for use in a Brain-Computer Interface (BCI) context. These libraries are configured to run as spellers, yet can easily be altered to cater for a wide range of use cases.
- Host: GitHub
- URL: https://github.com/hci-lab-um/web-ssvep-stimuli-generators
- Owner: hci-lab-um
- License: gpl-3.0
- Created: 2022-04-04T09:16:26.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2022-04-08T23:52:32.000Z (about 3 years ago)
- Last Synced: 2024-05-28T16:27:54.137Z (about 1 year ago)
- Topics: css3, javascript, ssvep, ssvep-bci, webgl
- Language: JavaScript
- Homepage:
- Size: 313 KB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# SSVEP Stimuli-Generator Libraries
CSS and WebGL were adopted to implement four cross-platform Steady State Visually Evoked Potential (SSVEP) stimuli-generator libraries, whose stimuli are produced via constant-period and square wave approximation techniques, for use in a Brain-Computer Interface (BCI) context. These libraries are configured to run as spellers, yet can easily be altered to cater for a wide range of use cases.
More information about these libraries can be found in this peer reviewed publication by the same authors: [Towards Accurate Browser-based SSVEP Stimuli Generation](https://www.scitepress.org/Papers/2020/101594/pdf/index.html).
In alignment with [existing documentation](https://developer.mozilla.org/en-US/docs/Web/Performance/CSS_JavaScript_animation_performance), it was found that CSS animations are more stable and performant than their WebGL counterparts.
## Generating on-page stimuli
There are 4 stimuli generators in this repository, `CSS+Square Wave Approximation`, `CSS+Constant Period`, `WebGL+Square Wave Approximation` and `WebGL+Constant Period`.After importing the library, you can create any number of stimuli on the page using the following `data-*` attributes:
1. `data-frequency`: specifying the SSVEP stimulus frequency
2. `data-light-color`: specifying the light color of the flickering SSVEP stimulus
3. `data-dark-color`: specifying the dark color of the flickering SSVEP stimulus
4. `data-phase-shift`: specifying the phase shift (frames delay) for the SSVEP stimulus
5. `data-pattern`: specifying the flickering button's pattern. You can choose from `solid`, `dot`, `chequered` or `line` pattern types.The `data-light-colour` and `data-dark-colour` attributes define how colors are applied based on the chosen flickering pattern:
- **Solid**: The stimulus alternates between `data-light-colour` and `data-dark-colour` to create a flickering effect.
- **Chequered**: The squares within the pattern will be displayed in `data-light-colour` and `data-dark-colour`.
- **Dot**: The dots will be displayed in `data-light-colour` and `data-dark-colour`, while the background remains **white**.
- **Line**: The **background** will be `data-dark-colour`, and the **lines** will be `data-light-colour`.The following is a sample screenshot showcasing all four `data-pattern` types in action:

### Begin Stimuli Generation
To begin stimuli generation, you must select your HTML elements and add to the manager### 1. CSS
Stimuli can be defined as follows for CSS:```html
Button 1
Button 2
Button 3
Button 4
``````html
import * as stimuli from "./dist/index.js"
const elements = document.querySelectorAll('button')
// ----------- CSS Methods -----------
const manager = new window.stimuli.CSS('approximation', elements.length)
// const manager = new window.stimuli.CSS('periodic', elements.length)elements.forEach(el => manager.set(el)) // Add Elements
manager.start() // Start Stimuli Generation```
### 2. WebGL
Stimuli can be defined as follows for WebGL:```html
``````html
import * as stimuli from "./dist/index.js"
const elements = document.querySelectorAll('button')
// ----------- WebGL Methods -----------
const canvas = document.body.querySelector('canvas')
const manager = new window.stimuli.WebGL('approximation', canvas, elements.length)
// const manager = new window.stimuli.WebGL('periodic', canvas, elements.length)elements.forEach(el => manager.set(el)) // Add Elements
manager.start() // Start Stimuli Generation```
```css
/* Styling the canvas so that it fills the whole screen and the button text above the canvas */
.button-text {
position: relative;
z-index: 2; /* Contains a higher z-index than the canvas */
}#canvas {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 1; /* Contains a lower z-index than the canvas */
}
```### Add Stimuli
You can add more stimuli by passing one or more elements to the `start()` method:``` javascript
manager.start(document.getElementById('new_element'))
// manager.start(document.body.querySelectorAll('.other'))
```This technique also allows you to selectively start a subset of elements.
### Cancel Stimuli Generation
You can cancel all ongoing stimuli generation by calling the `stop()` method:``` javascript
manager.stop()
```Or stop a subset by passing one or more elements as the first argument:
``` javascript
manager.stop(document.getElementById('new_element'))
// manager.stop(document.body.querySelectorAll('.other'))
```### Node.js Example (Using CSS)
To use the SSVEP stimuli library in a Node.js project:
1. Install via npm. Run the following command: `npm install ssvep-stimuli`.
2. Use the following code in your JavaScript file:```javascript
const stimuli = require('./dist/index.js');// Simulating HTML button elements for the example
const elements = [
{ frequency: 6.67, lightColor: '255,255,255,1', darkColor: '0,0,0,1', phaseShift: 0, pattern: 'solid' },
{ frequency: 7, lightColor: '0,0,255,1', darkColor: '0,255,0,1', phaseShift: 0, pattern: 'chequered' },
{ frequency: 8.57, lightColor: '0,0,255,1', darkColor: '255,0,0,1', phaseShift: 0, pattern: 'dot' },
{ frequency: 10, lightColor: '255,255,255,1', darkColor: '127,127,127,1', phaseShift: 0, pattern: 'line' }
];const manager = new stimuli.CSS('approximation', elements.length);
// const manager = new stimuli.CSS('periodic', elements.length);elements.forEach(el => manager.set(el));
manager.start();
```### Node.js Example (Using WebGL)
To use the SSVEP stimuli library in a Node.js project:
1. Install via npm. Run the following command: `npm install ssvep-stimuli`.
2. Use the following code in your JavaScript file:```javascript
const stimuli = require('./dist/index.js');// For WebGL, you would typically need to initialise a WebGL context.
// Here, we assume you're using a package like `headless-gl` or similar.const { createCanvas } = require('canvas'); // Example: 'canvas' package for WebGL context in Node.js
const canvas = createCanvas(800, 600); // Create a canvas to simulate the WebGL context// Simulating HTML button elements for the example
const elements = [
{ frequency: 6.67, lightColor: '255,255,255,1', darkColor: '0,0,0,1', phaseShift: 0, pattern: 'solid' },
{ frequency: 7, lightColor: '0,0,255,1', darkColor: '0,255,0,1', phaseShift: 0, pattern: 'chequered' },
{ frequency: 8.57, lightColor: '0,0,255,1', darkColor: '255,0,0,1', phaseShift: 0, pattern: 'dot' }
{ frequency: 10, lightColor: '255,255,255,1', darkColor: '127,127,127,1', phaseShift: 0, pattern: 'line' }
];const manager = new stimuli.WebGL('approximation', canvas, elements.length);
// const manager = new stimuli.WebGL('periodic', canvas, elements.length);elements.forEach(el => { manager.set(el); });
manager.start();
```## Roadmap
- Add and remove elements based on visibility in the window.
- Dynamically change the frequency values applied to an element
- Automatically assign for maximum discriminability.
- Position WebGL Canvas behind arbitrary elements across an entire a webpage *with scrolling*.
- Expose a way to assign your own CSS rules and/or WebGL intensities## Known Issues
### WebGL
1. Dynamically adding elements using WebGL techniques will create too many contexts and halt execution.## Acknowledgments
These libraries were developed by [Alison Camilleri](https://github.com/alison-camilleri) to fulfill part of the requirements for the award of a Master of Science in Computer Information Systems degree.### Supervisory Team
#### [Dr Chris Porter](https://www.um.edu.mt/profile/chrisporter)
Department of Computer Information Systems, Faculty of ICT#### [Dr Tracey Camilleri](https://www.um.edu.mt/profile/traceycamilleri)
Department of Systems & Control Engineering, Faculty of Engineering### Other Contributors
#### [Garrett Flynn](https://github.com/garrettmflynn)
Founding Partner at [Brains@Play](https://github.com/brainsatplay)
- Refactored the libraries for publication (April 2022)#### [Daniel Calleja](https://github.com/daniel-calleja17) & (https://github.com/dcalleja17)
Research Support Officer on the BrainWeb Project
- Arranged the functionality of `data-dark-color` (December 2024)
- Implemented different pattern types for stimuli for both CSS and WebGL (January 2025)