Repository navigation
feat: Add screen-follow ambient light from USB video capture #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
033bc31
5f05ce5
a556093
b3e4c99
3a1a118
e3bbfe9
4a170d9
f460c00
618066b
1d21a3a
9062eb7
2265dab
0d7ba55
1f56602
f6db9f6
b387433
753e3a7
2e06701
35df972
8e6304d
560e08f
e87c3a1
886288c
ff236a6
e1d92fb
4e6f97b
318b824
a8d1aa6
7cfe6f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -367,7 +367,6 @@ | |
| - `drift`: how far the scene wanders from center, in pixels; 0 pins it. | ||
| - `zoom`: the camera pushes in and settles back; 0 holds it fixed. | ||
|
|
||
|
|
||
| Origin: MoonLight (Sutaburosu) | ||
|
|
||
| Detail: [technical](moxygen/FixedPointEffect.md) | ||
|
|
@@ -1174,7 +1173,21 @@ | |
|
|
||
| ## MoonLight-native effects | ||
|
|
||
| <a id="moonlive"></a> | ||
| <a id="ambilight"></a> | ||
|
|
||
| ### Ambilight 📺 | ||
|
|
||
| <img src="../../assets/light/effects/AmbilightEffect.gif" width="300" alt="Ambilight effect preview"> | ||
|
|
||
| Paints the layer with the live frame from the [Video](../core/services.md#video) service, so lights around a display glow the color of the picture nearest them. Each light shows the **mean** of the rectangle mapping to it. Sampling, black bars and the layout's part: ⌄ details. | ||
|
|
||
| - `brightness`: scales the sampled color, dimming the video not the output. | ||
| - `saturation`: how far each channel is pushed from its zone's luma. | ||
| - `smoothing`: how much of the gap to a new color closes per frame. | ||
| - `snapAbove`: a channel moving further than this jumps instead of easing. | ||
| - `edgeDepth`: how far into the picture the outermost lights look. | ||
| - `detectBlackBars`: map the lights across the picture, not the frame. | ||
| - `barLevel`: how dark a pixel counts as bar (0 to 64). | ||
|
|
||
| ### MoonLive 📝 · any | ||
|
|
||
|
|
@@ -1336,3 +1349,33 @@ | |
| Detail: [technical](moxygen/SineEffect.md) | ||
|
|
||
| [Tests](../../reference/tests/unit-tests.md#sineeffect) | ||
|
|
||
| ## Ambilight, details | ||
|
|
||
| #### Why the mean | ||
|
|
||
| A single sampled pixel flickers on film grain and moving edges. The mean of the whole rectangle is steady, which is what makes the light read as belonging to the picture rather than chasing it. This is the box filter Hyperion uses. | ||
|
|
||
| #### Sampling depth | ||
|
|
||
| `edgeDepth` **sets** the depth rather than raising a floor, so a value below a position's own share makes its zone thinner instead. The outermost lights' own share is 1/height of the frame, a sliver at the very edge where compression is worst; Hyperion samples about 8%. | ||
|
Check warning on line 1361 in docs/moonmodules/light/effects.md
|
||
|
|
||
| #### Black bars | ||
|
|
||
| `barLevel` defaults to 12, about 5%, which matches Hyperion and suits MJPEG: that is conventionally full-range, so black arrives near 0. **If bars are never detected**, suspect a grabber passing limited range through: black then sits at 16 and nothing below 12 ever matches, so raise this above 16. Lower it if dark scenes get cropped instead. | ||
|
|
||
| `edgeDepth` cannot substitute for detection: it widens a zone from the edge, so a bar stays inside it. Detection resists a dark *scene* two ways: a reading is adopted only after 30 agreeing frames, and anything deeper than 40% of an axis is refused as a scene rather than a bar. | ||
|
Check warning on line 1367 in docs/moonmodules/light/effects.md
|
||
|
|
||
| #### The layout decides the shape | ||
|
|
||
| The effect fills a logical box and knows nothing else. On a [Rectangle](layouts.md#rectangle) the interior maps to no LED, so a border strip shows the frame's border; on a [Grid](layouts.md#grid) the same effect is a video wall. Where your strip starts and which way it runs are `startCorner`, `offset` and `clockwise` on the layout, not settings here. | ||
|
|
||
| With no video source it paints black. Every effect owns its background, so returning early would leave the previous effect's picture frozen on the strip. | ||
|
|
||
| Origin: MoonLight | ||
|
|
||
| Detail: [technical](moxygen/AmbilightEffect.md) | ||
|
|
||
| [Tests](../../reference/tests/unit-tests.md#ambilighteffect) | ||
|
|
||
| <a id="moonlive"></a> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Move the The
📝 Fix - `barLevel`: how dark a pixel counts as bar (0 to 64).
+
+<a id="moonlive"></a>
### MoonLive 📝 · any [Tests](../../reference/tests/unit-tests.md#ambilighteffect)
-
-<a id="moonlive"></a>🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,11 @@ | ||
| { | ||
| "commit": "7072824b", | ||
| "commit": "a8d1aa65", | ||
| "flash": { | ||
| "esp32s3-n16r8": 2142976, | ||
| "desktop": 1993480, | ||
| "desktop": 2033096, | ||
| "esp32": 2091488, | ||
| "esp32p4rev1-eth": 2045840, | ||
| "esp32p4rev1-eth-wifi": 2331904, | ||
| "esp32p4rev1-eth-wifi": 2493504, | ||
| "esp32s3-n8r8": 2087168, | ||
| "esp32s31": 2428080, | ||
| "esp32-16mb": 2060368, | ||
|
|
@@ -14,31 +14,33 @@ | |
| "qemu": 1383648, | ||
| "esp32p4rev3-eth": 1643760, | ||
| "esp32s3-zero": 2024192, | ||
| "esp32-pico": 2107168 | ||
| "esp32-pico": 2107168, | ||
| "esp32p4rev3-eth-wifi": 2498304 | ||
| }, | ||
| "measured": { | ||
| "esp32p4rev1-eth": "2026-09-22", | ||
| "esp32s31": "2026-09-22", | ||
| "esp32": "2026-09-25", | ||
| "esp32-pico": "2026-09-09", | ||
| "esp32s3-n16r8": "2026-09-25", | ||
| "desktop": "2026-09-25", | ||
| "desktop": "2026-09-27", | ||
| "esp32s3-n8r8": "2026-09-08", | ||
| "esp32s3-zero": "2026-09-08", | ||
| "esp32-16mb": "2026-09-09", | ||
| "esp32p4rev1-eth-wifi": "2026-09-22", | ||
| "esp32-eth": "2026-09-11" | ||
| "esp32p4rev1-eth-wifi": "2026-09-27", | ||
| "esp32-eth": "2026-09-11", | ||
| "esp32p4rev3-eth-wifi": "2026-09-27" | ||
| }, | ||
| "perf": { | ||
| "desktop": { | ||
| "tick_us": 1, | ||
| "fps": 1000000, | ||
| "tick_us": 28, | ||
| "fps": 35714, | ||
|
Comment on lines
+36
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
rg -n -C6 'tick_us|fps' moondeck/check/repo_health.py moondeck/check/collect_kpi.py | head -120Repository: MoonModules/MoonLight Length of output: 10027 🏁 Script executed: set -o pipefail
printf '%s\n' '--- diff summary ---'
git diff --stat c57ff4bde77032cc34fe2ffd58c1d1e962212281 7cfe6f475f5a8bb1e60b5d25750db3a7263d1971 -- docs/reference/metrics/repo-health.json moondeck/check/collect_kpi.py moondeck/check/repo_health.py
printf '%s\n' '--- snapshot diff ---'
git diff --unified=30 c57ff4bde77032cc34fe2ffd58c1d1e962212281 7cfe6f475f5a8bb1e60b5d25750db3a7263d1971 -- docs/reference/metrics/repo-health.json
printf '%s\n' '--- collector diff ---'
git diff --unified=35 c57ff4bde77032cc34fe2ffd58c1d1e962212281 7cfe6f475f5a8bb1e60b5d25750db3a7263d1971 -- moondeck/check/collect_kpi.py
printf '%s\n' '--- collector context ---'
nl -ba moondeck/check/collect_kpi.py | sed -n '90,245p'
printf '%s\n' '--- repo-health context ---'
nl -ba moondeck/check/repo_health.py | sed -n '520,590p'Repository: MoonModules/MoonLight Length of output: 18069 🏁 Script executed: set -o pipefail
printf '%s\n' '--- collect_kpi entrypoints and serialization ---'
rg -n -C8 -F -- 'collect_desktop' moondeck/check/collect_kpi.py moondeck/check/repo_health.py
rg -n -C10 -F -- 'repo-health.json' moondeck/check/collect_kpi.py moondeck/check/repo_health.py
rg -n -C8 -E 'perf|tick_us|collect_kpi|json.dump|json.dumps' moondeck/check/repo_health.py | tail -220
printf '%s\n' '--- base collector around desktop collection ---'
git show c57ff4bde77032cc34fe2ffd58c1d1e962212281:moondeck/check/collect_kpi.py | nl -ba | sed -n '70,245p'
printf '%s\n' '--- scenario definitions and references ---'
rg -n -C3 -F -- 'Video_mutation' test moondeck docs
rg -n -C3 -F -- 'scenario_Effects_pipeline_builds_and_renders' test moondeck docsRepository: MoonModules/MoonLight Length of output: 19757 🏁 Script executed: set -o pipefail
printf '%s\n' '--- repo_health snapshot and measurement ---'
nl -ba moondeck/check/repo_health.py | sed -n '580,680p'
printf '%s\n' '--- all repo_health performance references ---'
rg -n -C8 --glob 'repo_health.py' -e 'tick_us|fps|perf|scenario|collect' moondeck/check
printf '%s\n' '--- snapshot history context ---'
git log --oneline --all -- moondeck/check/collect_kpi.py docs/reference/metrics/repo-health.json | head -20Repository: MoonModules/MoonLight Length of output: 33276 Do not use the aggregate desktop tick as a regression baseline.
Use the fixed 🤖 Prompt for AI Agents |
||
| "scenario_p50": { | ||
| "Effects_pipeline_builds_and_renders": { | ||
| "p50": 8, | ||
| "p95": 19, | ||
| "n": 27, | ||
| "last": "2026-09-25" | ||
| "last": "2026-09-27" | ||
| }, | ||
| "Layouts_resize_reallocates_live": { | ||
| "p50": 66, | ||
|
|
@@ -49,8 +51,8 @@ | |
| } | ||
| }, | ||
| "esp32": { | ||
| "tick_us": 8354, | ||
| "fps": 119 | ||
| "tick_us": 6832, | ||
| "fps": 146 | ||
| }, | ||
| "scenario_matrix": { | ||
| "Firmware_reports_what_is_running": { | ||
|
|
@@ -74,7 +76,7 @@ | |
| "p50": 8, | ||
| "p95": 19, | ||
| "n": 27, | ||
| "last": "2026-09-25" | ||
| "last": "2026-09-27" | ||
| } | ||
| }, | ||
| "Effects_swap_while_running": { | ||
|
|
@@ -92,58 +94,66 @@ | |
| "n": 8, | ||
| "last": "2026-09-24" | ||
| } | ||
| }, | ||
| "Video_mutation": { | ||
| "desktop-macos": { | ||
| "p50": 30, | ||
| "p95": 30, | ||
| "n": 1, | ||
| "last": "2026-09-27" | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| "loc": { | ||
| "core": 22174, | ||
| "light": 30956, | ||
| "platform": 16776, | ||
| "core": 22736, | ||
| "light": 31637, | ||
| "platform": 17439, | ||
| "ui": 11360, | ||
| "test": 57352, | ||
| "moondeck": 27952 | ||
| "test": 58703, | ||
| "moondeck": 27964 | ||
| }, | ||
| "comments": { | ||
| "core": { | ||
| "lines": 5659, | ||
| "ratio": 0.282 | ||
| "lines": 5792, | ||
| "ratio": 0.281 | ||
| }, | ||
| "light": { | ||
| "lines": 7456, | ||
| "lines": 7604, | ||
| "ratio": 0.27 | ||
| }, | ||
| "platform": { | ||
| "lines": 3605, | ||
| "ratio": 0.24 | ||
| "lines": 3710, | ||
| "ratio": 0.238 | ||
| }, | ||
| "ui": { | ||
| "lines": 3396, | ||
| "ratio": 0.316 | ||
| }, | ||
| "test": { | ||
| "lines": 6675, | ||
| "lines": 6830, | ||
| "ratio": 0.135 | ||
| }, | ||
| "moondeck": { | ||
| "lines": 4673, | ||
| "lines": 4675, | ||
| "ratio": 0.19 | ||
| } | ||
| }, | ||
| "tests": { | ||
| "cases": 2100, | ||
| "scenarios": 11 | ||
| "cases": 2171, | ||
| "scenarios": 12 | ||
| }, | ||
| "docs": { | ||
| "md_files": 134, | ||
| "md_lines": 28075, | ||
| "md_lines": 28222, | ||
| "plans_files": 37, | ||
| "backlog_lines": 3110, | ||
| "lessons_lines": 526, | ||
| "claude_md_lines": 281 | ||
| }, | ||
| "complexity": { | ||
| "functions": 3703, | ||
| "over_threshold": 277, | ||
| "functions": 3819, | ||
| "over_threshold": 283, | ||
| "worst_ccn": 128 | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the heading level and the merged paragraph.
Line 229 uses an h4 (
####) directly under the h2## Shared, details. markdownlint reports MD001 (heading-increment). Use###for the three new sub-headings.Line 245 has no blank line before the existing
**A lightPreset reference…**paragraph. Markdown therefore joins the current-limiter text and the preset-reference text into one paragraph. Add a blank line after Line 245.📝 Proposed fix
📝 Committable suggestion
🧰 Tools
🪛 GitHub Check: vale
[warning] 245-245:
[vale] reported by reviewdog 🐶
[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.
Raw Output:
{"message":"[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.","location":{"path":"docs/moonmodules/light/drivers.md","range":{"start":{"line":245,"column":1},"end":{"line":245,"column":5}}},"severity":"INFO","code":{"value":"MoonLight.SentenceLength"}}
[warning] 243-243:
[vale] reported by reviewdog 🐶
[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.
Raw Output:
{"message":"[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.","location":{"path":"docs/moonmodules/light/drivers.md","range":{"start":{"line":243,"column":1},"end":{"line":243,"column":4}}},"severity":"INFO","code":{"value":"MoonLight.SentenceLength"}}
[warning] 241-241:
[vale] reported by reviewdog 🐶
[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.
Raw Output:
{"message":"[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.","location":{"path":"docs/moonmodules/light/drivers.md","range":{"start":{"line":241,"column":1},"end":{"line":241,"column":4}}},"severity":"INFO","code":{"value":"MoonLight.SentenceLength"}}
[warning] 237-237:
[vale] reported by reviewdog 🐶
[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.
Raw Output:
{"message":"[MoonLight.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma.","location":{"path":"docs/moonmodules/light/drivers.md","range":{"start":{"line":237,"column":14},"end":{"line":237,"column":16}}},"severity":"INFO","code":{"value":"MoonLight.SentenceLength"}}
🪛 markdownlint-cli2 (0.23.3)
[warning] 229-229: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
🤖 Prompt for AI Agents
Source: Linters/SAST tools