voyvodka/LumaSync

Mirror your screen to WS2812B LED strips and Philips Hue entertainment areas in real time. Local-only, brand-agnostic, MIT-licensed.

0stars
0forks
0watchers
3open issues
status: CORElanguage: TypeScriptbranch: mainlicense: MIT Licenseupdated: 4/27/2026, 8:29:20 AMlast push: 4/28/2026, 9:19:48 PM
ambient-lightingambilightdesktop-appledmacosphilips-huereactrustscreen-capturetauritypescriptwindowsws2812b

README Snapshot

LumaSync

Website CI Release License: MIT Platform: macOS | Windows

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.

LumaSync compact lights view LumaSync full lights view

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 0x55 header, 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-api is 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 server
  • pnpm tauri dev: run desktop app in development mode
  • pnpm typecheck: run TypeScript type checks (no emit)
  • pnpm lint: alias for typecheck
  • pnpm vitest run: run frontend unit tests once
  • pnpm vitest: run frontend tests in watch mode
  • pnpm verify:shell-contracts: validate Rust command handlers match frontend contract definitions
  • pnpm check:rust: run Rust cargo check
  • pnpm check:all: run JS + Rust + shell contract checks together

Project Structure

  • src/: React application and feature modules
  • src/shared/contracts/: cross-layer contract definitions
  • src-tauri/src/commands/: Rust Tauri command handlers
  • docs/: 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 / 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

[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 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

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