# SPORE LEDLab LEDLab is a tool for streaming animations to LED matrices connected to SPORE nodes. Create visual effects with real-time parameter control and individual node management. ![ledlab](assets/ledlab.png) ![editor](assets/editor.png) ## Features - **Multi-Node Management**: Control multiple SPORE nodes individually - **Real-Time Preview**: See live canvas preview for each node - **Dynamic Presets**: Choose from 10+ built-in animation presets - **Visual Preset Editor**: Create custom animations with building blocks - **Live Parameter Control**: Adjust animation parameters in real-time - **Auto-Discovery**: Automatically discovers SPORE nodes on the network - **Modern UI**: Clean, responsive interface with dark/light theme support - **Import/Export**: Save and share custom presets as JSON files ## Architecture ### Server The Node.js server provides the backend for SPORE LEDLab: - **UDP Discovery**: Listens on port 4210 to automatically discover SPORE nodes - **WebSocket API**: Real-time bidirectional communication with the web UI - **Preset Management**: Manages animation presets with configurable parameters - **Multi-Node Streaming**: Streams different presets to individual nodes simultaneously - **Frame Generation**: Generates animation frames at configurable FPS (1-60) - **Node State Management**: Tracks configuration and streaming state per node ### Web UI The web interface provides an intuitive control panel: - **Node Grid View**: Visual grid showing all discovered nodes with live canvas previews - **Node Selection**: Click any node to open its control panel - **Preset Selection**: Choose from available animation presets - **Parameter Controls**: Real-time sliders and inputs for preset parameters - **Matrix Configuration**: Configurable matrix dimensions (default: 16x16) - **Settings Panel**: Test frames and matrix clearing utilities - **Theme Support**: Toggle between dark and light themes ### Communication Flow ``` Web UI (Browser) <--WebSocket--> Server <--UDP--> SPORE Nodes | Preset Engine | Frame Generation (60fps) ``` ## Build ### Prerequisites - Node.js (v14 or higher) - npm (v6 or higher) ### Installation 1. Clone the repository or navigate to the `spore-ledlab` directory: ```bash cd spore-ledlab ``` 2. Install dependencies: ```bash npm install ``` This will install: - `express`: Web server framework - `ws`: WebSocket library for real-time communication ### Project Structure ``` spore-ledlab/ ├── server/ # Backend server │ ├── index.js # Main server & WebSocket handling │ └── udp-discovery.js # UDP node discovery ├── presets/ # Animation preset implementations │ ├── preset-registry.js │ ├── base-preset.js │ ├── building-blocks.js # Reusable shape/animation components │ ├── custom-preset.js # Configurable preset engine │ ├── rainbow-preset.js │ ├── lava-lamp-preset.js │ ├── examples/ # Example custom preset JSON files │ └── ... ├── public/ # Frontend web UI │ ├── index.html │ ├── scripts/ # JavaScript modules │ │ ├── preset-editor.js # Visual preset editor │ │ └── ... │ └── styles/ # CSS stylesheets └── package.json # Project dependencies ``` ## Run ### Start the Server ```bash npm start ``` Or use the dev script (same as start): ```bash npm run dev ``` The server will: - Start the HTTP server on port 3000 - Initialize WebSocket server - Begin UDP discovery on port 4210 - Serve the web UI at http://localhost:3000 ### Access the Web UI Open your browser and navigate to: ``` http://localhost:3000 ``` ### Configure SPORE Nodes Ensure your SPORE nodes are: 1. Connected to the same network as the LEDLab server 2. Running firmware with PixelStreamController support 3. Listening on UDP port 4210 The nodes will automatically appear in the LEDLab grid view once discovered. ## Usage ### Basic Workflow 1. **Discover Nodes**: Wait for SPORE nodes to appear in the grid (auto-discovery runs every 5 seconds) 2. **Select a Node**: Click on any node in the grid to open the control panel 3. **Choose a Preset**: Select an animation preset from the dropdown menu 4. **Adjust Parameters**: Use sliders and inputs to modify animation parameters in real-time 5. **Start Streaming**: Click "Start Streaming" to begin sending frames to the selected node 6. **Stop Streaming**: Click "Stop Streaming" to halt the animation ### Available Presets - **Rainbow**: Classic rainbow cycle effect - **Lava Lamp**: Organic flowing blobs - **Aurora Curtains**: Northern lights simulation - **Bouncing Ball**: Physics-based bouncing ball - **Circuit Pulse**: Digital circuit patterns - **Meteor Rain**: Falling meteor trails - **Nebula Drift**: Cosmic cloud effects - **Ocean Glimmer**: Wave-like shimmer - **Spiral Bloom**: Rotating spiral patterns - **Voxel Fireflies**: 3D particle system - **Wormhole Tunnel**: Depth tunnel effect - **Fade Green-Blue**: Simple color fade ### Matrix Configuration Default matrix size is 16x16 pixels. To change: 1. Click the ⚙️ Settings button 2. Navigate to the Settings view 3. Adjust Width and Height values 4. Click "Apply Changes" ### Testing In the Settings view: - **Send Test Frame**: Sends a checkerboard pattern to verify connectivity - **Clear Matrix**: Turns off all LEDs on the selected node ## Configuration ### Server Configuration Edit `server/index.js` to modify: ```javascript const PORT = 3000; // HTTP/WebSocket port const UDP_PORT = 4210; // UDP discovery port const DEFAULT_FPS = 20; // Default frame rate const MATRIX_WIDTH = 16; // Default matrix width const MATRIX_HEIGHT = 16; // Default matrix height ``` ### Adding Custom Presets 1. Create a new preset file in `presets/`: ```javascript const BasePreset = require('./base-preset'); class MyCustomPreset extends BasePreset { constructor(width, height) { super(width, height); this.name = 'My Custom Preset'; this.description = 'Description of my preset'; } defineParameters() { return { speed: { type: 'range', min: 0.1, max: 5, step: 0.1, default: 1 }, color: { type: 'color', default: 'ff0000' } }; } update(frameCount) { // Animation logic here } } module.exports = MyCustomPreset; ``` 2. Register it in `presets/preset-registry.js`: ```javascript const MyCustomPreset = require('./my-custom-preset'); registerPreset('my-custom', MyCustomPreset); ``` ## Preset Editor The **🎨 Editor** view allows you to create custom animations by combining reusable building blocks without writing code. ### Building Blocks #### Shapes - **Circle**: Round shape with adjustable radius - **Rectangle**: Four-sided shape with width and height - **Triangle**: Three-sided shape - **Blob**: Soft circle with energy field falloff - **Point**: Single pixel - **Line**: Line between two points #### Patterns - **Trail**: Fade effect on previous frames - **Radial**: Gradient radiating from center - **Spiral**: Rotating spiral arms #### Colors - **Solid**: Single color - **Gradient**: Linear blend between two colors - **Palette**: Multi-stop gradient with custom colors - **Rainbow**: Color wheel effect #### Animations - **Move**: Linear movement from point A to B - **Rotate**: Rotation around center - **Pulse**: Scale oscillation (breathing effect) - **Oscillate X/Y**: Sine wave movement on X or Y axis - **Fade**: Fade in or out ### Creating a Custom Preset 1. Navigate to the **🎨 Editor** view 2. Enter a name and description 3. Add layers (shapes or patterns): - Select type and configure properties - Set position, size, and color - Add optional animation - Click **➕ Add Layer** 4. Edit layers with ✏️, reorder with ▲/▼, or delete with ✕ 5. Preview with **▶️ Preview** (requires a selected node from Stream view) 6. **💾 Save** to browser localStorage or **📤 Export JSON** to file ### Example Presets Import example JSON files from `presets/examples/` to learn: - **Pulsing Circle**: Rainbow circle with pulse animation - **Bouncing Squares**: Multiple colored squares oscillating - **Spiral Rainbow**: Rotating spiral with rainbow gradient - **Moving Triangle**: Triangle with linear movement Use **📥 Import JSON** to load examples and customize them. ### JSON Format Presets are stored as JSON: ```json { "name": "My Preset", "description": "Custom animation", "layers": [ { "type": "shape", "shape": "circle", "position": { "x": 8, "y": 8 }, "size": { "radius": 4 }, "color": { "type": "solid", "value": "ff0000" }, "animation": { "type": "pulse", "params": { "minScale": 0.5, "maxScale": 1.5, "frequency": 1.0 } } } ] } ``` See `presets/examples/README.md` for detailed documentation. ## Troubleshooting ### Nodes Not Appearing - Verify nodes are on the same network - Check firewall settings allow UDP port 4210 - Ensure nodes are running PixelStreamController firmware ### WebSocket Connection Issues - Check browser console for errors - Verify server is running on port 3000 - Try refreshing the browser ### Animation Not Streaming - Select a node first by clicking on it - Choose a preset from the dropdown - Verify the node shows "streaming" status ### Custom Preset Issues - **No preview**: Ensure a node is selected from Stream view first - **Nothing visible**: Check layer has valid position/size values - **Errors**: Open browser console (F12) for detailed error messages ## Technology Stack **Backend:** - Node.js - Express.js (HTTP server) - ws (WebSocket server) - UDP (Node discovery and frame streaming) **Frontend:** - Vanilla JavaScript (ES6+) - Component-based architecture - CSS3 with CSS variables for theming - Canvas API for visualization ## License MIT ## Credits Based on the SPORE framework and uses styling/components from spore-ui.