Skip to content

feature: Follow the screen with the lights around it - #138

Closed
Gohnnyman wants to merge 1 commit into
MoonModules:mainfrom
Gohnnyman:feat/ambilight-effect
Closed

Gohnnyman wants to merge 1 commit into
MoonModules:mainfrom
Gohnnyman:feat/ambilight-effect

Conversation

@Gohnnyman

@Gohnnyman Gohnnyman commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What's new

Lights around a display glow the colour of the picture nearest them.

  • VideoService — publishes one decoded RGB frame per tick, from a test pattern or a binary PPM. Carries the frame's tone curve, so a consumer averages light rather than bytes.
  • AmbilightEffect — each light shows the mean of the rectangle mapping to it, averaged in linear light. Smoothing, edge depth, letterbox detection.

Note

This PR is a part of #139 and #140 and should be merged first.
VideoService doesn't actually works with Video in this PR, proper USB Video decoding implemented in next PRs

Lights around a display now glow the color of the picture nearest them: a video source publishes one decoded RGB frame per tick, and an effect gives each light the mean of the rectangle mapping to it. The frame comes from a synthesized test pattern or a binary PPM, so the whole path is reviewable and testable on a desktop build. Capturing a real picture from an HDMI grabber over USB follows in its own change.

**Core**
- VideoService: two sources, a strict Netpbm P6 header parser, and a one-active-source seat so a service added or removed at runtime hands over rather than going dark
- VideoFrame: the frame contract, borrowing the producer's buffer for one tick
- Every frame carries its tone curve, sRGB here, so a consumer averages light rather than encoded bytes

**Light domain**
- AmbilightEffect: a per-light box filter averaged in LINEAR light, then encoded once per light, so a part-lit zone reads as bright rather than as a dim mush
- Positions reaching no LED are skipped, which on a border layout is most of the box, so a backlight strip costs its perimeter rather than its bounding box
- edgeDepth widens the outermost zones past the overscan junk; detectBlackBars moves them inside a letterbox, which edgeDepth cannot do
- Smoothing keeps 8.8 fixed-point state per channel, with snapAbove letting a cut land whole
- MappingLUT: hasDestination(), the one question the effect asks per position

**Tests**
- unit_VideoService: 13 cases over the header grammar, the seat election and the pattern's sweep rate
- unit_AmbilightEffect: 23 cases over orientation, coverage, the linear-light mean, smoothing in both directions, bar detection and the sparse-mapping skip, with a hollow-rectangle layout local to the file
- scenario_Video_source: add, configure and remove the service and its consumer under a running pipeline, which also pins the type registry, since the runner constructs every module through src/module_types.cpp

**Docs/CI**
- A Video card under core/services.md and an Ambilight card under light/effects.md, each with its details section
- screenshot_modules captures both

A strip is placed on a wall's edge pixels by the MoonLive library's backlight.mll, so this adds no layout. docgen: appendix lines 5617 to 5643, for the three new headers, which is the one rule that rises.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: MoonModules/MoonLight/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: c9acee9f-2bbc-45ed-a5fc-04475141afe6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ewowi

ewowi commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Thanks for splitting #114: reading the pieces one by one made something clear that the big PR hid. Together with TouchMyLight's planned FSEQ player, these are the first steps of one feature: content that comes from outside the device. I wrote down how I think it fits MoonLight's architecture, as a plan:
https://github.com/MoonModules/MoonLight/blob/next-iteration/docs/work/present/Plan-20261013%20-%20Streams%2C%20every%20frame%20from%20outside.md

The short version: two families meet in the layer. Channel data (Art-Net, sACN, DDP, FSEQ) is written in wiring order; pictures (capture, GIF, a test pattern) are sampled per light. Your VideoService is the picture source, and your Ambilight sampler, averaging in linear light, is the core of a picture effect that could then reach any layout, 3D included.

I'm going to research this further before we decide how to proceed, so this PR stays open for now. Please feel free to comment on the plan below: you've built the most of this so far, so your view on it is very welcome. One direction I'm considering is building a small shared groundwork first and adding your work on top in smaller steps, which would also make the reviews quicker.

One thing I'd like to ask for future PRs, and why: please keep each one to a single topic, roughly 400 changed lines and about ten files at most (tests welcome, generated files like metrics don't count). Beyond that size a review stops catching real problems: studies of code review (SmartBear and Cisco, and Google's own guide on small changes) find that reviewers miss most defects once a change grows past a few hundred lines. I review every line before it goes in, so small steps are what let me do that well, and they get merged faster too. Your #140 is a good example of the size that works. I've added this to our contributing rules.

Please hold off on updating this PR until I've done the groundwork; then we'll look together at where your work fits, so no effort goes into a shape that changes. For reference only, the review points so far:

  • size the smoother by the lit lights, not the whole box;
  • stride-sample each zone, so a 1080p frame can't overflow the sum or cost a read per source pixel;
  • bump seq only when the pixels change, and repaint on a control change;
  • a rebase on main: platform::fsReadAt became the read streams in Mount a microSD card at /sd, addressing ewowi's PR #134 review #136, so it doesn't compile on main yet.

@ewowi

ewowi commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

The groundwork for this is now on main (#141), so here is where your work fits.

What is set up

  • PictureService: the picture source, a service in Audio's pattern. It publishes a picture any number of effects read, with a test card as its first source.
  • PictureEffect: samples that picture onto any layout, with fit, fill or stretch, and point or area sampling in linear light. Area sampling averages each light's part of the picture, which is what a backlight needs.

What this means for #138
Following the screen is now the Picture effect's area sampling on a backlight layout, so it needs no effect of its own, and this PR can close. What remains of it is the part only you have built: border sampling, the edge depth and the smoothing, as one small PR extending PictureEffect's area sampling.

Where to read

For the PR: one topic, based on current main with only its own commits, max 400 changed lines and ten files (the rules). Not stacked on your other branches.

Thanks for the work that showed what this needed!

@Gohnnyman

Copy link
Copy Markdown
Contributor Author

Closing This PR in a favor of #149

@Gohnnyman Gohnnyman closed this Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants