Connects to a Muse device using Web Bluetooth API or uses mock data for development. Automatically detects the device type (legacy Muse 2 or Muse S Athena) and uses the appropriate protocol.
Parameters:
options(Object, optional) - Configuration optionsmock(boolean, default: false) - Enable mock mode to use pre-recorded datamockDataPath(string, optional) - Path to custom CSV file for mock data
Examples:
// Connect to real device (auto-detects Muse 2 or Muse S Athena)
const muse = await connectMuse();
console.log(muse.modelName); // "Muse 2" or "Muse Athena"
// Connect with mock data (no device required)
const muse = await connectMuse({ mock: true });
// Connect with custom mock data
const muse = await connectMuse({
mock: true,
mockDataPath: "/path/to/custom-data.csv",
});Returns a Muse instance.
Abstract base class for Muse device connections. Handles Bluetooth service discovery, protocol management, and data decoding for both legacy Muse and Muse S Athena devices. Cannot be instantiated directly — extend it to create custom implementations.
class CustomMuse extends MuseBase {
constructor(options) {
super(options);
}
}Parameters:
options(Object, optional)mock(boolean, default: false) - Enable mock modemockDataPath(string, optional) - Path to custom CSV file for mock data
| Property | Type | Description |
|---|---|---|
state |
number |
Connection state: 0 = idle, 1 = connecting, 2 = streaming |
modelName |
string |
"Muse 2" (legacy) or "Muse Athena" (detected automatically) |
mock |
boolean |
Whether mock mode is enabled |
Override these methods in subclasses to handle incoming data:
| Method | Description |
|---|---|
eegData(n, event) |
Legacy Muse EEG data for channel n (0-4) |
athenaEegData(n, event) |
Muse S Athena EEG data for channel n (0-2) |
batteryData(event) |
Battery level update |
accelerometerData(event) |
Accelerometer data |
gyroscopeData(event) |
Gyroscope data |
ppgData(n, event) |
PPG data for channel n (0-2) |
controlData(event) |
Control/info messages from device |
disconnected() |
Device disconnected |
devicePicked(deviceName) |
User selected a device from the picker |
These methods decode raw Bluetooth events into usable values:
| Method | Returns |
|---|---|
eventBatteryData(event) |
Battery percentage (number) |
eventAccelerometerData(event) |
number[3][3] — 3 axes, 3 samples each |
eventGyroscopeData(event) |
number[3][3] — 3 axes, 3 samples each |
eventEEGData(event) |
number[] — decoded 12-bit EEG samples |
eventPPGData(event) |
number[] — decoded 24-bit PPG samples |
eventControlData(event) |
object — parsed JSON info fields |
| Method | Description |
|---|---|
connect() |
Connect to device (or start mock data stream) |
disconnect() |
Disconnect from device and stop data streaming |
The main class for interacting with the Muse device. Extends MuseBase with circular buffer storage for all sensor data.
new Muse(options);Parameters:
options(Object, optional) - Configuration optionsmock(boolean, default: false) - Enable mock modemockDataPath(string, optional) - Path to custom CSV file for mock data
Example:
const muse = new Muse({ mock: true });
await muse.connect();
console.log(muse.modelName); // "Muse 2" or "Muse Athena"| Property | Type | Description |
|---|---|---|
eeg |
MuseCircularBuffer[5] |
EEG channel buffers (TP9, AF7, AF8, TP10, AUX) |
ppg |
MuseCircularBuffer[3] |
PPG channel buffers |
accelerometer |
MuseCircularBuffer[3] |
Accelerometer axis buffers (x, y, z) |
gyroscope |
MuseCircularBuffer[3] |
Gyroscope axis buffers (x, y, z) |
batteryLevel |
number | null |
Battery percentage (0-100) |
info |
object |
Device info from control characteristic |
state |
number |
Connection state (0=idle, 1=connecting, 2=streaming) |
modelName |
string |
"Muse 2" or "Muse Athena" |
mock |
boolean |
Whether mock mode is enabled |
| Method | Description |
|---|---|
connect() |
Connect to device (or start mock data stream) |
disconnect() |
Disconnect from device and stop data streaming |
A fixed-size circular buffer used for storing streaming sensor data (EEG, PPG, accelerometer, gyroscope).
new MuseCircularBuffer(size);Parameters:
size(number) - The maximum number of values the buffer can hold
| Property | Type | Description |
|---|---|---|
length |
number |
Current number of values in the buffer |
isFull |
boolean |
Whether the buffer is full |
lastwrite |
number |
Timestamp (ms) of the last write |
| Method | Returns | Description |
|---|---|---|
read() |
number | null |
Read and remove the next value, or null if empty |
write(value) |
void |
Write a value (ignored if buffer is full) |
Example:
import { MuseCircularBuffer } from "web-muse";
const buffer = new MuseCircularBuffer(256);
buffer.write(1.5);
buffer.write(2.3);
console.log(buffer.read()); // 1.5
console.log(buffer.length); // 1Sets up a continuous data pipeline that reads EEG samples from a connected Muse device at 256Hz and passes them to a callback.
Parameters:
muse(Muse) - A connected Muse instancesetRawEEG(Function) - Callback receiving an array of 4 channel values on each tick
Returns: A cleanup function that stops the pipeline.
Example:
import { setupPipeline } from "web-muse/eeg";
const stopPipeline = setupPipeline(muse, (rawEEG) => {
console.log("EEG sample:", rawEEG); // [ch1, ch2, ch3, ch4]
});
// Later...
stopPipeline();Starts recording EEG data into an internal buffer.
import { startRecording } from "web-muse/eeg";
startRecording();Stops recording and returns processed data. Requires at least 3 seconds of recorded data (768 samples at 256Hz).
Returns: object | null — Returns null if not enough data was recorded.
import { stopRecording } from "web-muse/eeg";
const result = stopRecording();
if (result) {
console.log(result);
}Return shape:
{
rawEEG: number[], // Latest sample per channel [ch1, ch2, ch3, ch4]
spectraData: number[][], // Power spectrum per channel
powerData: object[], // Power by frequency band per channel
// Each: { delta, theta, alpha, beta, gamma }
alphaData: number[] // Alpha band power per channel
}React context provider for EEG functionality. Wraps your app to provide EEG state and connection methods to child components via the useEEG hook.
Internally sets up the data pipeline (setupPipeline) when a device connects, and cleans it up on unmount.
import { EEGProvider } from "web-muse/react";
<EEGProvider>
<App />
</EEGProvider>React hook for accessing EEG state and connection methods from EEGProvider.
import { useEEG } from "web-muse/react";
const {
muse, // Muse instance (or null)
isConnected, // boolean — connection status
isMockData, // boolean — whether using mock data
rawEEG, // number[] — latest EEG readings from pipeline
connectMuse, // (options?) => Promise<void> — connect to device
connectMockData, // () => Promise<void> — DEPRECATED, use connectMuse({ mock: true })
disconnectEEG, // () => void — disconnect from device
} = useEEG();Example:
function BrainView() {
const { isConnected, connectMuse, disconnectEEG, rawEEG } = useEEG();
return (
<div>
{!isConnected ? (
<>
<button onClick={() => connectMuse()}>Connect Device</button>
<button onClick={() => connectMuse({ mock: true })}>Use Mock</button>
</>
) : (
<>
<div>EEG: {JSON.stringify(rawEEG)}</div>
<button onClick={disconnectEEG}>Disconnect</button>
</>
)}
</div>
);
}Note:
connectMockDatais deprecated. UseconnectMuse({ mock: true })instead.
The library processes EEG data into the following frequency bands:
| Band | Frequency Range | Associated With |
|---|---|---|
| Delta | 0.5 - 4 Hz | Deep sleep |
| Theta | 4 - 8 Hz | Drowsiness, meditation |
| Alpha | 8 - 13 Hz | Relaxation, eyes closed |
| Beta | 13 - 30 Hz | Active thinking, focus |
| Gamma | 30 - 100 Hz | Higher cognitive processing |
- Raw data collection at 256Hz sampling rate
- Data sanitization — null/NaN values are interpolated using last-known-good values
- Power spectrum calculation using the periodogram method (DFT)
- Frequency band power extraction
- Real-time data streaming to application
| Device | Service | EEG Format |
|---|---|---|
| Muse 2016 | Legacy (0xfe8d) |
12-bit, 5 channels |
| Muse 2 | Legacy (0xfe8d) |
12-bit, 5 channels |
| Muse S Athena | Custom (c8c0a708-...) |
14-bit multiplexed (OpenMuse) |
The library automatically discovers available services and detects whether the connected device is a legacy Muse or Muse S Athena, selecting the appropriate EEG parsing and start sequence.
Mock mode allows development and testing without a physical Muse device. When enabled, the library loads pre-recorded EEG data from a CSV file and streams it at the correct sample rate, looping continuously.
- No device required: Perfect for development and testing
- Realistic timing: Respects original timestamps from recordings
- Seamless API: Works identically to real device connection
- Custom data: Support for custom CSV files
The CSV file should follow this format:
Timestamp (ms),TP9 (left ear),AF7 (left forehead),AF8 (right forehead),TP10 (right ear)
5,-0.48828125,0,-0.48828125,-0.48828125
7,0,-0.48828125,-0.48828125,0
10,4.8828125,-0.48828125,2.44140625,3.90625
...Columns:
Timestamp (ms): Timestamp in millisecondsTP9: Left ear electrode dataAF7: Left forehead electrode dataAF8: Right forehead electrode dataTP10: Right ear electrode data
Data values should be in the range of approximately -1000 to 1000 (scaled EEG values in microvolts).
Basic mock mode:
const muse = await connectMuse({ mock: true });
// Works just like real device!Custom mock data file:
const muse = await connectMuse({
mock: true,
mockDataPath: "/data/my-recording.csv",
});Switching between real and mock:
const isDevelopment = process.env.NODE_ENV === "development";
const muse = await connectMuse({ mock: isDevelopment });The library includes error handling for:
- Bluetooth connection issues (device not found, GATT connection failed)
- No compatible Muse service found on device
- Data processing errors
- Device disconnection events
- Mock data loading errors
Errors can be caught using standard try-catch blocks:
try {
const muse = await connectMuse();
} catch (error) {
if (error.message.includes("No compatible Muse service")) {
console.error("Device is not a supported Muse headband");
} else {
console.error("Connection error:", error);
}
}
// With mock mode
try {
await connectMuse({ mock: true });
} catch (error) {
console.error("Failed to load mock data:", error);
}