403 Commits

Author SHA1 Message Date
997ff2fd70 Migrate frontend from JavaScript to TypeScript
- Rename all 54 .js files to .ts, update esbuild entry point
- Add tsconfig.json, TypeScript devDependency, typecheck script
- Create types.ts with 25+ interfaces matching backend Pydantic schemas
  (Device, OutputTarget, ColorStripSource, PatternTemplate, ValueSource,
  AudioSource, PictureSource, ScenePreset, SyncClock, Automation, etc.)
- Make DataCache generic (DataCache<T>) with typed state instances
- Type all state variables in state.ts with proper entity types
- Type all create*Card functions with proper entity interfaces
- Type all function parameters and return types across all 54 files
- Type core component constructors (CardSection, IconSelect, EntitySelect,
  FilterList, TagInput, TreeNav, Modal) with exported option interfaces
- Add comprehensive global.d.ts for window function declarations
- Type fetchWithAuth with FetchAuthOpts interface
- Remove all (window as any) casts in favor of global.d.ts declarations
- Zero tsc errors, esbuild bundle unchanged

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:08:23 +03:00
55772b58dd Replace deploy workflow with portable Windows release build
- Remove old Docker-based deploy.yml
- Add release.yml: builds portable ZIP on tag push, uploads to Gitea
- Add build-dist.ps1: downloads embedded Python, installs deps, bundles app
- Add scrollbar-gutter: stable to prevent layout shift

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 11:21:55 +03:00
968046d96b HA integration: fix reload loop, parallel device fetch, WS guards, translations
- Fix indentation bug causing scenes device to not register
- Use nonlocal tracking to prevent infinite reload loops on target/scene changes
- Guard WS start/stop to avoid redundant connections
- Parallel device brightness fetching via asyncio.gather
- Route set_leds service to correct coordinator by source ID
- Remove stale pattern cache, reuse single timeout object
- Fix translations structure for light/select entities
- Unregister service when last config entry unloaded

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 11:21:46 +03:00
122e95545c Card bulk operations, remove expand/collapse, graph color picker fix
- Bulk selection mode: Ctrl+Click or toggle button to enter, Escape to exit
- Shift+Click for range select, bottom toolbar with SVG icon action buttons
- All CardSections wired with bulk actions: Delete everywhere,
  Start/Stop for targets, Enable/Disable for automations
- Remove expand/collapse all buttons (no collapsible sections remain)
- Fix graph node color picker overlay persisting after outside click
- Add Icons section to frontend.md conventions
- Add trash2, listChecks, circleOff icons to icon system
- Backend: processing loop performance improvements (monotonic timestamps,
  deque-based FPS tracking)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 01:21:27 +03:00
f4647027d2 Show actual API error details in modal save/create failures
Previously modals showed generic "Failed to add/save" messages. Now they
extract and display the actual error detail from the API response (e.g.,
"URL is required", "Name already exists"). Handles Pydantic validation
arrays by joining msg fields.

Fixed in 8 files: device-discovery, devices, calibration,
advanced-calibration, scene-presets, automations, command-palette.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 15:19:08 +03:00
cdba98813b Backend performance and code quality improvements
Performance (hot path):
- Fix double brightness: removed duplicate scaling from 9 device clients
  (wled, adalight, ambiled, openrgb, hue, spi, chroma, gamesense, usbhid,
  espnow) — processor loop is now the single source of brightness
- Bounded send_timestamps deque with maxlen, removed 3 cleanup loops
- Running FPS sum O(1) instead of sum()/len() O(n) per frame
- datetime.now(timezone.utc) → time.monotonic() with lazy conversion
- Device info refresh interval 30 → 300 iterations
- Composite: gate layer_snapshots copy on preview client flag
- Composite: versioned sub_streams snapshot (copy only on change)
- Composite: pre-resolved blend methods (dict lookup vs getattr)
- ApiInput: np.copyto in-place instead of astype allocation

