voyvodka/LumaSync
Mirror your screen to WS2812B LED strips and Philips Hue entertainment areas in real time. Local-only, brand-agnostic, MIT-licensed.
README Snapshot
LumaSync
Website: lumasync.app
LumaSync is a native desktop app that mirrors your screen to WS2812B LED strips and Philips Hue entertainment areas in real time. A single calibrated room map drives per-edge LED layouts and Hue channel placement; all processing stays on your machine — no cloud, no telemetry.
It combines a React + TypeScript frontend with a Rust/Tauri runtime to keep the UI responsive while handling native desktop behavior.
Screenshots
Compact tray-sized mode (320×480) and full workspace mode (900×620) — amber Rev 07 design language, same state shared across both layouts.
Features
- Ambilight: real-time screen capture drives LED strips and/or Hue lights simultaneously, with per-LED edge sampling anchored to the room map
- Philips Hue: DTLS 1.2 PSK entertainment streaming, channel position editor, zone auto-derivation from room map
- Room map editor: drag-and-drop canvas with furniture, TV anchor, and USB strip objects; Hue channels overlaid on normalized coordinates
- Multi-monitor capture: pick which display feeds the lights; hot-plug and resolution changes are handled without restart
- Color correction: per-channel R/G/B gamma, Kelvin white-balance, and saturation trim — tuned once per strip, persisted per layout
- Solid color: RGB + brightness push to USB and Hue with debounced 50 ms update
- LED calibration: edge counts, gap, corner ownership, start anchor, direction — persisted per layout
- Firmware profiles: LumaSync-native framing out of the box; Adalight profile for off-the-shelf microcontrollers
- Target-aware pipeline: choose USB, Hue, or both per mode; hot-plug detection with suggestion banner
- Compact, stays out of your way: lives in the tray; opens as a 320×480 panel for quick scene changes or a 900×620 full view for calibration, on demand
- Runtime HUD: StatusBar pill surfaces live FPS and end-to-end latency with green/amber/red thresholds
- Native notifications: OS-level toast for connection, stream, and update events; permission banner asks once and never re-prompts
- Resilient shell: global error boundary catches render faults and offers a localized restart/logs card instead of a white-screened tray window
- Auto-updater: GitHub Releases with minisign signature verification
Tech Stack
- Frontend: Vite, React 19, TypeScript (strict), Tailwind CSS
- Desktop runtime: Tauri v2, Rust
- Testing: Vitest + Testing Library, Cargo test
- Package manager: pnpm
Supported Hardware
USB Controllers
Microcontrollers using the following USB-to-serial chips are supported:
| Chip | USB ID |
|---|---|
| CH340 | 1A86:7523 |
| FTDI FT232 | 0403:6001 |
| CP2102 (Silicon Labs) | 10C4:EA60 |
| Arduino Uno R3 | 2341:0043 |
| Arduino Uno (original) | 2341:0001 |
Baud rate: 115200. LumaSync ships with two firmware profiles:
- LumaSync-native (default):
0xAA 0x55header, LE LED count, gamma-corrected RGB triplets, XOR checksum. A matching firmware sketch ships with the companion hardware repo. - Adalight: the widely-used
"Ada"header format, compatible with off-the-shelf WS2812B controllers and existing Adalight firmware builds.
Profile is selected per device in the Devices section.
Philips Hue
- Hue Bridge (gen 2+) on the local network
- At least one configured Entertainment Area in the Hue app
- macOS only:
macos-private-apiis required for fullscreen calibration overlays — the app requests this automatically
Platform Support
| Platform | Status | Notes |
|---|---|---|
| macOS | Full support | Primary development target. macos-private-api enabled for fullscreen overlays. |
| Windows | Full support | USB and Hue features work. Windows Graphics Capture powers the capture pipeline. |
| Linux | Planned (v1.5) | Not shipped in v1.4. Targeted for the next release; requires GTK 3, WebKitGTK 4.1, and libudev. |
Getting Started
Prerequisites
- Node.js 20+
- pnpm 10+
- Rust toolchain (stable)
- Tauri platform prerequisites for your OS
Install
pnpm install
Development
pnpm tauri dev
Build
pnpm tauri build
Common Scripts
pnpm dev: run web-only Vite dev serverpnpm tauri dev: run desktop app in development modepnpm typecheck: run TypeScript type checks (no emit)pnpm lint: alias for typecheckpnpm vitest run: run frontend unit tests oncepnpm vitest: run frontend tests in watch modepnpm verify:shell-contracts: validate Rust command handlers match frontend contract definitionspnpm check:rust: run Rustcargo checkpnpm check:all: run JS + Rust + shell contract checks together
Project Structure
src/: React application and feature modulessrc/shared/contracts/: cross-layer contract definitionssrc-tauri/src/commands/: Rust Tauri command handlersdocs/: debugging and manual operational docs
Documentation
- Debugging guide:
docs/debugging.md - Contributing guide:
CONTRIBUTING.md - Code of Conduct:
CODE_OF_CONDUCT.md - Security policy:
SECURITY.md - Support guide:
SUPPORT.md - Changelog:
CHANGELOG.md
Contributing
Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request.
Security
If you discover a security issue, please follow the process in SECURITY.md.
License
MIT © 2026 voyvodka
Changelog
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog: https://keepachangelog.com/en/1.1.0/
[Unreleased]
[1.4.0] — 2026-04-24
Added
- USB per-LED sampling: each LED now samples its own edge region of the screen (anchored to the room map's edge counts, start anchor, direction, and bottom gap), replacing the single-zone hardcode shipped in v1.3; baud budget adapts dynamically so 60 LEDs run at ~60 FPS and 200 LEDs at ~19 FPS within the 115200 baud limit
- LedSink trait: a common
start / send_frame / stopabstraction over the serial output bridge, laying the foundation for WLED (v1.5) and OpenRGB (v2.0) sinks - Multi-monitor capture: stable display IDs on macOS (SCDisplay) and Windows (device_name) with automatic primary-display fallback on unplug; selected display persists across restarts
- Per-channel color correction: independent R/G/B gamma tables, Kelvin white-balance multipliers, and BT.601-luminance saturation trim — tuned once per strip, applied on the hot path before smoothing so USB, Hue, and the edge-signal preview stay visually consistent
- Adalight firmware profile: encoder dispatch selects between LumaSync-native framing (default) and the widely-used Adalight
"Ada"header format; profile is persisted per device - Serial handshake round-trip: PING/PONG opcode protocol with
SerialHealthReportand codedSerialHealthCodestatus; firmware implementation ships in the companion hardware repo's v1.5 update - Platform notifications:
tauri-plugin-notification+tauri-plugin-processwired end-to-end; permission banner asks once, OS-level toasts for connection, stream, and update events;open_log_dircommand exposes the app log directory - FPS/latency HUD: StatusBar fourth pill shows live frame rate and end-to-end latency with green/amber/red thresholds (45/25 FPS); always visible while Ambilight is active
- Global ErrorBoundary: catches render faults and surfaces a localized fallback card with Show logs, Restart, and Copy error actions instead of a blank tray window
- Keyboard shortcuts:
Alt+1/2/3(Ctrl on Windows/Linux) to switch modes,Alt+,/Cmd+,to open Settings; TR-layout-safe key resolution with input-focus guard - Hue richer pairing errors: CLIP
error.typeis now split intoLINK_BUTTON_NOT_PRESSED,DEVICETYPE_INVALID,BRIDGE_BUSY, andRATE_LIMITED— each surfaces a distinct localized message - Hue room archetype enrichment: entertainment area list fetches CLIP v2 archetype data in parallel (
tokio::join!) and surfaces it in the area-select UI - Hue intensity presets: Subtle (EWMA 0.15) / Moderate (0.35) / Intense (0.60) coefficient shortcuts for fast ambience tuning
Changed
- CI hardening: 3-OS matrix (ubuntu-22.04, macos-latest, windows-latest) with
cargo fmt --check,cargo clippy -D warnings,cargo check --all-targets --all-features,cargo test --no-run, andcargo auditon Linux; CodeQL JavaScript/TypeScript scanning on push, PR, and weekly schedule;dependency-review-actionwith MIT/Apache/BSD/ISC allow-list on PRs - Rust toolchain pinned to stable via
rust-toolchain.tomlwithrustfmtandclippycomponents - Node.js bumped from 20 to 22 across CI and release workflows
- Log rotation set to 5 MB (KeepOne in release builds, KeepAll in debug)
- Hue 403 re-pair contract tightened: only a 403 with CLIP
type == 1triggers re-pair; other 403 responses are treated as transient and do not interrupt the session - Lighting responsiveness unified: the continuous smoothing slider and the Hue-only intensity preset merged into a single three-step control (Subtle / Moderate / Intense) that drives both USB and Hue EWMA paths at once; legacy persisted state (
smoothingAlpha,hueIntensityPreset) still reads through a fallback chain so no migration is required - Hue pipeline now applies the full color-correction chain (gamma + Kelvin + saturation), matching the USB encoder order byte-for-byte so strip and bulbs stay visually consistent
- Rust deps: reqwest rustls chain updated (aws-lc-sys 0.37 → 0.40, rustls-webpki 0.103.10 → 0.103.13, rustls 0.23.37 → 0.23.39)
- Frontend deps:
@tauri-apps/plugin-notificationand@tauri-apps/plugin-processadded; minor/patch bumps across the React/Vite/Vitest ecosystem - GitHub Actions:
actions/checkoutandactions/setup-nodepinned;pnpm/action-setupheld at v4 with pnpm 10 explicit pin
Fixed
- Silent
try/catchpurge: 7 swallowed errors inApp.tsxandSystemSectionnow route through the structured logger with contextual prefixes - Preexisting Rust test bitrot:
hue_onboarding_tddfixtures andambilight_captureimport blocks had drifted from the current module layout; fixed socargo testcompiles cleanly in CI - 14 clippy pedantic lint warnings resolved as a baseline cleanup pass
- Ambilight settings persistence: pending
lightingModewrites are now flushed onpagehideandvisibilitychange, so saturation and black-border toggles survive Cmd+R / tray close / reload cycles - Color correction + firmware profile payload: the mode normalizer now preserves these fields end-to-end instead of stripping them before
set_lighting_modeinvoke, so slider commits actually reach the worker
Removed
- 5 orphan settings components absorbed by M6:
LanguageSection,StartupTraySection,AboutLogsSection,CalibrationSection,ConfigurePage— along with 2 orphan test files SidebarFpsWidgetretired; the StatusBar FPS/latency pill supersedes it
Security
- CodeQL JavaScript/TypeScript scanning added to CI (push, PR, and weekly Monday schedule)
dependency-review-actiongates PRs on license allow-list (MIT/Apache/BSD/ISC) and blocks high-severity CVEscargo auditruns on Linux CI step; 8 transitive RUSTSEC advisories resolved by bumping the reqwest/rustls chain
[1.3.1] — 2026-04-23
Fixed
- CHANGELOG: de-duplicated
[1.1.0]heading; the March 2026 foundation entry was never tagged and is now demoted to a historical sub-section so the release workflow's changelog extractor no longer silently drops it
[1.3.0] — 2026-04-22
Added
- Compact UI mode with dual-sized window (compact 320×480 / full 900×620), custom overlay title bar, and accent theme system driven by a new
UIModecontract - CompactLayout view with quick-access mode presets, scene tiles, and integrated mode toggle for a tray-style experience
- LightsSection redesign (M6): mode selector, scene presets, ambilight profile sliders, and live device/status visualisation
- StatusBar with mode, device, and stream indicators alongside the new shell chrome
- UpdateModal rewrite covering four states (available / downloading / installing / error) with i18n-backed labels
- Hue Bridges section redesign (B-08): card state classes, pill variants, traffic bar label row, four-step pairing tracker with failure state, area-select label, conflict/repair/offline banners, and action buttons aligned to all 17 defined states
- Edge signal preview panel: the ambilight worker now emits a throttled
ambilight://edge-signalTauri event (~10 Hz) with top/bottom/left/right RGB samples, rendered as live linear gradients next to a primary-display tile - Runtime telemetry meta pill showing live
Δframe latency andΣFPS sourced fromget_runtime_telemetrywhile Ambilight is active; polling pauses when the tab is hidden - Ambilight saturation control: luminance-preserving Rec.601 factor (range 0.5–2.0, identity 1.0) stored as an
AtomicU32in the worker's live settings, applied on the hot path before smoothing so USB LEDs, Hue channels, and the edge-signal preview stay visually consistent; exposed in Lights as a 50–200% dial - Unified scene preset catalog (
src/features/mode/model/scenePresets.ts) with abrightnessfield, shared by Compact and Lights; active preset is derived from the current SOLID payload so selection survives view switches and app restarts - Dock "+" add-zone affordance rendered as disabled with a tooltip, surfacing multi-zone support as a known-future feature
EdgeSignalPayload/EDGE_SIGNAL_EVENTexported from the mode contract module for typed event wiring- Jules agent documentation: hard constraints, security rules, and architecture data-flow map to guide automated security/performance scans
LedRoomCanvas: read-only SVG illustration of the monitor + desk scene with LED dots distributed per edge, a #1 start marker, and a direction arrow — driven purely fromLedCalibrationConfigderiveDefaultCounts(display): frontend heuristic that assigns sensible per-edge LED counts from monitor resolution and aspect ratio so auto-selected displays fill the canvas on first run without a template picker
Changed
- Compact/full UI mode transition now uses a single content slot with sequential fade + resize + fade and easing matched to the window animation, eliminating the progressive-clipping artefact where the incoming layout overflowed the still-animating window
- Removed the orange edge-sweep animation from window mode transitions; the simpler fade + resize flow remains
- LED Setup redesigned to a single-screen stage + 268px dock layout: the three-step display/template/editor wizard, template picker, and draggable editor canvas are gone; counts are adjusted directly in the dock and the test pattern runs in place with a preview/output HUD overlay on the canvas
- LED Setup dock exposes the full strip topology: partial-edge setups (e.g. LEDs only on the top) are allowed (0-count edges), monitor stand gap (
bottomMissing) has a dedicated stepper, LED direction toggles between CW / CCW, and start anchor is driven by edge tabs + Start/End/Gap-R/Gap-L endpoint buttons so all 10LedStartAnchorpositions are reachable.LedRoomCanvasnow renders the stand gap and places the#1marker on the gap-adjacent LED forbottom-gap-*anchors - Calibration validation: 0-count edges are now accepted as long as
sum > 0(NO_LEDS_CONFIGURED); stand gap wider than the bottom edge now fails withBOTTOM_MISSING_EXCEEDS_BOTTOM;normalizeLedCalibrationConfigauto-clampsbottomMissingto bottom count and auto-healsstartAnchorwhen its edge is zeroed out - Hue stream health polling migrated from
setIntervalto recursivesetTimeout, preventing overlapping probes when a health check takes longer than its interval and stopping polling as soon as the stream is detected dead - Internationalisation sweep: DeviceSection cell labels (Area, Protocol, Ch, Rate, Status, Error, Retries, Next, Fault, Config, Credential, Invalid), traffic bar Stream label, DTLS streaming subtitle, display card ID/Scale labels, previously-missing wizard step keys, UpdateModal note kind tags moved to
updater.noteKind.*, RenameDialog Cancel/OK buttons in RoomMapEditor, and StatusBar keyboard hint labels (mode / settings) — EN + TR locales kept in sync - Test layout: all colocated
*.test.ts(x)files relocated into__tests__/subdirectories and CLAUDE.md updated to document the convention - Rust dependencies bumped:
tokio1.50.0 → 1.52.1,openssl0.10.76 → 0.10.78 - Frontend dependencies bumped (minor/patch):
i18next26.0.4 → 26.0.6,react-i18next17.0.2 → 17.0.4,tailwindcss+@tailwindcss/vite4.2.2 → 4.2.4,typescript6.0.2 → 6.0.3,vite8.0.8 → 8.0.9,vitest4.1.4 → 4.1.5,happy-dom+@happy-dom/global-registrator20.8.9 → 20.9.0 - GitHub Actions bumped:
actions/checkout4 → 6,actions/setup-node4 → 6,pnpm/action-setup4 → 6 - Dependabot configuration added for Cargo, npm, and GitHub Actions ecosystems so future dependency updates land as reviewable PRs
- Linux CI hardened with
DEBIAN_FRONTEND=noninteractiveto prevent apt-get prompts from hanging the runner .gitignorenow ignores.planning/and.jules/recursively so local planning artefacts never leak into status- Removed legacy
.julestracking files from the repository
Releases
- LumaSync v1.4.0
### Added - USB per-LED sampling: each LED now samples its own edge region of the screen (anchored to the room map's edge counts, start anchor, direction, and bottom gap), replacing the single-zone hardcode shipped in v1.3; baud budget adapts dynamically so 60 LEDs run at ~60 FPS and 200 LEDs at ~19 FPS within the 115200 baud limit - LedSink trait: a common `start / send_frame / stop` abstraction over the serial output bridge, laying the foundation for WLED (v1.5) and OpenRGB (v2.0) sinks - Multi-monitor capture: stable display IDs on macOS (SCDisplay) and Windows (device_name) with automatic primary-display fallback on unplug; selected display persists across restarts - Per-channel color correction: independent R/G/B gamma tables, Kelvin white-balance multipliers, and BT.601-luminance saturation trim — tuned once per strip, applied on the hot path before smoothing so USB, Hue, and the edge-signal preview stay visually consistent - Adalight firmware profile: encoder dispatch selects between LumaSync-native framing (default) and the widely-used Adalight `"Ada"` header format; profile is persisted per device - Serial handshake round-trip: PING/PONG opcode protocol with `SerialHealthReport` and coded `SerialHealthCode` status; firmware implementation ships in the companion hardware repo's v1.5 update - Platform notifications: `tauri-plugin-notification` + `tauri-plugin-process` wired end-to-end; permission banner asks once, OS-level toasts for connection, stream, and update events; `open_log_dir` command exposes the app log directory - FPS/latency HUD: StatusBar fourth pill shows live frame rate and end-to-end latency with green/amber/red thresholds (45/25 FPS); always visible while Ambilight is active - Global ErrorBoundary: catches render faults and surfaces a localized fallback card with Show logs, Restart, and Copy error actions instead of a blank tray window - Keyboard shortcuts: `Alt+1/2/3` (Ctrl on Windows/Linux) to switch modes, `Alt+,` / `Cmd+,` to open Settings; TR-layout-safe key resolution with input-focus guard - Hue richer pairing errors: CLIP `error.type` is now split into `LINK_BUTTON_NOT_PRESSED`, `DEVICETYPE_INVALID`, `BRIDGE_BUSY`, and `RATE_LIMITED` — each surfaces a distinct localized message - Hue room archetype enrichment: entertainment area list fetches CLIP v2 archetype data in parallel (`tokio::join!`) and surfaces it in the area-select UI - Hue intensity presets: Subtle (EWMA 0.15) / Moderate (0.35) / Intense (0.60) coefficient shortcuts for fast ambience tuning ### Changed - CI hardening: 3-OS matrix (ubuntu-22.04, macos-latest, windows-latest) with `cargo fmt --check`, `cargo clippy -D warnings`, `cargo check --all-targets --all-features`, `cargo test --no-run`, and `cargo audit` on Linux; CodeQL JavaScript/TypeScript scanning on push, PR, and weekly schedule; `dependency-review-action` with MIT/Apache/BSD/ISC allow-list on PRs - Rust toolchain pinned to stable via `rust-toolchain.toml` with `rustfmt` and `clippy` components - Node.js bumped from 20 to 22 across CI and release workflows - Log rotation set to 5 MB (KeepOne in release builds, KeepAll in debug) - Hue 403 re-pair contract tightened: only a 403 with CLIP `type == 1` triggers re-pair; other 403 responses are treated as transient and do not interrupt the session - Lighting responsiveness unified: the continuous smoothing slider and the Hue-only intensity preset merged into a single three-step control (Subtle / Moderate / Intense) that drives both USB and Hue EWMA paths at once; legacy persisted state (`smoothingAlpha`, `hueIntensityPreset`) still reads through a fallback chain so no migration is required - Hue pipeline now applies the full color-correction chain (gamma + Kelvin + saturation), matching the USB encoder order byte-for-byte so strip and bulbs stay visually consistent - Rust deps: reqwest rustls chain updated (aws-lc-sys 0.37 → 0.40, rustls-webpki 0.103.10 → 0.103.13, rustls 0.23.37 → 0.23.39) - Frontend deps: `@tauri-apps/plugin-notification` and `@tauri-apps/plugin-process` added; minor/patch bumps across the React/Vite/Vitest ecosystem - GitHub Actions: `actions/checkout` and `actions/setup-node` pinned; `pnpm/action-setup` held at v4 with pnpm 10 explicit pin ### Fixed - Silent `try/catch` purge: 7 swallowed errors in `App.tsx` and `SystemSection` now route through the structured logger with contextual prefixes - Preexisting Rust test bitrot: `hue_onboarding_tdd` fixtures and `ambilight_capture` import blocks had drifted from the current module layout; fixed so `cargo test` compiles cleanly in CI - 14 clippy pedantic lint warnings resolved as a baseline cleanup pass - Ambilight settings persistence: pending `lightingMode` writes are now flushed on `pagehide` and `visibilitychange`, so saturation and black-border toggles survive Cmd+R / tray close / reload cycles - Color correction + firmware profile payload: the mode normalizer now preserves these fields end-to-end instead of stripping them before `set_lighting_mode` invoke, so slider commits actually reach the worker ### Removed - 5 orphan settings components absorbed by M6: `LanguageSection`, `StartupTraySection`, `AboutLogsSection`, `CalibrationSection`, `ConfigurePage` — along with 2 orphan test files - `SidebarFpsWidget` retired; the StatusBar FPS/latency pill supersedes it ### Security - CodeQL JavaScript/TypeScript scanning added to CI (push, PR, and weekly Monday schedule) - `dependency-review-action` gates PRs on license allow-list (MIT/Apache/BSD/ISC) and blocks high-severity CVEs - `cargo audit` runs on Linux CI step; 8 transitive RUSTSEC advisories resolved by bumping the reqwest/rustls chain
Open on GitHub - LumaSync v1.3.1
### Fixed - CHANGELOG: de-duplicated `[1.1.0]` heading; the March 2026 foundation entry was never tagged and is now demoted to a historical sub-section so the release workflow's changelog extractor no longer silently drops it
Open on GitHub - LumaSync v1.3.0
### Added - Compact UI mode with dual-sized window (compact 320×480 / full 900×620), custom overlay title bar, and accent theme system driven by a new `UIMode` contract - CompactLayout view with quick-access mode presets, scene tiles, and integrated mode toggle for a tray-style experience - LightsSection redesign (M6): mode selector, scene presets, ambilight profile sliders, and live device/status visualisation - StatusBar with mode, device, and stream indicators alongside the new shell chrome - UpdateModal rewrite covering four states (available / downloading / installing / error) with i18n-backed labels - Hue Bridges section redesign (B-08): card state classes, pill variants, traffic bar label row, four-step pairing tracker with failure state, area-select label, conflict/repair/offline banners, and action buttons aligned to all 17 defined states - Edge signal preview panel: the ambilight worker now emits a throttled `ambilight://edge-signal` Tauri event (~10 Hz) with top/bottom/left/right RGB samples, rendered as live linear gradients next to a primary-display tile - Runtime telemetry meta pill showing live `Δ` frame latency and `Σ` FPS sourced from `get_runtime_telemetry` while Ambilight is active; polling pauses when the tab is hidden - Ambilight saturation control: luminance-preserving Rec.601 factor (range 0.5–2.0, identity 1.0) stored as an `AtomicU32` in the worker's live settings, applied on the hot path before smoothing so USB LEDs, Hue channels, and the edge-signal preview stay visually consistent; exposed in Lights as a 50–200% dial - Unified scene preset catalog (`src/features/mode/model/scenePresets.ts`) with a `brightness` field, shared by Compact and Lights; active preset is derived from the current SOLID payload so selection survives view switches and app restarts - Dock "+" add-zone affordance rendered as disabled with a tooltip, surfacing multi-zone support as a known-future feature - `EdgeSignalPayload` / `EDGE_SIGNAL_EVENT` exported from the mode contract module for typed event wiring - Jules agent documentation: hard constraints, security rules, and architecture data-flow map to guide automated security/performance scans - `LedRoomCanvas`: read-only SVG illustration of the monitor + desk scene with LED dots distributed per edge, a #1 start marker, and a direction arrow — driven purely from `LedCalibrationConfig` - `deriveDefaultCounts(display)`: frontend heuristic that assigns sensible per-edge LED counts from monitor resolution and aspect ratio so auto-selected displays fill the canvas on first run without a template picker ### Changed - Compact/full UI mode transition now uses a single content slot with sequential fade + resize + fade and easing matched to the window animation, eliminating the progressive-clipping artefact where the incoming layout overflowed the still-animating window - Removed the orange edge-sweep animation from window mode transitions; the simpler fade + resize flow remains - LED Setup redesigned to a single-screen stage + 268px dock layout: the three-step display/template/editor wizard, template picker, and draggable editor canvas are gone; counts are adjusted directly in the dock and the test pattern runs in place with a preview/output HUD overlay on the canvas - LED Setup dock exposes the full strip topology: partial-edge setups (e.g. LEDs only on the top) are allowed (0-count edges), monitor stand gap (`bottomMissing`) has a dedicated stepper, LED direction toggles between CW / CCW, and start anchor is driven by edge tabs + Start/End/Gap-R/Gap-L endpoint buttons so all 10 `LedStartAnchor` positions are reachable. `LedRoomCanvas` now renders the stand gap and places the `#1` marker on the gap-adjacent LED for `bottom-gap-*` anchors - Calibration validation: 0-count edges are now accepted as long as `sum > 0` (`NO_LEDS_CONFIGURED`); stand gap wider than the bottom edge now fails with `BOTTOM_MISSING_EXCEEDS_BOTTOM`; `normalizeLedCalibrationConfig` auto-clamps `bottomMissing` to bottom count and auto-heals `startAnchor` when its edge is zeroed out - Hue stream health polling migrated from `setInterval` to recursive `setTimeout`, preventing overlapping probes when a health check takes longer than its interval and stopping polling as soon as the stream is detected dead - Internationalisation sweep: DeviceSection cell labels (Area, Protocol, Ch, Rate, Status, Error, Retries, Next, Fault, Config, Credential, Invalid), traffic bar Stream label, DTLS streaming subtitle, display card ID/Scale labels, previously-missing wizard step keys, UpdateModal note kind tags moved to `updater.noteKind.*`, RenameDialog Cancel/OK buttons in RoomMapEditor, and StatusBar keyboard hint labels (mode / settings) — EN + TR locales kept in sync - Test layout: all colocated `*.test.ts(x)` files relocated into `__tests__/` subdirectories and CLAUDE.md updated to document the convention - Rust dependencies bumped: `tokio` 1.50.0 → 1.52.1, `openssl` 0.10.76 → 0.10.78 - Frontend dependencies bumped (minor/patch): `i18next` 26.0.4 → 26.0.6, `react-i18next` 17.0.2 → 17.0.4, `tailwindcss` + `@tailwindcss/vite` 4.2.2 → 4.2.4, `typescript` 6.0.2 → 6.0.3, `vite` 8.0.8 → 8.0.9, `vitest` 4.1.4 → 4.1.5, `happy-dom` + `@happy-dom/global-registrator` 20.8.9 → 20.9.0 - GitHub Actions bumped: `actions/checkout` 4 → 6, `actions/setup-node` 4 → 6, `pnpm/action-setup` 4 → 6 - Dependabot configuration added for Cargo, npm, and GitHub Actions ecosystems so future dependency updates land as reviewable PRs - Linux CI hardened with `DEBIAN_FRONTEND=noninteractive` to prevent apt-get prompts from hanging the runner - `.gitignore` now ignores `.planning/` and `.jules/` recursively so local planning artefacts never leak into status - Removed legacy `.jules` tracking files from the repository ### Fixed - Hue stream polling overlapping probes when a health check ran longer than the interval (migrated to recursive `setTimeout`) - DeviceSection and SettingsLayout test suites updated for the b06 redesign markup - LightsSection test suite: added a `Trans` mock so rich-text i18n fragments render deterministically in jsdom - Removed unused imports that were failing `tsc --noEmit` with TS6133 after recent refactors - Hardcoded fallback strings in Device and Updater UIs replaced with `t()` keys so EN/TR locales render consistently ### Performance - RoomMapEditor: isolated high-frequency mouse-coordinate state into a dedicated child that uses native DOM listeners with `requestAnimationFrame` throttling, eliminating full-editor re-renders on cursor movement - SettingsLayout: wrapped in `React.memo` to prevent polling-triggered re-renders of the entire settings tree ### Known Limitations - USB output is single-zone: the ambilight worker currently samples one pixel and sends a single RGB triplet per frame to the controller, which the companion firmware extends across the full strip. Per-edge position sampling driven by `LedCalibrationConfig` (edge counts, start anchor, direction, bottom gap) is planned for v1.4; the calibration UI still records and persists the full layout so the Hue channel path and future USB wiring stay consistent. - The USB serial frame format is LumaSync-specific (`0xAA 0x55` header, LE LED count, gamma-corrected RGB, XOR checksum) — earlier documentation referred to this as "Adalight-compatible", which it is not.
Open on GitHub - LumaSync v1.2.0
### Added - Room map editor: undo/redo with Cmd+Z / Cmd+Shift+Z (max 50 steps) - Room map editor: collapsible object list panel (right sidebar) with grouped objects and inline rename - Room map editor: smart snap alignment guides (edge/center) during drag operations - Room map editor: origin crosshair marker with snap-to-center - Room map editor: right-click context menu (duplicate, delete, lock, z-order, rename, rotate) - Room map editor: property bar with numeric x/y/w/h/rotation inputs for precise positioning - Room map editor: extended keyboard shortcuts (Cmd+D duplicate, Shift+Arrow 10x nudge, L lock, [ ] z-order) - Room map editor: scroll wheel zoom (0.5x–3x) with mouse-centered scaling and Cmd+0 fit-to-view - Room map editor: space+drag and middle-mouse pan navigation - Room map editor: real-time mouse coordinate display in meters - Room map editor: template system with presets (TV 55", L-desk, full room, blank canvas) - Room map editor: multi-image background layers with per-layer opacity, lock, and reorder - Room map editor: universal object lock and resize handles for all object types - Room map editor: floating left toolbar replacing fixed top toolbar ### Fixed - Room map editor: rotated furniture resize now uses anchor-based positioning for correct behavior
Open on GitHub - LumaSync v1.1.1
### Fixed - Windows: calibration overlay close event no longer intercepted by the close-to-tray handler (overlay was preventing app quit) - Windows: overlay positioning now uses display's scale factor instead of window's runtime scale factor, fixing placement on DPI-scaled monitors - Windows: WebView2 child windows now receive `WS_EX_TRANSPARENT | WS_EX_LAYERED` so the overlay is truly click-through and does not block mouse events behind it
Open on GitHub - LumaSync v1.1.0
### Added - Ambilight: black border detection to crop letterbox bars before color sampling - Ambilight: user-configurable color transition speed (smoothing alpha) in settings - Tray: quick-action menu items (Lights Off, Resume Last Mode, Solid Color) with i18n label support - CI: universal macOS binary (x86_64 + arm64) support in release workflow - Debug: sidebar FPS widget in development builds ### Changed - Hue: per-channel EWMA smoothing and continuous position sampling for smoother color transitions - App version now resolved dynamically from the build instead of a hardcoded string - macOS deployment target set to 12.3 for SCStream compatibility ### Fixed - WS2812B output: apply gamma 2.2 correction for accurate perceived brightness - Ambilight UI: reflect mode state correctly in UI on transient Hue failure - Hue telemetry: fix stream state reporting after per-channel smoothing refactor - Tests: fix 2 failing unit tests and resolve 12 unhandled rejections in App test suite - SCStream: fix log timestamp formatting and release crash on session stop
Open on GitHub - LumaSync v1.0.4
### Changed - Migrated package manager from Yarn Classic (1.x) to pnpm 10; updated all scripts, CI/CD workflows, docs, and `tauri.conf.json` - SECURITY.md: updated supported versions table from `0.1.x` to `1.0.x` and added private vulnerability reporting link - README.md: added CI, Release, License, and Platform badges; added Platform Support table (macOS / Windows / Linux) - CONTRIBUTING.md: commit examples updated with scope prefixes; added fork workflow and review process sections - CODE_OF_CONDUCT.md: added GitHub private vulnerability reporting as a confidential report channel ### Fixed - Release workflow (`release.yml`): added `typecheck`, `verify:shell-contracts`, and `vitest run` validation steps before build - CI workflow (`ci.yml`): added `vitest run` step for frontend test coverage - CHANGELOG.md: removed stale separator under `[Unreleased]` ### Added - `.github/ISSUE_TEMPLATE/config.yml`: issue template chooser with security advisory link and blank issue restriction - CLAUDE.md: added Code Style, Verification Flow sections; consolidated with AGENTS.md as single source of truth - AGENTS.md: rewritten as thin reference to CLAUDE.md with agent-specific behavioral rules only ### Fixed (tests) - `App.test.tsx`: fixed mode orchestration tests for updated output target and Hue gate behavior - `manualConnectFlow.test.ts`: fixed auto-scan, stale selection, remembered port, and refresh throttle tests - `useHueOnboarding.runtime.test.ts`: fixed retry pipeline routing test - `GeneralSection.test.tsx`: fixed solid payload color change test - `useRoomMapPersist.test.ts`: fixed resetConfig default room map test
Open on GitHub - LumaSync v1.0.3
### Added - Room map canvas editor with draggable furniture, TV anchor, and USB strip objects (`RoomMapEditor`, `RoomMapCanvas`, `RoomMapToolbar`) - `HueChannelOverlay` renders channel positions on the room map using a `[-1,1]` normalized coordinate system - `HueChannelMapPanel`: drag-and-drop single and multi-channel positioning, z-axis detail strip, coordinate tooltips, positions persisted via `shellStore` - Zone auto-derivation: `deriveZones` algorithm maps LED strip positions to Hue channel regions automatically (13 unit tests) - `ZoneDeriveOverlay` and `ZoneListPanel` for reviewing, renaming, and deleting derived zones; zone assignment mode in `HueChannelOverlay` - `HueReadySummaryCard` in Device section — shows stream state indicator, entertainment area name, and bridge IP when Hue is connected - `update_hue_channel_positions` Rust command writes edited channel positions back to the Hue bridge with save confirmation UI - Target-aware lighting pipeline: `targets` field on `LightingModeConfig` selects which output devices (USB / Hue) participate per mode - `resolveDefaultTargets` helper preserves backward compatibility with persisted configs that predate the targets field - USB hot-plug detection: suggestion banner appears when a USB controller is plugged in while Hue-only mode is active - Startup target filtering: USB target is silently removed from persisted state if the device is not connected on launch - Delta start/stop in `handleOutputTargetsChange` — adding or removing an output target while a mode is active no longer restarts the full pipeline - `HueTelemetryGrid` component in Diagnostics tab showing live DTLS stream metrics - `HUE_FAULT_CODES` typed constant map replaces raw string matching for all DTLS fault conditions - `FullTelemetrySnapshot` type and `get_full_telemetry_snapshot` Tauri command for combined runtime diagnostics - `simulate_hue_fault` Rust command for fault injection during development and testing - `copy_background_image` Rust command for importing a floor-plan background into the room map - `roomMap.ts` contract: placement types, `RoomMapObject` discriminated union, coordinate definitions - `UPDATE_CHANNEL_POSITIONS` command and associated status codes added to `hue.ts` contract - `roomMap` persistence field and `ROOM_MAP` section ID added to `shell.ts` contract - Shell contracts verifier extended to validate room map and Hue channel position contract coverage - `targetFailed` i18n key under `device.hue` namespace (EN + TR) - Tauri `dialog` and `fs` plugins for background image import ### Fixed - `handleOutputTargetsChange` no longer stops an active lighting mode when a target is only being added (not removed) - DTLS reconnect monitor correctly detects and registers thread death in all failure paths
Open on GitHub - v1.0.2
**Full Changelog**: https://github.com/voyvodka/LumaSync/compare/v1.0.1...v1.0.2
Open on GitHub - v1.0.1
**Full Changelog**: https://github.com/voyvodka/LumaSync/compare/v1.0...v1.0.1
Open on GitHub