410 lines
12 KiB
Markdown
410 lines
12 KiB
Markdown
# 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.
|
||
|
||

|
||

|
||
|
||
|
||
## 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.
|