Code quality:
- BaseJsonStore: RLock on get/delete/get_all/count (was created but unused)
- EntityNotFoundError → proper 404 responses across 15 route files
- Remove 21 defensive getattr(x,'tags',[]) — field guaranteed on all models
- Fix Dict[str,any] → Dict[str,Any] in template/audio_template stores
- Log 4 silenced exceptions (automation engine, metrics, system)
- ValueStream.get_value() now @abstractmethod
- Config.from_yaml: add encoding="utf-8"
- OutputTargetStore: remove 25-line _load override, use _legacy_json_keys
- BaseJsonStore: add _legacy_json_keys for migration support
- Remove unnecessary except Exception→500 from postprocessing list endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 15:06:29 +03:00
1f047d6561 KC test uses shared LiveStreamManager, tree-nav dropdown, KC card badge fix
- KC test WS now acquires from LiveStreamManager instead of creating its
  own DXGI duplicator, eliminating capture contention with running LED targets
- Tree-nav refactored to compact dropdown on click with outside-click dismiss
  (closes on click outside the trigger+panel, not just outside the container)
- KC target card badge (e.g. "Daylight Cycle") no longer wastes empty space

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 14:50:33 +03:00
6a31814900 Fix scroll position reset when closing modals
- Use { behavior: 'instant' } in unlockBody scrollTo to override
  CSS scroll-behavior: smooth on html element
- Use { preventScroll: true } on focus() restore in Modal.forceClose
- Add overflow-y: scroll to body.modal-open to prevent scrollbar shift

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:39:53 +03:00
ea9b05733b Dim non-related edges and flow dots when a graph node is selected
- Fix CSS specificity: .dimmed now overrides .graph-edge-active opacity/filter
- Add data-from/data-to to flow dot groups so they can be dimmed per-edge
- Dim flow dots on non-chain edges in highlightChain(), restore on clear

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:14:32 +03:00
05152a0f51 Settings tabs, log overlay, external URL, Sources tree restructure, audio fixes
- Settings modal split into 3 tabs: General, Backup, MQTT
- Log viewer moved to full-screen overlay with compact toolbar
- External URL setting: API endpoints + UI for configuring server domain
  used in webhook/WS URLs instead of auto-detected local IP
- Sources tab tree restructured: Picture Source (Screen Capture/Static/
  Processed sub-groups), Color Strip, Audio, Utility
- TreeNav extended to support nested groups (3-level tree)
- Audio tab split into Sources and Templates sub-tabs
- Fix audio template test: device picker now filters by engine type
  (was showing WASAPI indices for sounddevice templates)
- Audio template test device picker disabled during active test
- Rename "Input Source" to "Source" in CSS test preview (en/ru/zh)
- Fix i18n: log filter/level items deferred to avoid stale t() calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:16:57 +03:00
191c988cf9 Graph node FPS hover tooltip, full names, no native SVG tooltips
Graph editor:
- Floating FPS tooltip on hover over running output_target nodes (300ms delay)
- Shows errors, uptime, and FPS sparkline seeded from server metrics history
- Tooltip positioned below node with fade-in/out animation
- Uses pointerover/pointerout with relatedTarget check to prevent flicker
- Fixed-width tooltip (200px) with monospace values to prevent layout shift
- Node titles show full names (removed truncate), no native SVG <title> tooltips

Documentation:
- Added duration/numeric formatting conventions to contexts/frontend.md
- Added node hover tooltip docs to contexts/graph-editor.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:45:59 +03:00
afd4a3bc05 Override blend mode, FPS sparkline, fix api_input persistence
New features:
- Override composite blend mode: per-pixel alpha from brightness
  (black=transparent, bright=opaque). Ideal for API input over effects.
- API input test preview FPS chart uses shared createFpsSparkline
  (same look as target card charts)

Fixes:
- Fix api_input source not surviving server restart: from_dict was
  still passing removed led_count field to constructor
- Fix composite layer brightness/processing selectors not aligned:
  labels get fixed width, selects fill remaining space
- Fix CSPT input selector showing in non-CSPT CSS test mode
- Fix test modal LED/FPS controls showing for api_input sources
- Server only sends test WS frames when api_input push_generation changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 15:12:57 +03:00
be356f30eb Fix HAOS light color reverting after timeout
When HA sets a color via turn_on, also update the source's fallback_color
to match. This way when the api_input timeout fires (default 5s), the
stream reverts to the same color instead of black. turn_off resets
fallback to [0,0,0].

