This plan outlines a significant upgrade to transform the EEG Dipole Demo from a single-dipole educational tool into a research-grade forward modeling platform. The upgrade introduces:
- Blob Mode - Active region modeling with collective controls
- 3D Positioning - Full nasion-inion axis placement
- Time Series Drive - User-uploaded amplitude modulation
- Data Export - 10/20 electrode voltage time series output
- Single HTML file (~2.4MB, mostly base64-encoded coronal brain image)
- Coronal plane constraint - Dipoles fixed at y=0
- Point dipole model - V ∝ (p · R) / |R|³
- 19 electrodes - Standard 10-20 montage (Fp1, Fp2, F3, F4, F7, F8, Fz, T3, T4, C3, C4, Cz, T5, T6, P3, P4, Pz, O1, O2, Oz)
- Two views - Coronal slice (x-z) + topographic map (x-y projected)
- Real-time rendering - requestAnimationFrame loop
+z (superior/dorsal)
|
| +y (anterior/nasion)
| /
| /
| /
+---------- +x (right)
Current: dipoles at y=0 (coronal plane)
Proposed: full y-axis movement (-1 to +1)
Concept: Instead of placing individual point dipoles, users create a "blob" representing an active cortical patch. The blob contains multiple dipoles with coherent orientation.
Implementation Options:
| Option | Description | Pros | Cons |
|---|---|---|---|
| A. Gaussian Cluster | 3D Gaussian distribution of dipole density | Biologically plausible, smooth falloff | Computationally heavier |
| B. Uniform Sphere | Uniform dipole density within spherical region | Simple, fast | Sharp boundary unrealistic |
| C. Surface Patch | Dipoles constrained to brain surface | Most realistic | Requires surface mesh |
Recommended: Option A (Gaussian Cluster) - Good balance of realism and simplicity.
Blob Properties:
- Position (x, y, z) - center of mass
- Radius - σ parameter of Gaussian
- Orientation (θ, φ) - direction of all dipoles in blob
- Strength - total dipole moment magnitude
- Dipole count - sampling density (affects accuracy vs. performance)
Complexity: MEDIUM
- New data structure for blobs
- Collective potential computation (sum N dipole contributions)
- UI for blob radius, orientation dial
- Visual representation (ellipsoid/cloud)
UI Changes:
Mode: [Single Dipole ↔ Blob Region] toggle
Blob Controls:
├── Radius slider: 0.05 - 0.3 (brain units)
├── Orientation dial: 0° - 360° (circular control)
├── Tilt slider: 0° - 90° (radial vs tangential)
├── Strength slider: 0.1 - 2.0
└── Resolution: [Low|Med|High] (dipole sampling)
Current Limitation: All dipoles at y=0. User cannot place sources in frontal or occipital regions accurately.
Challenge: How to visualize and control the 3rd dimension?
Implementation Options:
| Option | Description | Complexity | User Experience |
|---|---|---|---|
| A. Y-Slider Only | Simple slider for y-position | LOW | Limited spatial intuition |
| B. Sagittal View | Add 3rd canvas showing x-y or y-z plane | HIGH | Full 3D understanding |
| C. 3D Rotation | WebGL 3D head model | VERY HIGH | Best visualization |
| D. Hybrid | Y-slider + topomap indicator | MEDIUM | Good balance |
Recommended: Option D (Hybrid) initially, with Option B as a follow-up enhancement.
Hybrid Approach:
- Add Y-position slider to blob/dipole controls
- Show blob projection on topomap (circle at projected position)
- Topomap becomes partially 3D-aware (blob appears as dot/circle showing depth)
- Optional: Add sagittal slice view later
Brain Boundary in 3D:
- Current: 2D mask from coronal image
- Needed: 3D brain model (ellipsoid approximation or volumetric)
Simplified 3D Brain Model:
// Ellipsoid approximation
function inBrain3D(x, y, z) {
const cx = 0, cy = 0, cz = -0.05; // center
const rx = 0.75, ry = 0.80, rz = 0.70; // radii
const dx = (x - cx) / rx;
const dy = (y - cy) / ry;
const dz = (z - cz) / rz;
return (dx*dx + dy*dy + dz*dz) <= 1.0;
}Complexity: MEDIUM-HIGH
- Y-position control trivial
- Visualization of depth requires thought
- 3D brain constraint needs new model or volumetric data
- Sagittal view (optional) requires new anatomical image
Concept: User uploads a file containing amplitude values over time. The blob's strength follows this time course during playback.
File Format Options:
Option A: Simple CSV
-----------------------
time,amplitude
0.000,0.0
0.001,0.23
0.002,0.45
...
Option B: Multi-channel CSV (for multiple blobs)
-------------------------------------------------
time,blob1,blob2,blob3
0.000,0.0,0.1,0.0
0.001,0.23,0.15,0.05
...
Option C: JSON with metadata
-----------------------------
{
"sampleRate": 1000,
"duration": 2.0,
"channels": [
{"name": "blob1", "data": [0.0, 0.23, 0.45, ...]},
{"name": "blob2", "data": [0.1, 0.15, 0.12, ...]}
]
}
Recommended: Option B - Simple, standard, supports multiple blobs.
Playback System:
Timeline UI:
┌────────────────────────────────────────────┐
│ [▶] [⏸] [⏹] |░░░░░●░░░░░░░░░░░░░░| 0.523s │
│ [1x] [2x] [0.5x] │
└────────────────────────────────────────────┘
Implementation:
- File input element with drag-drop support
- CSV parser (Papa Parse library or vanilla JS)
- Time series data structure
- Animation controller (playhead, speed, loop)
- Interpolation between samples (linear or cubic)
- Per-frame amplitude update to blob(s)
Complexity: MEDIUM
- File upload: trivial
- CSV parsing: simple (vanilla JS adequate)
- Playback controls: standard pattern
- Blob-to-channel mapping: needs UI
- Performance: may need optimization for long recordings
Concept: During time series playback, compute and export the voltage at each 10/20 electrode location.
Output Format:
time,Fp1,Fp2,F3,F4,F7,F8,Fz,T3,T4,C3,C4,Cz,T5,T6,P3,P4,Pz,O1,O2,Oz
0.000,-0.23,0.45,0.12,-0.08,...
0.001,-0.21,0.42,0.14,-0.09,...
...Implementation:
- Pre-compute mode: calculate all frames before export
- Streaming mode: compute during playback, buffer results
- Export button triggers CSV download
Performance Consideration:
- 20 electrodes × 1000 samples × N blobs × M dipoles/blob
- For M=50 dipoles, N=1 blob, 1000 samples: 1M potential calculations
- Should complete in <1 second on modern hardware
Complexity: LOW
- Just data collection during playback
- Standard CSV generation
- Blob download mechanism
Problem: Current inBrain() uses 2D coronal mask. Moving to y-axis requires 3D.
Solutions:
- Quick: Ellipsoid approximation (math-only, no new images)
- Better: Volumetric mask from Allen Brain Atlas
- Best: Load actual brain mesh for surface constraint
Recommendation: Start with ellipsoid, upgrade later if needed.
Problem: If we add sagittal view, three views must stay synchronized.
Solution: Centralized state management:
const state = {
blobs: [...],
selectedBlobId: null,
viewMode: 'coronal', // or 'sagittal', 'both'
// ...
};
function updateViews() {
drawCoronal(state);
drawTopomap(state);
if (state.viewMode === 'both') drawSagittal(state);
}Problem: Computing potentials at high frame rates with many dipoles could lag.
Solutions:
- Precomputation: Calculate all frames upfront (blocking but predictable)
- Web Workers: Offload computation to background thread
- Adaptive sampling: Reduce dipole count in blobs during playback
Recommendation: Precomputation for recordings <10s, Web Workers for longer.
Problem: Atlas uses different coordinate systems (MNI, Allen CCF).
Solution: For this demo, use simplified models rather than true atlas coordinates. The unit sphere model is pedagogically cleaner.
Future Enhancement: Add coordinate transform option for advanced users.
Problem: Current 2.4MB single file is already unwieldy. Adding features will make it worse.
Decision: Move to multi-file architecture.
EEG-Dipole-Demo/
├── index.html # Main HTML structure
├── css/
│ └── styles.css # All styles (extracted from inline)
├── js/
│ ├── main.js # Entry point, initialization
│ ├── core/
│ │ ├── physics.js # Potential calculations
│ │ ├── electrodes.js # 10/20 electrode definitions
│ │ └── math.js # Vector math utilities
│ ├── models/
│ │ ├── dipole.js # Single dipole class
│ │ ├── blob.js # Blob (active region) class
│ │ └── timeseries.js # Time series data handling
│ ├── views/
│ │ ├── coronal.js # Coronal canvas rendering
│ │ ├── topomap.js # Topographic map rendering
│ │ └── sagittal.js # (Future) Sagittal view
│ ├── ui/
│ │ ├── controls.js # Slider/button bindings
│ │ ├── timeline.js # Playback controls
│ │ ├── file-upload.js # Time series file handling
│ │ └── dipole-list.js # Dipole/blob list management
│ └── export/
│ └── csv.js # CSV export functionality
├── assets/
│ ├── coronal-slice.png # Brain image (extracted from base64)
│ └── sagittal-slice.png # (Future) Sagittal brain image
└── README.md # Updated documentation
Note: For users who need single-file deployment, we can provide a build script that bundles everything back into one file.
Deliverables:
- Extract code from monolithic HTML into modular JS files
- Extract CSS into separate stylesheet
- Extract brain image from base64 to PNG file
- Set up simple build process (optional, for single-file output)
- Verify existing functionality works
Risk: Breaking existing functionality during refactor. Mitigation: Comprehensive testing at each step.
Deliverables:
- Blob data structure and physics
- Mode toggle (single dipole ↔ blob)
- Blob controls (radius, orientation dial, strength)
- Blob visualization in coronal view
- Update topomap rendering for blob
Deliverables:
- Y-position slider for blobs
- 3D ellipsoid brain constraint
- Topomap depth indicator
- (Optional) Basic sagittal view
Deliverables:
- File upload UI (drag-drop CSV)
- CSV parser
- Timeline/playback controls
- Blob amplitude modulation
- Channel-to-blob mapping UI
Deliverables:
- Voltage computation during playback
- CSV export of electrode time series
- Download button and file naming
Deliverables:
- UI/UX refinements
- Error handling and validation
- Updated README
- Example time series files
- Usage tutorial
Options:
- A) Gaussian:
density(r) = exp(-r²/2σ²) - B) Uniform sphere:
density(r) = 1 if r < R else 0 - C) Shell: dipoles on surface of sphere only
Recommendation: A (Gaussian) - most physically plausible.
Options:
- A) Include in initial release
- B) Defer to future version
- C) Add as optional toggle
Recommendation: B or C - Y-slider + topomap indicator sufficient for v2.0.
Options:
- A) CSV only (simple)
- B) CSV + JSON (flexible)
- C) CSV + EDF/BDF support (clinical compatibility)
Recommendation: A for v2.0, with extensibility hooks for future formats.
Options:
- A) No build (ES modules loaded directly)
- B) Simple bundler (esbuild/rollup)
- C) Full toolchain (webpack/vite)
Recommendation: A with optional B - ES modules work in modern browsers, bundler script for single-file output.
| Phase | Complexity | Files Affected |
|---|---|---|
| Phase 1 (Refactor) | HIGH | All (rewrite) |
| Phase 2 (Blob Mode) | MEDIUM | models/blob.js, views/, ui/controls.js |
| Phase 3 (Y-Axis) | MEDIUM | models/, views/coronal.js, ui/controls.js |
| Phase 4 (Time Series) | MEDIUM | models/timeseries.js, ui/timeline.js, ui/file-upload.js |
| Phase 5 (Export) | LOW | export/csv.js, ui/controls.js |
| Phase 6 (Polish) | LOW | All (minor) |
-
Blob shape: Should blobs always be spherical, or support ellipsoids for anisotropic activation?
-
Multiple blobs: Should users be able to create multiple blobs simultaneously? (Increases complexity but useful for bilateral sources)
-
Time series assignment: If multiple blobs exist, how should uploaded channels map to blobs? (Explicit mapping UI vs. automatic by order)
-
Sagittal image source: Should we extract a sagittal slice from the same atlas as coronal, or use Allen Brain Atlas API?
-
Offline mode: Should the multi-file architecture still support offline use? (Probably yes via bundling)
-
Coordinate display: Should we show MNI coordinates or keep the abstract unit sphere system?
- Review this plan - Confirm approach and priorities
- Resolve open questions - Especially blob shape and multiple blob support
- Begin Phase 1 - Architecture refactor
- Iterative implementation - Phase by phase with testing
Files Created:
EEG-Dipole-Demo/
├── index.html # New modular HTML (replaces monolith)
├── index-legacy.html # Original single-file version (preserved)
├── css/
│ └── styles.css # Extracted and enhanced styles
├── js/
│ ├── main.js # Application entry point
│ ├── core/
│ │ ├── math.js # Vector math, interpolation, Delaunay
│ │ ├── electrodes.js # 10-20 electrode definitions
│ │ └── physics.js # Potential calculations (dipole + blob)
│ ├── models/
│ │ ├── dipole.js # Single dipole class
│ │ ├── blob.js # Blob (active region) class
│ │ ├── timeseries.js # Time series parsing and interpolation
│ │ └── state.js # Centralized state management
│ ├── views/
│ │ ├── coronal.js # Coronal canvas rendering
│ │ └── topomap.js # Topographic map rendering
│ ├── ui/
│ │ ├── controls.js # Source management UI
│ │ ├── timeline.js # Playback controls
│ │ └── file-upload.js # CSV upload handling
│ └── export/
│ └── csv.js # CSV export functionality
└── assets/
└── coronal-slice.png # Extracted brain image (1536x1024)
Key Achievements:
- Extracted 2.4MB base64 image to separate PNG file
- Modularized JavaScript with ES6 modules
- Centralized state management with pub/sub pattern
- Blob model with Gaussian sampling implemented
- Time series playback system implemented
- Export system implemented
- 3D brain boundary check (ellipsoid) implemented
All features were implemented as part of the architecture refactor:
- Blob Mode - Active regions with radius, strength, orientation
- Y-Axis Positioning - Slider for anterior-posterior placement
- Time Series Playback - CSV upload, channel mapping, timeline controls
- Export System - Static frame and full series export
Plan Version: 1.1 Updated: 2026-01-24 Status: Phase 1 Complete, Testing Needed