Skip to main content
Glama
smart-vick
by smart-vick
README.md
# Neuro-Cube

**A 3D Rubik's Cube you solve with your attention.** Sustained mental focus —
measured live from EEG — rotates the selected face. Ships with a
hardware-agnostic **BrainFlow → MCP bridge** so any AI assistant can read your
real-time focus state.

Runs fully without an EEG headset (`--mock`), so you can try it right now.

![Neuro-Cube](tests/snapshots/05_retention_hud.png)

---

## Why this exists

Consumer EEG splits into two camps: polished but closed focus-training apps
(Muse, FocusCalm), and open developer platforms with no real application on top
(OpenBCI, Neurosity). Neuro-Cube sits in the gap — **open, complete, and
readable**:

| | Neuro-Cube | Closed apps | Dev platforms |
|---|---|---|---|
| Works with any BrainFlow headset | ✅ | ❌ one vendor | partial |
| Complete interactive 3D app | ✅ | ❌ | ❌ |
| Readable, tested source | ✅ 136 checks | ❌ closed | varies |
| Runs with **no hardware** | ✅ `--mock` | ❌ | ❌ |
| Exposes brain state to AI (MCP) | ✅ any headset | ❌ | one vendor, $999 device |

---

## Quick start (no hardware needed)

```bash
git clone https://github.com/smart-vick/neuro-cube.git
cd neuro-cube
pip install -r requirements.txt
python main.py --mock
```

| Key | Action |
|-----|--------|
| `←` / `→` | Select which face to turn (highlighted on the cube) |
| `Space` | Simulate a focus event → turns the selected face |
| `u d l r f b` | Direct moves (`+Shift` = counter-clockwise) |
| `s` | Scramble, and reset the solve timer |

Scramble it, solve it, and the timer + move counter tell you how you did.

**With a headset** — no code changes, just drop the `--mock`:

```bash
python main.py                 # BrainFlow synthetic board (simulated signal)
```

Focus is computed as `beta / (beta + alpha + theta)` band power. Sustained focus
above threshold turns the selected face; hysteresis and a cooldown stop it
firing repeatedly.

---

## The MCP bridge

A standalone MCP server that exposes your live focus state to **any** MCP client
(Claude Desktop, etc.) — the same idea as Neurosity's built-in MCP support, but
for any BrainFlow-supported headset instead of one $999 device.

```bash
pip install -r requirements-mcp.txt
python -m mcp_bridge.server                                   # synthetic board
python -m mcp_bridge.server --board-id 38 --serial-port COM3  # real headset
python -m mcp_bridge.demo_client                              # see it working
```

Register it with an MCP client:

```json
{ "mcpServers": { "neuro-cube-brain": {
    "command": "python", "args": ["-m", "mcp_bridge.server"],
    "cwd": "/absolute/path/to/neuro-cube" } } }
```

It exposes one tool, `get_brain_state`:

```json
{ "state": "focused", "focus": 0.7926, "focused": true,
  "has_data": true, "age_seconds": 0.056, "board": "synthetic" }
```

`state` is `focused`, `unfocused`, or `no_signal`. Readings older than 2 s
degrade to `no_signal`, so a stalled poll loop or a dropped headset can never
report a stale "focused".

> **One headset, one process.** The bridge and the cube each open their own
> BrainFlow session, so pointing both at the *same physical device* will fail —
> the second `prepare_session()` is rejected, or one process takes the stream and
> the other goes quiet with no visible error. Run one at a time, or run the
> bridge on the synthetic board while the cube uses the headset.

---

## How it works

```
BrainFlowPoller (daemon thread)      CubeState (lock-guarded)         App (main thread)
  poll EEG -> filter -> focus         magiccube + threading.Lock       Panda3D task, per frame
  |- event_queue.put(event) --------> execute_move() validates ------> drain queues, animate
  |- read_state() (snapshot) --> MCP bridge (separate process)
```

Four rules keep it race-free, and they are not negotiable:

1. **One-way queues.** The EEG thread never imports Panda3D, never touches cube
   state, never calls the view. It only puts events on a queue.
2. **One source of truth.** Every mutation goes through `CubeState.execute_move()`
   under a lock; consumers only ever see immutable snapshots.
3. **The render loop never blocks.** Every queue read is `get_nowait()`. Heavy
   signal processing happens only on the daemon thread.
4. **Moves are serialized.** One face rotation at a time; bursts queue up rather
   than tearing the scene graph.

The MCP bridge reads a separate lock-guarded `FocusState` snapshot rather than
the event queue, so it observes brain state without stealing events from the cube.

---

## Testing

```bash
pip install -r requirements-dev.txt
pytest tests/                 # 9 suites, ~136 checks (~50s)
pytest tests/ -m "not slow"   # skip board-driven suites (~15s)
python tests/test_directions.py   # any suite standalone
```

Suites run in subprocesses because Panda3D's `ShowBase` is a process-level
singleton. Notable coverage:

- **`test_directions.py`** — all 18 moves verified against *independent* vector
  algebra. An inverse-to-solved check can't catch a consistently mirrored
  renderer; this can.
- **`test_focus_metric.py`** — signal processing driven by crafted sine waves:
  20 Hz (beta) → focus 1.0, 10 Hz (alpha) → 0.0.
- **`test_focus_gate.py`** — hysteresis and cooldown with an injected clock,
  including a flapping storm rate-limited from ~100 triggers down to ~10.
- **`render_snapshot.py`** — headless rendering, verified by screenshot.

The suite has caught four real bugs, including a flat/disconnected electrode
reading as focus ≈ 0.5 (dangerously near the trigger threshold) and BrainFlow's
logger corrupting the MCP server's stdio JSON-RPC channel.

---

## Hardware

Any [BrainFlow-supported board](https://brainflow.readthedocs.io/en/stable/SupportedBoards.html)
— OpenBCI, Muse, Neurosity, Ganglion, and others — via `--board-id`. Nothing in
the code is vendor-specific.

**Note:** the default thresholds (`FOCUS_ON_THRESHOLD = 0.65`,
`FOCUS_OFF_THRESHOLD = 0.45`) are placeholders. Real EEG varies per person and
per headset, so calibrate against your own baseline before expecting good
control.

## Status

Cube, renderer, retention hook, and MCP bridge are complete and tested.
Outstanding: real-hardware threshold calibration, and polish (camera orbit,
counter-clockwise moves via focus duration).

## License

MIT — see [LICENSE](LICENSE).