Added coordinator.update_source() for PUT /color-strip-sources/{id}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 14:52:50 +03:00
8a6ffca446 Rework API input CSS: segments, remove led_count, HAOS light, test preview
API Input CSS rework:
- Remove led_count field from ApiInputColorStripSource (always auto-sizes)
- Add segment-based payload: solid, per_pixel, gradient modes
- Segments applied in order (last wins on overlap), auto-grow buffer
- Backward compatible: legacy {"colors": [...]} still works
- Pydantic validation: mode-specific field requirements

Test preview:
- Enable test preview button on api_input cards
- Hide LED/FPS controls for api_input (sender controls those)
- Show input source selector for all CSS tests (preselected)
- FPS sparkline chart using shared createFpsSparkline (same as target cards)
- Server only sends frames when push_generation changes (no idle frames)

HAOS integration:
- New light.py: ApiInputLight entity per api_input source (RGB + brightness)
- turn_on pushes solid segment, turn_off pushes fallback color
- Register wled_screen_controller.set_leds service for arbitrary segments
- New services.yaml with field definitions
- Coordinator: push_colors() and push_segments() methods
- Platform.LIGHT added to platforms list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 14:47:42 +03:00
823cb90d2d Show captured border width overlay in picture CSS test preview
Backend: send border_width in WS metadata and frame_dims (width, height)
as a separate JSON message on first JPEG frame.

Frontend: render semi-transparent green overlay rectangles on each active
edge showing the sampling region depth, plus a small px label. Overlays
are proportionally sized based on border_width relative to frame dimensions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:09:29 +03:00
00c9ad3a86 Live KC test WS, sync clock fix, device card perf, camera icons, tab indicator
Key Colors test:
- New WS endpoint for live KC target test streaming (replaces REST polling)
- Auto-connect on lightbox open, auto-disconnect on close
- Uses same FPS/preview_width as CSS source test (no separate controls)
- Removed FPS selector, start/stop toggle, and updateAutoRefreshButton

Device cards:
- Fix full re-render on every poll caused by relative "Last seen" time in HTML
- Last seen label now patched in-place via data attribute (like FPS metrics)
- Remove overlay visualization button from LED target cards

Sync clocks:
- Fix card not updating start/stop icon: invalidate cache before reload

Other:
- Tab indicator respects bg-anim toggle (hidden when dynamic background off)
- Camera backend icon grid uses SVG icons instead of emoji
- Frontend context rule: no emoji in IconSelect items

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 02:03:07 +03:00
bcba5f33fc OpenRGB dedup fix, device card URL badge overflow fix
- Replace threshold-based dedup with exact equality check in OpenRGB client;
  threshold dedup caused animation stutter at low software brightness
- Add brightness_control capability to OpenRGB provider (software simulated)
- Fix device card URL/COM badge overlapping close button: badge stays inside
  card-title flex container, both name and badge truncate with ellipsis

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 01:36:36 +03:00
29b43b028d Fix automation badge overflow, dashboard crosslinks, compact numbers, icon grids, OpenRGB brightness
UI fixes:
- Automation card badge moved to flex layout — title truncates, badge stays visible
- Automation condition pills max-width increased to 280px
- Dashboard crosslinks fixed: pass correct sub-tab key (led-targets not led)
- navigateToCard only skips data load when tab already has cards in DOM
- Badge gets white-space:nowrap + flex-shrink:0 to prevent wrapping

New features:
- formatCompact() for large frame/error counters (1.2M, 45.2K) with hover title
- Log filter and log level selects replaced with IconSelect grids
- OpenRGB devices now support software brightness control

OpenRGB improvements:
- Added brightness_control capability (uses software brightness fallback)
- Change-threshold dedup compares raw pixels before brightness scaling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 01:29:17 +03:00
304fa24389 Comprehensive WebUI review: 41 UX/feature/CSS improvements
Safety & Correctness:
- Add confirmation dialogs to Stop All, turnOffDevice
- i18n confirm dialog (title, yes, no buttons)
- Fix duplicate tutorial-overlay ID
- Define missing CSS variables (--radius, --text-primary, --hover-bg, --input-bg)
- Fix toast z-index conflict with confirm dialog (2500 → 3000)

UX Consistency:
- Add backdrop-close to test modals
- Add device clone feature (only entity without it)
- Add sync clocks to command palette
- Replace 20+ hardcoded accent colors with CSS vars/color-mix()
- Remove dead .badge duplicate from components.css
- Make calibration elements keyboard-accessible (div → button)
- Add aria-labels to color picker swatches
- Fix pattern canvas mobile horizontal scroll
- Fix graph editor mobile bottom clipping

Polish:
- Add empty-state messages to all CardSection instances
- Convert 21 px font-sizes to rem
- Add scroll-behavior: smooth with reduced-motion override
- Add @media print styles
- Add :focus-visible to 4 missing interactive elements
- Fix settings modal close label (Cancel → Close)
- Fix api-key submit button i18n

New Features:
- Command palette actions: start/stop targets, activate scenes, enable/disable
- Bulk start/stop API endpoints (POST /output-targets/bulk/start|stop)
- OS notification history viewer modal
- Scene "used by" automation reference count on cards
- Clock elapsed time display on Streams tab cards
- Device "last seen" relative timestamp on cards
- Audio device refresh button in edit modal
- Composite layer drag-to-reorder
- MQTT settings panel (broker config with JSON persistence)
- WebSocket log viewer with level filtering and ring buffer
- Runtime log-level adjustment (GET/PUT endpoints + settings UI)
- Animated value source waveform canvas preview
- Gradient custom preset save/delete (localStorage)
- API key read-only display in settings
- Backup metadata (file size, auto/manual badges)
- Server restart button with confirm + overlay
- Partial config export/import per entity type
- Progressive disclosure in target editor (Advanced section)

CSS Architecture:
- Define radius scale tokens (--radius-sm/md/lg/pill)
- Scope .cs-filter selectors to remove 7 !important overrides
- Consolidate duplicate toggle switch (filter-list → settings-toggle)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 18:46:38 +03:00
a4a0e39b9b Replace bare — and generic None in selectors with descriptive None (reason) labels
All optional entity selectors now use the format "None (description)" with
i18n keys instead of hardcoded "—" or bare "None". Added common.none_no_cspt,
common.none_no_input, common.none_own_speed keys to all 3 locales. Updated
frontend context with the convention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 17:46:37 +03:00
bbe42ee0a2 Graph editor: unified card colors, keyboard focus, color picker button
- Unified graph node colors with card color system (shared localStorage)
- Added color picker palette button to node overlay toolbar
- Auto-focus graph container for keyboard shortcuts to work immediately
- Trap Tab key to prevent focus escaping to footer
- Added mandatory bundle rebuild note to CLAUDE.md files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 17:34:07 +03:00
0bb4d7c3aa Add video picture source: file, URL, YouTube, sync clock, trim, test preview
Backend:
- VideoCaptureSource dataclass with url, loop, playback_speed, start/end_time,
  resolution_limit, clock_id, target_fps fields
- VideoCaptureStream: OpenCV decode thread with frame-accurate sync clock seeking,
  loop, trim range, resolution downscale at decode time
- YouTube URL resolution via yt-dlp (auto-detects youtube.com, youtu.be, shorts)
- Thumbnail extraction from first frame (GET /picture-sources/{id}/thumbnail)
- Video test WS preview: streams JPEG frames with elapsed/frame_count metadata
- Run video_stream.start() in executor to avoid blocking event loop during
  yt-dlp resolution
- Full CRUD via existing picture source API (stream_type: "video")
- Wired into LiveStreamManager for target streaming

Frontend:
- Video icon (film) in picture source type map and graph node subtypes
- Video tree nav node in Sources tab with CardSection
- Video fields in stream add/edit modal: URL, loop toggle, playback speed slider,
  target FPS, start/end trim times, resolution limit
- Video card rendering with URL, FPS, loop, speed badges
- Clone data support for video sources
- i18n keys for video source in en/ru/zh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 23:48:43 +03:00
0bbaf81e26 Major graph editor improvements: standalone features, touch, docking, UX
Graph standalone features:
- Clone button on all entity nodes (copy icon, watches for new entity)
- Scene preset activation button (play icon, calls /activate API)
- Automation enable/disable via start/stop toggle (PUT enabled)
- Add missing entity types: sync_clock, scene_preset, pattern_template
- Fix edit/delete handlers for cspt, sync_clock
- CSPT added to test/preview button kinds
- Bulk delete with multi-select + Delete key confirmation
- Undo/redo framework with toolbar buttons (disabled when empty)
- Keyboard shortcuts help panel (? key, draggable, anchor-persisted)
- Enhanced search: type:device, tag:production filter syntax
- Tags passed through to all graph nodes for tag-based filtering
- Filter popover with grouped checkboxes replaces flat pill row

