Desktop-приложение, которое видит все лица на сцене через веб-камеру, позволяет выбрать одно из них кликом и управляет световой головой по DMX так, чтобы луч следил за выбранным человеком.
Стек: Kotlin / JVM, Compose Multiplatform for Desktop, OpenCV YuNet (через JavaCV), Art-Net для DMX, Koin для DI.
- Bootstrap проекта (Gradle, Compose, JavaCV).
- Захват веб-камеры и превью (1280×720, avfoundation на macOS).
- YuNet face detection — все лица в кадре одновременно, bbox + 5 keypoints.
- UI выбора POI: клик по лицу → это лицо становится целью прожектора.
- Face tracking: стабильные ID между кадрами, чтобы выбор не терялся.
- Art-Net DMX sender + DmxFixture (artnet4j, unicast, multi-fixture ready).
- Сцены: сохранение/загрузка конфигурации фикстур и калибровки в
~/.lighthouse/scenes/. - 4-точечная homography калибровка камера → pan/tilt (с визуальным визардом и полигоном покрытия).
- Clean Architecture: domain/adapter/app/ui слои; правило зависимостей читается по импортам.
- One-Euro filter сглаживания движения (pan + tilt, адаптивный cutoff).
- Edge cases: лицо пропало (blackout работает; hold-last в планах), потеря камеры.
- macOS, Linux или Windows.
- JDK 21 (Temurin рекомендован).
- Веб-камера.
- Опционально: QLC+ для отладки без физической световой головы.
git clone <repo>
cd lighthouseJDK 21 ставим один раз. macOS:
brew install --cask temurin@21ONNX-модели хранятся в Git LFS. Установи его до клонирования, иначе вместо модели скачается текстовый указатель и приложение упадёт на старте:
brew install git-lfs
git lfs installЕсли Gradle не находит JDK 21 автоматически, пропиши путь в ~/.gradle/gradle.properties (per-machine, в репо не лежит):
org.gradle.java.home=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home./gradlew runПри первом запуске macOS попросит разрешение на доступ к камере — выдай его процессу, который её открыл (Terminal, iTerm или Android Studio).
./gradlew packageDmg
./gradlew packageDistributionForCurrentOSSceneManagerScreen → загрузить / создать SceneData (~/.lighthouse/scenes/)
│
▼
CameraSource (JavaCV) → TrackingPipeline → StateFlow<DetectedFrame>
│ │
YuNetDetector CameraPreview (Compose)
(все лица в кадре) Image + FaceOverlay
│
SpotlightController
(выбранное лицо → pan/tilt)
│
HomographyMapper (опционально)
4-точечная калибровка камера→pan/tilt
или линейный fallback если нет калибровки
│
List<DmxFixture> ← по одному на голову
│
ArtNetClient (artnet4j)
unicastDmx → QLC+ / голова
Конвейер живёт в одном Flow на Dispatchers.IO. UI подписывается на StateFlow и перерисовывает превью с оверлеем поверх кадра. На каждый кадр SpotlightController пересчитывает координаты центра выбранного лица через гомографическую матрицу (или линейно если калибровки нет) в 16-bit pan/tilt и отправляет Art-Net пакет по unicast на каждую зарегистрированную голову.
gradle/libs.versions.toml — version catalog
build.gradle.kts — Kotlin 2.0 + Compose 1.7 + JavaCV + Koin
src/main/kotlin/tracker/
Main.kt — startKoin + when(AppState.screen)
di/AppModule.kt — Koin: wire-up всех синглтонов
domain/
entity/ — FaceDetection, TrackedFace, SceneData,
DmxFixture, PanTilt, CalibrationData, …
usecase/ — FaceTracker, CalibrationUseCase, PositionMapper,
MapperFactory, DmxSender, DmxSenderFactory
repository/SceneRepository.kt— интерфейс персистентности сцен
adapter/
camera/ — CameraSource, YuNetDetector
calibration/ — HomographyMapper (findHomography)
dmx/ — ArtNetSender
persistence/SceneStore.kt — JSON-файлы в ~/.lighthouse/scenes/
app/
AppState.kt — AppScreen, CalibrationStatus, AppState
AppViewModel.kt — навигация, scenes StateFlow, spotlight lifecycle
TrackingPipeline.kt — Flow<DetectedFrame>: capture → detect → emit
FacePositionResolver.kt — resolve(frame, id, mapper?) → PanTilt?
SpotlightController.kt — FacePositionResolver + DmxSender (оркестрация)
ui/
CameraPreview.kt — Image + FaceOverlay; onRawClick для калибровки
TrackingScreen.kt — превью + плавающий тулбар
SceneManagerScreen.kt — список сцен
SceneEditorScreen.kt — редактор + 4-точечный калибровочный визард
src/main/resources/models/ — ONNX-модели (YuNet)
Все версии зависимостей — в gradle/libs.versions.toml. Шпаргалка по проекту и грабли — в CLAUDE.md.
./gradlew compileKotlin # быстрая проверка ошибок
./gradlew run # запустить
./gradlew tasks --group "compose desktop"
./gradlew --stop # рестарт демонаTBD.