539e43195f
Full-app UI/UX refresh committing to a tech-instrument / studio-console aesthetic inspired by hardware synths, Eurorack panels, and DAW layouts. Design tokens and fonts: - Embed Manrope (body), JetBrains Mono (labels/metrics), Big Shoulders Display (numeric readouts) as local .woff2 variable fonts with latin + latin-ext + cyrillic + cyrillic-ext subsets via unicode-range. - New Lumenworks token layer in base.css: --lux-bg-0..3, --lux-line(-bold), --lux-ink(-dim/-mute/-faint), --ch-signal/-cyan/-magenta/-amber/-coral/ -violet channel palette, --lux-signal-glow, --lux-shadow-rack, all theme-aware for dark + light. Existing tokens untouched for compat. Shell (header + sidebar): - Header rebuilt as a 3-column CSS-grid transport bar (brand | center | toolbar) with a glowing LED brand mark rendered via pseudo-elements on .header-title. Gradient channel-color rule under the bottom border. - New sidebar.css introduces a vertical channel-strip nav. Active tab gets a glowing left stripe + radial tint + LED pip. .sidebar-foot contains a live CPU/FPS meter plate. - Sidebar collapses to a 56 px icon rail at <=1100 px and hides via display:contents at <=600 px so mobile.css's fixed bottom tab-bar flows through unchanged. Cards and dashboard: - .card gets channel stripe (data-card-type + .ch-* utilities auto-map from data-target-id / data-stream-id / data-automation-id etc.), corner bracket, gradient background, subtle rack shadow. - .card-running replaces the old @property --border-angle conic-gradient rotating border with a lightweight signalFlow linear-gradient strip on the bottom edge (cheaper paint, no GPU layer compositing per card). - Skeleton loaders rewritten: left hairline + corner bracket + gradient shimmer instead of the old text-color opacity pulse. - .dashboard-target rows pick up the same channel-stripe + signalFlow treatment. Section headers use mono micro-caps with a channel-green underline accent consistent across the app. - .perf-chart-card: channel stripe replaces old border-top; per-metric accents moved to the channel palette (CPU=coral, RAM=violet, GPU=green, temp=amber). Metric values use tabular-nums + a soft glow. Live bindings (no new endpoints): - _updateSidebarMeter: binds the sidebar Load + FPS bars to the existing /system/performance poll. - _updateTransportStatus: toggles the transport chip between "Ready" and "Armed - N live" whenever the dashboard's running-target set is recomputed. Tree-nav + sub-tabs: - tree-nav.css trigger pill gets a channel-stripe left edge that glows when open; panel has a gradient channel-accent rule across the top; group headers use silkscreened micro-caps; active leaf has a pulsing LED pip + channel tint. - .stream-tab-btn / .subtab-section-header adopt the same mono-caps + channel-underline language for consistency. - Graph editor toolbar gets gradient + hairline + rack shadow + backdrop blur. Canvas and nodes untouched. Modals (40+ modals share modal.css): - Radial-dim + 6 px blur backdrop. Content gets a gradient background, hairline border, deep rack shadow, top channel-accent rule driven by --modal-ch, bottom-right corner bracket (hidden on mobile fullscreen). - Per-modal-ID channel lanes: target editors = green, source/input editors = cyan, audio = magenta, automation/scene/game = violet, settings/auth = amber, confirm = coral. - Modal headers: vertical channel stripe left of the title + hairline divider. Modal footers: hairline top border + subtle gradient wash. Forms: - Inputs use hairline borders; number inputs switch to mono + tabular-nums for column alignment. Focus state: channel-green ring + soft glow. - Buttons use mono-uppercase type with signal-glow on primary and coral- glow on danger. Mobile (<=600 px): - Fixed bottom .tab-bar gets the full Lumenworks treatment: gradient fill, top channel-accent rule matching the transport bar, backdrop blur. Active tab has an LED pip above the icon + channel tint + icon recolor. - Fullscreen modals: corner bracket hidden, header stripe slimmed. Microcopy (en / ru / zh): - "Targets" -> "Channels" / "Каналы" / "通道" - "Sources" -> "Inputs" / "Входы" / "输入" - Internal tab keys (dashboard/automations/targets/streams/integrations/ graph) kept stable so no JS or localStorage migration is needed. - Added: sidebar.workspaces, sidebar.load, sidebar.fps, transport.status.ready, transport.status.armed. Compatibility: - All existing class hooks preserved (.tab-bar, .tab-btn, .card, .card-running, .tree-dd-*, .cs-*, .perf-chart-card, .modal-content, .dashboard-target, etc.). No JS or API changes required for the new look to take effect. - Tour selectors survive (header .header-title, #tab-btn-*, onclick markers on theme/settings/search, #cp-wrap-accent, etc.). - Mobile <=600 px bottom tab-bar keeps working via display:contents fall-through in the new sidebar. Build: tsc --noEmit clean; npm run build clean. CSS bundle grew from ~177 KB to ~201 KB for the full new visual system. Fonts loaded lazily per unicode-range subset (~98 KB critical path for English). Phased plan + deferred follow-ups (dashboard hero strip, legacy-token cleanup) recorded at the top of TODO.md. Reference mockup: server/docs/ui-redesign-mockup.html.
LedGrab - Server
High-performance FastAPI server that captures screen content and controls WLED devices for ambient lighting.
Overview
The server component provides:
- 🎯 Real-time Screen Capture - Multi-monitor support with configurable FPS
- 🎨 Advanced Processing - Border pixel extraction with color correction
- 🔧 Flexible Calibration - Map screen edges to any LED layout
- 🌐 REST API - Complete control via 25+ REST endpoints
- 💾 Persistent Storage - JSON-based device and configuration management
- 📊 Metrics & Monitoring - Real-time FPS, status, and performance data
Quick Start
Option 1: Docker (Recommended)
# Start server
docker-compose up -d
# View logs
docker-compose logs -f
# Stop server
docker-compose down
Server runs on: http://localhost:8080
Option 2: Python
# Create virtual environment
python -m venv venv
# Activate
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
# Install dependencies
pip install .
# Set PYTHONPATH
export PYTHONPATH=$(pwd)/src # Linux/Mac
set PYTHONPATH=%CD%\src # Windows
# Run server
uvicorn ledgrab.main:app --host 0.0.0.0 --port 8080
Installation
Requirements
- Python 3.11+ (for Python installation)
- Docker & Docker Compose (for Docker installation)
- WLED device on your network
See ../INSTALLATION.md for comprehensive installation guide.
Configuration
Configuration File
Edit config/default_config.yaml:
server:
host: "0.0.0.0"
port: 8080
log_level: "INFO"
processing:
default_fps: 30 # Target frames per second
max_fps: 60 # Maximum allowed FPS
border_width: 10 # Pixels to sample from edge
wled:
timeout: 5 # Connection timeout (seconds)
retry_attempts: 3 # Number of retries
storage:
devices_file: "data/devices.json"
logging:
format: "json"
file: "logs/ledgrab.log"
Environment Variables
# Server configuration
export LEDGRAB_SERVER__HOST="0.0.0.0"
export LEDGRAB_SERVER__PORT=8080
export LEDGRAB_SERVER__LOG_LEVEL="INFO"
# Processing configuration
export LEDGRAB_PROCESSING__DEFAULT_FPS=30
export LEDGRAB_PROCESSING__BORDER_WIDTH=10
# WLED configuration
export WLED_WLED__TIMEOUT=5
Usage
WLED Device Setup
Important: Configure your WLED device using the official WLED web interface before connecting it to this controller:
- Access WLED Interface: Open
http://[wled-ip]in your browser - Configure Device Settings:
- Set LED count and type
- Configure brightness, color order, and power limits
- Set up segments if needed
- Configure effects and presets
This controller only sends pixel color data - it does not manage WLED settings like brightness, effects, or segments. All WLED device configuration should be done through the official WLED interface.
API Documentation
- Web UI: http://localhost:8080 (recommended for device management)
- Swagger UI: http://localhost:8080/docs
- ReDoc: http://localhost:8080/redoc
Quick Example
# 1. Add device
curl -X POST http://localhost:8080/api/v1/devices \
-H "Content-Type: application/json" \
-d '{"name":"Living Room","url":"http://192.168.1.100","led_count":150}'
# 2. Start processing
curl -X POST http://localhost:8080/api/v1/devices/{device_id}/start
# 3. Check status
curl http://localhost:8080/api/v1/devices/{device_id}/state
Testing
# Run all tests
pytest
# Run with coverage
pytest --cov=ledgrab --cov-report=html
# Run specific test
pytest tests/test_screen_capture.py -v
Development
Project Structure
src/ledgrab/
├── main.py # FastAPI application
├── config.py # Configuration
├── api/ # API routes
├── core/ # Core functionality
│ ├── screen_capture.py
│ ├── wled_client.py
│ ├── calibration.py
│ └── processor_manager.py
├── storage/ # Data persistence
└── utils/ # Utilities
Code Quality
# Format code
black src/ tests/
# Lint code
ruff check src/ tests/
License
MIT - see ../LICENSE