Touch device support:
- Pinch-to-zoom with 2-finger gesture tracking
- Double-tap zoom toggle (1.0x ↔ 1.8x)
- Multi-touch pointer tracking with pinch-to-pan
- Overlay buttons and port labels visible on selected (tapped) nodes
- Larger touch targets for ports (@media pointer: coarse)
- touch-action: none on SVG canvas
- 10px dead zone for touch vs 4px for mouse

Visual improvements:
- Port pin labels shown outside node on hover/select (outlined text)
- Hybrid active edge flow: thicker + glow + animated dots
- Test/preview icon changed to flask (matching card tabs)
- Clone icon scaled down to 60% for compact overlay buttons
- Monospace font for metric values (stable-width digits)
- Hide scrollbar on graph tab (html:has override)

Toolbar docking:
- 8-position dock system (4 corners + 4 side midpoints)
- Vertical layout when docked to left/right sides
- Dock position indicators shown during drag (dots with highlight)
- Snap animation on drop
- Persisted dock position in localStorage

Resize handling:
- View center preserved on fullscreen/window resize (ResizeObserver)
- All docked panels re-anchored on container resize
- Zoom inertia for wheel and toolbar +/- buttons

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 19:58:45 +03:00
50c40ed13f Frontend performance and code quality improvements
Performance: cache getBoundingClientRect in card-glare and drag-drop,
build adjacency Maps for O(1) graph BFS, batch WebGL uniform uploads,
cache matchMedia/search text in card-sections, use Map in graph-layout.

Code quality: extract shared FPS chart factory (chart-utils.js) and
FilterListManager (filter-list.js), replace 14-way CSS editor dispatch
with type handler registry, move state to state.js, fix layer violation
in api.js, add i18n for hardcoded strings, sync 53 missing locale keys,
add HTTP error logging in DataCache.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 18:14:26 +03:00
014b4175b9 Add transient preview WS endpoint and test button in CSS editor modal
- Add /color-strip-sources/preview/ws endpoint for ad-hoc source preview
  without saving (accepts full config JSON, streams RGB frames)
- Add test preview button (flask icon) to CSS editor modal footer
- For self-contained types (static, gradient, color_cycle, effect, daylight,
  candlelight), always previews current form values via transient WS
- For non-previewable types, falls back to saved source test endpoint
- Fix route ordering: preview/ws registered before {source_id}/ws
- Fix css-test-led-control label alignment (display: inline globally)
- Add gradient onChange callback for future live-update support
- Add i18n keys for preview (en/ru/zh)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 14:49:22 +03:00
6c7b7ea7d7 Separate tree nodes into independent panels, remove graph local search, UI improvements
- Split Sources tab: raw/raw_templates, processed/proc_templates each get own panel
- Split Targets tab: led-devices, led-targets, kc-targets, kc-patterns each get own panel
- Remove graph local search — search button and / key open global command palette
- Add graphNavigateToNode for command palette → graph node navigation
- Add tree group expand/collapse animation (max-height + opacity transition)
- Make tree group headers visually distinct (smaller, uppercase, left border on children)
- Make CardSection collapse opt-in via collapsible flag (disabled by default)
- Move filter textbox next to section title (remove margin-left: auto)
- Fix notification bell button vertical centering in test preview
- Fix clipboard copy on non-HTTPS with execCommand fallback
- Add overlay toggle button on picture-based CSS cards
- Add CSPT to graph add-entity picker and global search
- Update all cross-link navigation paths for new panel keys
- Add i18n keys for new tree groups and search groups (en/ru/zh)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:32:13 +03:00
3292e0daaf Add graph icon grid, search-to-graph nav, overlay on CSS cards, fix clipboard copy
- Convert graph editor add-entity menu to showTypePicker icon grid with SVG icons
- Add CSPT to graph add-entity picker and ALL_CACHES watcher
- Add graphNavigateToNode() — command palette navigates to graph node when graph tab active
- Add CSPT entities to global search palette results
- Add overlay toggle button on picture-based CSS cards (toggleCSSOverlay)
- Fix clipboard copy on non-HTTPS (LAN) with execCommand fallback for all copy functions
- Fix notification bell button vertical centering in test preview strip canvas
- Add overlay.toggle, search.group.cspt i18n keys (en/ru/zh)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 11:32:55 +03:00
294d704eb0 Add CSPT entity, processed CSS source type, reverse filter, and UI improvements
- Add Color Strip Processing Template (CSPT) entity: reusable filter chains
  for 1D LED strip postprocessing (backend, storage, API, frontend CRUD)
