Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ Each name is a script under `moondeck/`, run through `uv run`; the command and w

**`check_docgen` is a ratchet.** Errors are resolved before a commit, and warnings may only fall: the committed `docs/reference/metrics/docgen.md` is the number to beat, on the total and on every rule. It fails a run that raises either. Per rule as well as per total, because a total hides one rule paying for another, and because the cheapest way to satisfy a width rule is to split a line, which raises the block count and fixes nothing. A rule whose own limit changed is the one case to say so in the commit.

**A file with warnings is left better than it was found.** Holding the line is the floor, not the goal: the report is meant to shrink, and it only does so if each change spends a little effort on the warnings in the files it already touches. Reasonable effort, in the spirit of principle 5: the ones a reader would agree with, not a rewrite of every comment in the file. What resists is left with its count unchanged rather than forced, since a comment split to satisfy a width rule is the move the per-rule ratchet exists to refuse. Files the change never opened are a sweep of their own.
**A file with warnings is left better than it was found, and the aim is zero.** Errors stay at 0, always. Holding the warning line is the floor, not the goal. The report shrinks only if each change spends effort on the warnings in the files it already touches. **A touched file that still has warnings gets all of them resolved, so the file leaves the list entirely.** Clearing a file beats shaving one finding off each of five: a file at zero stays there, where a file at four drifts back. Reasonable effort, in the spirit of principle 5: the ones a reader would agree with, not a rewrite of every comment in the file. What resists is left with its count unchanged rather than forced, since a comment split to satisfy a width rule is the move the per-rule ratchet exists to refuse. A file that cannot reach zero says in one line what remains and why. The overflow moves rather than shrinks: module behavior into the header's `///`, cross-module rationale into the file's `@moreinfo` appendix, reached by `@xref`. Files the change never opened are a sweep of their own.

Three checks earn their place for a reason worth knowing. **Repo health** is the only place the creeping numbers are visible: flash and DRAM per target, binary size, the tick matrix, line counts, complexity warnings. Its diff belongs in the commit and its deltas in the commit message. It runs when the code changes rather than on every commit, because its timings drift with the host: on a docs-only diff it records a regression that nothing in the diff caused. **The no-backend build** catches a helper left unused outside its guard, fatal under GCC while clang stays silent. **ESP32 firmware fresh** compares the binary against every source in a tenth of a second and catches the edit that was never compiled; compile for real after an sdkconfig or toolchain change. The [provisioning path](moondeck/MoonDeck.md#improv_smoke_test) is the five files MoonDeck names.

Expand Down
Binary file added docs/assets/light/drivers/RtspDriver.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions docs/moonmodules/light/drivers.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,22 @@

Detail: [technical](moxygen/HlsDriver.md) · [the transport-stream muxer](moxygen/MpegTs.md)

<a id="rtsp"></a>

### RTSP 🖥️ · video out

<img src="../../assets/light/drivers/RtspDriver.png" width="300" alt="RTSP driver controls">

Streams the layer as **H.264 over RTSP**, which a player pulls rather than fetching segments. Point VLC or `ffplay` at the `url` the card shows. It reaches a viewer **much sooner than HLS**, which buffers whole segments before it plays one, so this is the remote view to reach for. [Preview](#preview) stays the one that keeps pace with the lights, sending raw pixels and no codec at all.

Runs on the **ESP32-P4** and on the desktop. One encoder, so **RTSP and [HLS](#hls) run one at a time**. See [the details below](#rtsp-details).

- `targetFps`: encode-rate ceiling (default 30, 1–60), which is also the keyframe interval.
- `scale`: video pixels per light (0 = auto). Each light is a solid block, never a blur.
- read-only: `url` to play. The card's status line names the connected viewer.

Detail: [technical](moxygen/RtspDriver.md) · [the RTP packetiser](moxygen/RtpH264.md) · [the session](moxygen/RtspSession.md)

<a id="shared-details"></a>

## Shared, details
Expand Down Expand Up @@ -303,6 +319,36 @@

**Where the segments live.** On desktop, the transient `/.hls/` directory, served at `/hls/` and excluded from config backups. Large grids trade framerate, the render loop being single-threaded: 512x512 streams smoothly, TV-native resolutions do not yet.

<a id="rtsp-details"></a>

## RTSP, details

**Playing the stream.** Any RTSP player opens the `url` the card shows. These two are what the driver is tested against:

```sh
ffplay -fflags nobuffer -flags low_delay rtsp://<device>:554/
vlc rtsp://<device>:554/
```

`-fflags nobuffer -flags low_delay` is what makes ffplay show the stream as it arrives rather than filling a buffer first, which is the whole point of reaching for RTSP. VLC buffers about a second by default, so `--network-caching=100` brings it closer.

**Watching LEDs on a monitor.** A grid is small in pixels and large in meaning, so scale it up with nearest-neighbor and each light stays a crisp square instead of a blurred blob:

```sh
ffplay -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 \
-vf "scale=768:768:flags=neighbor,format=yuv420p" rtsp://<device>:554/
```

`-probesize 32 -analyzeduration 0` skips the startup probing, so the picture appears at once. `format=yuv420p` silences ffplay's `No accelerated colorspace conversion` notice, which reports a missing SIMD path in the player's own window conversion and says nothing about the stream.

**The newest viewer is the viewer.** One session plays at a time, since each viewer costs another send on a device that is also driving lights. A new connection takes the session over rather than being refused. The reason is that a player which vanishes without `TEARDOWN` leaves a socket open and silent, and TCP reports a peer's absence only to a write it stops acknowledging, so waiting on that would strand the stream for minutes. The displaced viewer sees its connection close, which every player reports.

Check warning on line 344 in docs/moonmodules/light/drivers.md

View workflow job for this annotation

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [projectMM.SentenceLength] Sentence runs past 30 words; it is probably two thoughts joined by a comma. Raw Output: {"message":"[projectMM.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":344,"column":212},"end":{"line":344,"column":215}}},"severity":"INFO","code":{"value":"projectMM.SentenceLength"}}

