# 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: - **Gateway Integration**: Subscribes to spore-gateway WebSocket for real-time cluster updates (requires spore-gateway to be running) - **UDP Frame Streaming**: Sends animation frames to SPORE nodes via UDP on port 4210 - **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) Gateway WebSocket (Real-time cluster updates) ``` ## Build ### Prerequisites - Node.js (v14 or higher) - npm (v6 or higher) - spore-gateway must be running on port 3001 ### 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 │ ├── gateway-client.js # Gateway client for node discovery │ └── udp-discovery.js # UDP sender for frame streaming ├── 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 8080 (default) - Initialize WebSocket server - Connect to spore-gateway for node discovery - Initialize UDP sender for frame streaming - Serve the web UI at http://localhost:8080 ### Access the Web UI Open your browser and navigate to: ``` http://localhost:8080 ``` ### 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 4. Discovered by spore-gateway 5. Labeled with `app: pixelstream` (LEDLab only displays nodes with this label) The nodes will automatically appear in the LEDLab grid view once they are discovered by spore-gateway and have the `app: pixelstream` label. ### Node Labeling To display nodes in LEDLab, you must set the `app: pixelstream` label on your SPORE nodes. This can be done via the spore-gateway API or from the SPORE node itself. **From SPORE Node:** Nodes should advertise their labels via the UDP heartbeat. The PixelStreamController firmware automatically sets the `app: pixelstream` label. **Manual via Gateway:** You can also set labels manually using the spore-gateway API or spore-ui interface. ### Disabling Filtering To display all nodes without filtering, set the environment variable: ```bash FILTER_APP_LABEL= npm start ``` Or leave it empty to show all discovered nodes. ## 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` or use environment variables: ```javascript const PORT = 8080; // HTTP/WebSocket port const UDP_PORT = 4210; // UDP frame streaming port const GATEWAY_URL = 'http://localhost:3001'; // spore-gateway URL const FILTER_APP_LABEL = 'pixelstream'; // Filter nodes by app label const DEFAULT_FPS = 20; // Default frame rate const MATRIX_WIDTH = 16; // Default matrix width const MATRIX_HEIGHT = 16; // Default matrix height ``` Environment variables: - `PORT` - HTTP server port (default: 8080) - `UDP_PORT` - UDP port for frame streaming (default: 4210) - `GATEWAY_URL` - spore-gateway URL (default: http://localhost:3001) - `FILTER_APP_LABEL` - Filter nodes by app label (default: pixelstream, set to empty string to disable filtering) - `MATRIX_WIDTH` - Default matrix width (default: 16) - `MATRIX_HEIGHT` - Default matrix height (default: 16) ### 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 - Ensure spore-gateway is running on port 3001 - Verify nodes are on the same network - Check firewall settings allow UDP port 4210 - Ensure nodes are running PixelStreamController firmware - Verify spore-gateway has discovered the nodes - **IMPORTANT**: Nodes must have the `app: pixelstream` label set. LEDLab only displays nodes with this label. Check node labels in spore-gateway. ### WebSocket Connection Issues - Check browser console for errors - Verify server is running on port 8080 (default) - 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) - HTTP client (for querying spore-gateway) - UDP (Frame streaming only) **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.