- Add "processed" color strip source type that wraps another CSS source and
  applies a CSPT filter chain (dataclass, stream, schema, modal, cards)
- Add Reverse filter for strip LED order reversal
- Add CSPT and processed CSS nodes/edges to visual graph editor
- Add CSPT test preview WS endpoint with input source selection
- Add device settings CSPT template selector (add + edit modals with hints)
- Use icon grids for palette quantization preset selector in filter lists
- Use EntitySelect for template references and test modal source selectors
- Fix filters.css_filter_template.desc missing localization
- Fix icon grid cell height inequality (grid-auto-rows: 1fr)
- Rename "Processed" subtab to "Processing Templates"
- Localize all new strings (en/ru/zh)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 02:16:59 +03:00
7e78323c9c Add LED axis ticks and calibration labels to color strip test preview
- Add horizontal axis with tick marks and LED index labels below strip
  and composite preview canvases (first/last labels edge-aligned)
- Show actual/calibration LED count label on picture-based composite
  layers (e.g. "25/934")
- Display warning icon in orange when LED counts don't match
- Send is_picture and calibration_led_count in composite layer_infos

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:47:22 +03:00
d1c8324c0f Move color strip sources from Targets tab to Sources tab
- Remove csColorStrips CardSection from targets.js, add to streams.js
- Add color_strip sub-tab with tree nav entry between Picture and Audio
- Update navigateToCard refs in target cards and command palette
- Update tutorial steps: remove led-css from targets, add color_strip to sources
- Add i18n keys for streams.group.color_strip and tour.src.color_strip

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:37:06 +03:00
49c2a63d68 Bundle frontend with esbuild, serve fonts offline, fix dashboard
- Add esbuild bundling: JS (IIFE, minified, sourcemapped) and CSS into
  single dist/ files, replacing 15+ individual CSS links and CDN scripts
- Bundle Chart.js and ELK.js from npm instead of CDN (fully offline)
- Serve DM Sans and Orbitron fonts locally from static/fonts/
- Fix dashboard automation card stretching full width (max-width: 500px)
- Fix time_of_day condition not localized in automation cards
- Add Chrome browser tools context file for MCP testing workflow
- Update frontend context with bundling docs and Chrome tools reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:20:20 +03:00
46d77052ad Add GZip compression middleware for static file serving
Reduces transfer sizes by ~75% (e.g. graph-editor.js 74KB→16KB,
en.json 92KB→22KB), significantly improving page load times.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 21:58:33 +03:00
dd92af9913 Add graph filter by entity type/running state and fix duplicate API calls
- Add entity type toggle pills and running/stopped filter to graph filter bar
- DataCache: return cached data if fresh, skip redundant fetches on page load
- Entity events: use force-fetch instead of invalidate+fetch to avoid stale gap
- Add no-cache middleware for static JS/CSS/JSON to prevent stale browser cache
- Reduces API calls on page load from ~70 to ~30

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 21:56:46 +03:00
a922c6e052 Add type picker for entity creation, icon grid filter, and serial port placeholder
- Replace inline type selectors with pre-modal type picker grid for devices,
  color strip sources, and value sources
- Add filterable search to icon grid when items > 9 (no auto-focus on touch)
- Show disabled (grayed-out) filtered items instead of hiding them
- Responsive grid columns (2-5 cols based on viewport width)
- Add "Select a port..." placeholder to serial port dropdown
- Update en/ru/zh locales with new keys

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 21:44:26 +03:00
6395709bb8 Unify graph docking, fix device hot-switch, and compact UI cards
- Unify minimap/toolbar/legend drag+dock into shared _makeDraggable() helper
- Persist legend visibility and position, add active state to toggle buttons
- Show custom colors only on graph cards (entity defaults remain in legend)
- Replace emoji overlay buttons with SVG path icons
- Fix stale is_running blocking target start (auto-clear if task is done)
- Resolve device/target IDs to names in conflict error messages
- Hot-switch LED device on running target via async stop-swap-start cycle
- Compact automation dashboard cards and fix time_of_day localization
- Inline CSS source pill on target cards to save vertical space

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 21:12:12 +03:00
272cb69247 Add 6 new device providers, IconSelect grids, and UI fixes
New device providers: ESP-NOW, Philips Hue, USB HID, SPI Direct,
Razer Chroma SDK, and SteelSeries GameSense — each with client,
provider, full backend registration, schemas, routes, and frontend
support including discovery, form fields, and i18n.

Add IconSelect grids for SPI LED chipset selector and GameSense
peripheral type selector with new Lucide icons (cpu, keyboard,
mouse, headphones).

Replace emoji graph overlay buttons (eye, bell) with proper SVG
path icons for consistent cross-platform rendering.

Fix connection overlay causing horizontal scroll by adding
overflow: hidden.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 20:32:28 +03:00
51ec0970c3 Add per-button tooltips to graph overlay and widen stream test modal
- Each graph node overlay button now has its own <title> tooltip
  (Edit, Delete, Start/Stop, Test, etc.) instead of inheriting the
  card name from the parent group
- Widen #test-stream-modal to 700px (matching CSS source test modal)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 21:40:00 +03:00
153972fcd5 Fix device provider kwargs, camera crash guard, target API, and graph color picker
- Refactor all device providers to use explicit kwargs.get() instead of
  fragile pop-then-passthrough (fixes WLED target start failing with
  unexpected dmx_protocol kwarg)
- Add process-wide camera index registry to prevent concurrent opens of
  the same physical camera which crashes the DSHOW backend on Windows
- Fix OutputTargetResponse validation error when brightness_value_source_id
  is None (coerce to empty string in response and from_dict)
- Replace native <input type="color"> in graph editor with the custom
  color picker popover used throughout the app, positioned via
  getScreenCTM() inside an absolute overlay on .graph-container

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 21:36:26 +03:00
8960e7dca3 Fix anchor positions getting corrupted by fullscreen mode
Skip persisting minimap/toolbar anchor data while in fullscreen so
dragging during fullscreen doesn't overwrite normal-mode offsets.
ResizeObserver now just clamps during fullscreen instead of
re-applying normal-mode anchors to the fullscreen-sized container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:43:07 +03:00
39981fbc45 Add graph editor filter, anchor-based positioning, and context docs
- Add name/kind/subtype filter bar with keyboard shortcut (F key)
- Filtered-out nodes get dimmed styling, nearly invisible on minimap
- Add anchor-based positioning for minimap and toolbar (remembers
  which corner element is closest to, maintains offset on resize)