**UDP carries the video.** The control conversation runs over TCP on port 554, and the frames go to the UDP port the viewer names in `SETUP`. A network that blocks that port pair leaves the stream silent while the session looks connected. A player asking for interleaved TCP instead is told so by code, since this server speaks UDP.

**The rate is what the device renders.** `targetFps` is a ceiling rather than a promise: a heavy effect that ticks at 8 fps is streamed at 8 fps, since a frame that was never rendered cannot be sent. A stream slower than expected is therefore a question about the render loop rather than the transport. Each module's own tick time in the UI says which effect is spending the time.

**The delay that remains is the codec's.** H.264 emits a frame once it has the whole frame, and a decoder holds one more, so tens of milliseconds stay whatever the transport does. What RTSP removes is HLS's segment buffering, which is the seconds.

<a id="preview-details"></a>

## Preview, details
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ projectMM ships **no migration code**: the persistence layer is robust by defaul

## Unreleased (`next-iteration`)

<!-- At the v5.0.0 tag this heading becomes `## v5.0.0`, and a fresh `## Unreleased` opens above it. The entries below are what that release asks of a user; the release notes summarise them and link here. -->

### System: `expertMode` became `mode`, with three levels

**Action: re-set a control, and only if you had expert mode on.**
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/hardware/control-surfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ What projectMM needs to know about the physical desks on the bench, so a control

**The headline, because it contradicts the obvious assumption:** neither desk speaks OSC. Both are
**Mackie Control** surfaces. OSC is the right protocol for the wider ecosystem (Resolume,
TouchDesigner, TouchOSC, DIY Arduino rigs) and is planned on that basis, but it does not reach these two. See [the OSC plan](../../work/present/Plan-20260829%20-%20OSC%20control%20ingest.md).
TouchDesigner, TouchOSC, DIY Arduino rigs) and is planned on that basis, but it does not reach these two. See [the OSC plan](../../work/past/plans/Plan-20260829%20-%20OSC%20control%20ingest%20(shipped).md).

## Behringer X-Touch (Universal)

Expand Down
16 changes: 8 additions & 8 deletions docs/reference/metrics/docgen.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Generated by [`moondeck/check/check_docgen.py`](../../../moondeck/check/check_do

Every place the generated documentation breaks the shape [the standards](../../contributing/documentation-standards.md#the-card) define. Current state only: the trend is this file's git history. The list only shrinks.

**0 error(s)** and **3131 warning(s)** across 217 page(s).
**0 error(s)** and **3090 warning(s)** across 215 page(s).

An error is in a file that generates a documentation page, a header or a catalog page, so the finding is a defect in what gets published and it fails the gate. A warning is in an implementation file, which publishes nothing: its comments are a note to the next reader, worth fixing without being worth stopping a commit for. Both are counted here, because a warning nobody sees is a warning nobody fixes.

Expand All @@ -14,8 +14,8 @@ The split is temporary. It stages the sweep rather than ranking the two kinds of

| Rule | Errors | Warnings |
|---|---:|---:|
| over-wide comment lines | 0 | 2225 |
| multi-line comment blocks | 0 | 604 |
| over-wide comment lines | 0 | 2192 |
| multi-line comment blocks | 0 | 596 |
| over-long sentences | 0 | 108 |
| over-wide doc lines | 0 | 102 |
| member deep dives | 0 | 92 |
Expand All @@ -27,7 +27,7 @@ The unit a sweep runs in: one summary page and the headers it owns, as the [hier
| Summary page | Errors | Warnings |
|---|---:|---:|
| `(tests, no card)` | 0 | 2203 |
| `platform/index.md` | 0 | 518 |
| `platform/index.md` | 0 | 477 |
| `core/system.md` | 0 | 410 |

## Where the work is
Expand Down Expand Up @@ -56,7 +56,7 @@ By rule, warnings: 1668 over-wide comment lines, 239 multi-line comment blocks,

### platform/index.md

**0 error(s)** and **518 warning(s)** across 25 file(s).
**0 error(s)** and **477 warning(s)** across 23 file(s).

| Findings | File | |
|---:|---|---|
Expand All @@ -67,12 +67,12 @@ By rule, warnings: 1668 over-wide comment lines, 239 multi-line comment blocks,
| 34 | `src/platform/esp32/moonlive_asm_xtensa.cpp` | warning |
| 30 | `src/platform/desktop/moonlive_asm_x86_64.cpp` | warning |
| 30 | `src/platform/esp32/platform_esp32_rmt.cpp` | warning |
| 24 | `src/platform/esp32/platform_esp32_ota.cpp` | warning |
| 23 | `src/platform/esp32/moonlive_asm_riscv.cpp` | warning |
| 21 | `src/platform/desktop/moonlive_asm_arm64.cpp` | warning |
| 1-19 each | *15 more warning files, 100 findings* | |
| 19 | `src/platform/esp32/platform_esp32_parlio.cpp` | warning |
| 1-10 each | *13 more warning files, 64 findings* | |

By rule, warnings: 363 over-wide comment lines, 155 multi-line comment blocks.
By rule, warnings: 330 over-wide comment lines, 147 multi-line comment blocks.

### core/system.md

Expand Down
Loading
Loading