- Fix minimap not movable after reload (_applyMinimapAnchor undefined)
- Fix ResizeObserver to use anchor system for both minimap and toolbar
- Add graph-editor.md context file and update frontend.md with graph sync notes
- Add filter i18n keys for en/ru/zh locales

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:39:14 +03:00
e163575bac Fix zoomToPoint animation to smoothly fly-to target node
Interpolate both view center and zoom level together using rAF
instead of CSS transitions, so the target node smoothly slides
to screen center while zooming in simultaneously.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:06:05 +03:00
844866b489 Zoom to newly added entity in graph editor instead of just panning
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:49:34 +03:00
5c7c2ad1b2 Enhance graph editor: fullscreen bg, add-entity focus, color picker fix, UI polish
- Move bg-anim canvas into graph container during fullscreen so dynamic background is visible
- Watch for new entity creation from graph add menu and auto-navigate to it after reload
- Position color picker at click coordinates instead of 0,0
- Replace test/preview play triangle with eye icon to distinguish from start/stop
- Always use port-aware bezier curves for edges instead of ELK routing
- Add fullscreen and add-entity buttons to toolbar with keyboard shortcuts (F11, +)
- Add confirmation dialog for relayout when manual positions exist
- Remove node body stroke, keep only color bar; add per-node color picker
- Clamp toolbar position on load to prevent off-screen drift
- Add graph tab to getting-started tutorial
- Add WASD/arrow spatial navigation, ESC reset, keyboard shortcuts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:48:55 +03:00
b370bb7d75 Add interactive graph editor connections: port-based edges, drag-connect, and detach
- Add visible typed ports on graph nodes (colored dots for each edge type)
- Route edges to specific port positions instead of node center
- Drag from output port to compatible input port to create/change connections
- Right-click edge context menu with Disconnect option
- Delete key detaches selected edge
- Mark nested edges (composite layers, zones) as non-editable with dotted style
- Add resolve_ref helper for empty-string sentinel to clear reference fields
- Apply resolve_ref across all storage stores for consistent detach support
- Add connection mapping module (graph-connections.js) with API field resolution
- Add i18n keys for connection operations (en/ru/zh)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:15:33 +03:00
ff24ec95e6 Add Art-Net / sACN (E1.31) DMX device support
Full-stack implementation of DMX output for stage lighting and LED controllers:
- DMXClient with Art-Net and sACN packet builders, multi-universe splitting
- DMXDeviceProvider with manual_led_count capability and URL parsing
- Device store, API schemas, routes wired with dmx_protocol/start_universe/start_channel
- Frontend: add/settings modals with DMX fields, IconSelect protocol picker
- Fix add device modal dirty check on type change (re-snapshot after switch)
- i18n keys for DMX in en/ru/zh locales

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:46:40 +03:00
18c886cbc5 Use primary color for running node icons and fix add device modal dirty check
- Running graph nodes show entity icon in --primary-color instead of --text-muted
- Fix AddDeviceModal always showing dirty: serialize zones array with JSON.stringify
  for proper strict equality comparison (matching DeviceSettingsModal pattern)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:05:37 +03:00
7902d2e1f9 Add start/stop, test, and notification buttons to graph editor node overlays
- Output targets and sync clocks get start/stop (▶/■) with optimistic UI update
- Test/preview button for templates, sources, and KC targets
- Notification test button (🔔) for notification color strip sources
- Fetch batch states to show correct running status for output targets
- Sync clocks show running state from API (is_running)
- Surgical DOM patching (patchNodeRunning) preserves hover state on toggle
- Success button hover style (green) for start action

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:56:19 +03:00
a54e2ab8b0 Add rubber-band selection, multi-node drag, edge click, and keyboard shortcuts
- Shift+drag on empty space draws selection rectangle to select multiple nodes
- Multi-node drag: dragging a selected node moves all selected nodes together
- Click edge to highlight it and its connected nodes
- Delete key removes single selected node, Ctrl+A selects all
- Edges now have pointer cursor for click affordance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:30:09 +03:00
6d85385dbb Add node dragging, animated flow dots, and canvas cleanup to graph editor
- Drag nodes to reposition with dead-zone, edge re-routing, and minimap sync
- Animated flow dots trace upstream chains to running nodes
- Manual positions persist across re-renders, cleared on relayout
- Fix canvas event listener leak on re-render by calling destroy()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:21:14 +03:00
bd7a315c2c Add visual graph editor for entity interconnections
SVG-based node graph with ELK.js autolayout showing all 13 entity types
and their relationships. Features include:

- Pan/zoom canvas with bounds clamping and dead-zone click detection
- Interactive minimap with viewport rectangle, click-to-pan, drag-to-move,
  and dual resize handles (bottom-left/bottom-right)
- Movable toolbar with drag handle and inline zoom percentage indicator
- Entity-type SVG icons from Lucide icon set with subtype-specific overrides
- Command palette search (/) with keyboard navigation and fly-to
- Node selection with upstream/downstream chain highlighting
- Double-click to zoom-to-card, edit/delete overlay on hover
- Legend panel, orphan node detection, running state indicators
- Full i18n support with languageChanged re-render
- Catmull-Rom-to-cubic bezier edge routing for smooth curves

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:01:47 +03:00