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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .claude/workflows/write-behaviour-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ phase('Study + write')

const results = await parallel(MODULES.map(([cls, header, kind]) => () =>
agent(
`Write a behaviour-specific doctest unit test for the projectMM module **${cls}** (${kind}).
`Write a behaviour-specific doctest unit test for the MoonLight module **${cls}** (${kind}).

Repo: the current workspace root (the projectMM checkout you're running in) — all paths below are relative to it.
Repo: the current workspace root (the MoonLight checkout you're running in) — all paths below are relative to it.

## Study first (do NOT guess behaviour)
1. Read the module header: ${header} — understand what it ACTUALLY does: its controls, its render/modify logic, what it writes to the buffer or how it transforms coordinates. Behaviour is the spec.
Expand Down
2 changes: 1 addition & 1 deletion .github/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "projectMM CodeQL config"
name: "MoonLight CodeQL config"

# Code we did not write and will not change is not a finding we can act on. doctest.h is the
# vendored single-header test framework (test/doctest.h) and the only third-party source in the
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/prose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Prose

# Vale over the lines a PR ADDS or changes, with the rules in .vale/styles/projectMM/. Diff-scoped
# Vale over the lines a PR ADDS or changes, with the rules in .vale/styles/MoonLight/. Diff-scoped
# on purpose: the tree still holds pre-existing violations, and a contributor is answerable for
# what they wrote, not for inherited prose. An `error` (em-dash, British spelling, "e.g.") fails
# the check; warnings and suggestions land as inline annotations only.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ jobs:
run: |
set -euo pipefail
# Render the docs/ tree (Material for MkDocs) as the Pages ROOT
# (moonmodules.github.io/projectMM/) — the project's front door.
# (moonmodules.github.io/MoonLight/) — the project's front door.
# Config: mkdocs.yml; deps declared inline in the build script (uv
# provisions them). Build to a temp dir, then copy INTO pages/ so the
# installer staged above under pages/install/ survives (a plain
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,4 @@ __pycache__/
# listed media types one by one, to protect run files that used to live here; they no
# longer do, so the rule can say what it means.
/media/
.playwright-profile/
42 changes: 21 additions & 21 deletions .vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
# this is their mechanical half. Run: `vale docs/ CLAUDE.md README.md` or via check_prose.py.
StylesPath = .vale/styles
MinAlertLevel = suggestion
# Proper nouns the rules must not correct: see .vale/styles/config/vocabularies/projectMM.
Vocab = projectMM
# Proper nouns the rules must not correct: see .vale/styles/config/vocabularies/MoonLight.
Vocab = MoonLight

# Defaults first: in Vale a LATER [glob] overrides an earlier one, so the general rule leads and
# the specific pages below it win.
[*.md]
BasedOnStyles = projectMM
BasedOnStyles = MoonLight

# CODE CARRIES PROSE TOO: a `///` becomes a page, a `//` is read beside the line it explains, and
# documentation-standards.md governs both. Held to the same rules as a page, so that when
Expand All @@ -18,7 +18,7 @@ BasedOnStyles = projectMM
# header and reports ZERO FILES, which reads exactly like a clean run. CComments hands it the
# tree-sitter syntax tree and lints the comment nodes alone, so code is never read as prose.
[*.{c,h,hpp,cpp,inc}]
BasedOnStyles = projectMM
BasedOnStyles = MoonLight
View = CComments

# Upstream code, vendored rather than written here: not our prose to rule on.
Expand Down Expand Up @@ -50,26 +50,26 @@ BasedOnStyles =
# Add a page here when `vale <page>` reports nothing; the sweep plan in docs/work/present/ is the
# list. When every page is here, the two prose scripts go and this section becomes the default.
[docs/tutorials/installing-on-linux.md]
BasedOnStyles = projectMM
projectMM.SentenceLength = error
projectMM.Weasel = error
projectMM.NegatedHeading = error
projectMM.SelfReference = error
BasedOnStyles = MoonLight
MoonLight.SentenceLength = error
MoonLight.Weasel = error
MoonLight.NegatedHeading = error
MoonLight.SelfReference = error

[docs/contributing/coding-standards.md]
BasedOnStyles = projectMM
projectMM.SentenceLength = error
projectMM.Weasel = error
projectMM.NegatedHeading = error
projectMM.SelfReference = error
BasedOnStyles = MoonLight
MoonLight.SentenceLength = error
MoonLight.Weasel = error
MoonLight.NegatedHeading = error
MoonLight.SelfReference = error

# The rules page must QUOTE the things it bans (an em-dash, "analyse", "this page", "really"), so
# the four rules whose examples it carries stay off here. The rest are strict.
[docs/contributing/documentation-standards.md]
BasedOnStyles = projectMM
projectMM.EmDash = NO
projectMM.Spelling = NO
projectMM.SelfReference = NO
projectMM.Weasel = NO
projectMM.SentenceLength = error
projectMM.NegatedHeading = error
BasedOnStyles = MoonLight
MoonLight.EmDash = NO
MoonLight.Spelling = NO
MoonLight.SelfReference = NO
MoonLight.Weasel = NO
MoonLight.SentenceLength = error
MoonLight.NegatedHeading = error
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ A high-performance system driving large LED installations and DMX fixtures. One

3. **Architecture first.** The domain-neutral core owns the hard constructs, written once; the light domain stays simple on top. Platform-specific code lives only in the platform layer. When core enforces a rule on one path, extend core to the next. No hacks: fix it the standard way when spotted, or backlog the real fix by name. Default to subtraction: the first question on any change is what it can remove.

**Build the best solution, not the compatible one.** projectMM has no installed base to protect, so "it would break existing configs" is not an argument for a worse design. When a better shape replaces an older one, the old one goes: two mechanisms doing one job is the debt this project exists to avoid. The break is documented rather than carried, which costs a [MIGRATING](docs/reference/MIGRATING.md) entry and buys one way to do each thing. Weigh what a user loses, not what changes.
**Build the best solution, not the compatible one.** MoonLight has no installed base to protect, so "it would break existing configs" is not an argument for a worse design. When a better shape replaces an older one, the old one goes: two mechanisms doing one job is the debt this project exists to avoid. The break is documented rather than carried, which costs a [MIGRATING](docs/reference/MIGRATING.md) entry and buys one way to do each thing. Weigh what a user loses, not what changes.

4. **Guardrails everywhere.** Every behavior is pinned by tests whose descriptions read as functional documentation. Every commit is measured, so growth and regression are visible as they happen. Judgment is reviewed; everything else is checked per event below. The final guardrail is physical: verified means it ran on real hardware, with the product owner's eyes as the measurement.

Expand Down
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,9 @@ if(WIN32)
endif()

# Application
add_executable(projectMM src/main.cpp src/platform/desktop/main_desktop.cpp ${MM_WIN_RESOURCES})
# module_types.cpp is the shared type registry, compiled into the app and the scenario runner
# alike so one list serves both: src/module_types.cpp carries the reason.
add_executable(projectMM src/main.cpp src/module_types.cpp src/platform/desktop/main_desktop.cpp ${MM_WIN_RESOURCES})
target_link_libraries(projectMM PRIVATE mm_core mm_platform)
add_dependencies(projectMM ui_embed build_info_gen moonlive_catalog)

Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# projectMM
# MoonLight

Drive large LED installations and DMX fixtures. One source tree drives ESP32, Teensy, Raspberry Pi, macOS, Windows and Linux.

Expand All @@ -8,7 +8,7 @@

No hardware handy? The [desktop build](https://github.com/MoonModules/projectMM/releases/latest) runs the same UI and effect pipeline on macOS, Windows and Linux, driving fixtures over Art-Net, DDP or E1.31.

If you like projectMM, give it a star, fork it, or open an issue. It helps the project get noticed.
If you like MoonLight, give it a star, fork it, or open an issue. It helps the project get noticed.

## What you get

Expand Down Expand Up @@ -38,7 +38,7 @@

## The parts

projectMM is one system in nine named parts. Each has a page that owns its detail.
MoonLight is one system in nine named parts. Each has a page that owns its detail.

```mermaid
flowchart TB
Expand Down Expand Up @@ -164,7 +164,7 @@

**ESP32**: open the [web installer](https://moonmodules.org/projectMM/install/) in Chrome or Edge ([MoonInstaller](#mooninstaller)). It walks you through device, firmware, flashing and network setup.

**Desktop**: download your build from the [releases page](https://github.com/MoonModules/projectMM/releases), then open `http://localhost:8080/`. Step by step with screenshots: [Installing projectMM on a desktop](docs/how-to/installing-to-desktop.md).
**Desktop**: download your build from the [releases page](https://github.com/MoonModules/projectMM/releases), then open `http://localhost:8080/`. Step by step with screenshots: [Installing MoonLight on a desktop](docs/how-to/installing-to-desktop.md).

- **macOS arm64**: `.dmg`, drag to Applications. Ad-hoc signed, so right-click and Open the first time.
- **Windows x64**: `-setup.exe` installs for your user without an admin prompt. Unsigned, so SmartScreen asks once.
Expand Down Expand Up @@ -194,7 +194,7 @@

## How we work

projectMM is built by AI agents under tight human direction. Everything in this repository is authored by agents; the **product owner** writes none of it directly. What the product owner authors is the [process](CLAUDE.md), the [architecture](docs/explanation/architecture/index.md), and the [module specifications](docs/moonmodules/), then decides what to build, reviews every line, runs the hardware tests, and controls every commit and release. Agents write; the product owner thinks.
MoonLight is built by AI agents under tight human direction. Everything in this repository is authored by agents; the **product owner** writes none of it directly. What the product owner authors is the [process](CLAUDE.md), the [architecture](docs/explanation/architecture/index.md), and the [module specifications](docs/moonmodules/), then decides what to build, reviews every line, runs the hardware tests, and controls every commit and release. Agents write; the product owner thinks.

Check warning on line 197 in README.md

View workflow job for this annotation

GitHub Actions / vale

[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":"README.md","range":{"start":{"line":197,"column":165},"end":{"line":197,"column":169}}},"severity":"INFO","code":{"value":"MoonLight.SentenceLength"}}

The roles, the principles and the full process: [CLAUDE.md](CLAUDE.md).

Expand All @@ -209,28 +209,28 @@
| **StarLight** | Standalone LED firmware | [ewowi/StarLight](https://github.com/ewowi/StarLight) |
| **MoonLight** | Ground-up build: 60+ effects, memory-optimized mapping, 11 driver types | [ewowi/MoonLight](https://github.com/ewowi/MoonLight) |

We built and maintained these, so projectMM rests on our own hands-on experience. Their lessons are distilled in [`docs/work/past/`](docs/work/past/index.md). We carry the ideas forward and write our own code, crediting by name whoever inspired a feature.
We built and maintained these, so MoonLight rests on our own hands-on experience. Their lessons are distilled in [`docs/work/past/`](docs/work/past/index.md). We carry the ideas forward and write our own code, crediting by name whoever inspired a feature.

## Credits

People whose work directly shaped parts of projectMM. We study their thinking with respect and write our own code against our architecture:
People whose work directly shaped parts of MoonLight. We study their thinking with respect and write our own code against our architecture:

- **[WLED](https://github.com/wled/WLED) and [WLED-MM](https://github.com/MoonModules/WLED)**: projectMM is born out of WLED and takes the usermod idea further, where everything is a module. A projectMM device also acts as a WLED device and talks to WLED devices.
- **[WLED](https://github.com/wled/WLED) and [WLED-MM](https://github.com/MoonModules/WLED)**: MoonLight is born out of WLED and takes the usermod idea further, where everything is a module. A MoonLight device also acts as a WLED device and talks to WLED devices.
- **Frank ([softhack007](https://github.com/softhack007))**: main author of the WLED-MM audio-reactive usermod. The ideas behind [AudioService](docs/moonmodules/core/moxygen/AudioService.md), including the adaptive noise gate analyzed with his permission, descend from years of collaboration.
- **[troyhacks](https://github.com/troyhacks/WLED)**: reworked the WLED-MM audio DSP onto Espressif's [esp-dsp](https://github.com/espressif/esp-dsp) FFT, the same choice AudioService makes.
- **[Stefan Petrick](https://github.com/StefanPetrick)**: the generative-field vocabulary from [Animartrix](https://github.com/StefanPetrick/animartrix), [FunkyNoise](https://github.com/StefanPetrick/FunkyNoise) and [ColorTrails](https://github.com/StefanPetrick/ColorTrails). [Aurora](docs/moonmodules/light/effects.md#aurora), [PolarNoise](docs/moonmodules/light/effects.md#polarnoise), [Tunnel](docs/moonmodules/light/effects.md#tunnel) and [Trails](docs/moonmodules/light/effects.md#trails) sit in that tradition, written on the published algorithms underneath.
- **[hpwit](https://github.com/hpwit) (Yves Bazin)**: the clockless I2S, RMT and Parlio driver techniques, and the [ESPLiveScript](https://github.com/hpwit/ESPLiveScript) engine behind MoonLive.
- **Christophe Gagnier ([@Moustachauve](https://github.com/Moustachauve))**: author of the native [WLED-Android](https://github.com/Moustachauve/WLED-Android) and [WLED-iOS](https://github.com/Moustachauve/WLED-iOS) apps, whose source let projectMM devices appear in them.
- **Christophe Gagnier ([@Moustachauve](https://github.com/Moustachauve))**: author of the native [WLED-Android](https://github.com/Moustachauve/WLED-Android) and [WLED-iOS](https://github.com/Moustachauve/WLED-iOS) apps, whose source let MoonLight devices appear in them.
- **The [Improv Wi-Fi](https://github.com/improv-wifi) project**: the open serial provisioning standard the web installer uses.
- **[FastLED](https://github.com/FastLED/FastLED)**: the canonical LED-effects library whose names and models projectMM carries forward (`scale8`, `sin8`, the gradient-palette model, the `beatsin8` family) so a contributor recognizes them on sight. The implementations are our own, integer-only and hot-path-tuned.
- **[FastLED](https://github.com/FastLED/FastLED)**: the canonical LED-effects library whose names and models MoonLight carries forward (`scale8`, `sin8`, the gradient-palette model, the `beatsin8` family) so a contributor recognizes them on sight. The implementations are our own, integer-only and hot-path-tuned.
- **[FPP](https://github.com/FalconChristmas/fpp) (Falcon Player)**: the show player that prompted [PanelCardDriver](docs/moonmodules/light/drivers.md#panelcard): if a Linux host can feed a wall of HUB75 panels, so can the board already rendering them.
- **[Tasmota](https://github.com/arendst/Tasmota) and Mathieu Carbou's [MycilaSafeBoot](https://github.com/mathieucarbou/MycilaSafeBoot)**: the safeboot pattern behind [MoonBase](docs/explanation/architecture/moonbase.md), our from-scratch minimal take on it.
- **Damian Schneider ([dedehai](https://github.com/DedeHai))**: author of the WLED Particle System, whose shape our [particle kernel](docs/moonmodules/light/power-functions.md#particles) follows in fixed point.
- **wladi ([myhome-control](https://shop.myhome-control.de))**: designer of the [MHC-WLED ESP32-P4 shield](https://shop.myhome-control.de/en/ABC-WLED-ESP32-P4-shield/HW10027), and the source of the pinout details that got its line-in audio working.

## Contributing

projectMM is a community project, shaped by the people who use it:
MoonLight is a community project, shaped by the people who use it:

- **Ideas and requests**: an effect, a layout, a driver, a fixture you want supported? [Open an issue](https://github.com/MoonModules/projectMM/issues).
- **Help build it**: pick something from the [issues](https://github.com/MoonModules/projectMM/issues), or propose a module. The process is in [CLAUDE.md](CLAUDE.md).
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# projectMM in a container: the desktop firmware, which is the whole system without an ESP32.
# MoonLight in a container: the desktop firmware, which is the whole system without an ESP32.
#
# docker compose up -d start it, in the background
# docker compose logs -f watch it
Expand All @@ -24,13 +24,13 @@ services:

ports:
# CHANGE ME: the port YOU open in the browser is the left one. 8081 rather than 8080 so a
# container never fights a projectMM already installed on the machine. The right side is the
# container never fights a MoonLight already installed on the machine. The right side is the
# port inside the container and does not change: containers do not share a port space, so
# several instances can all listen on 8080 internally with different left-hand numbers.
- "8081:8080"

volumes:
# Config, presets and scripts. Everything the app writes lands in /data/projectMM, so this one
# Config, presets and scripts. Everything the app writes lands in /data/MoonLight, so this one
# mount is the whole of its state: remove it and a restart comes up factory-fresh.
- projectmm-data:/data

Expand Down
Binary file added docs/assets/light/effects/PulseEffect.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/light/effects/PulseEffect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/uiscenarios/01-install-desktop.webm
Binary file not shown.
Binary file added docs/assets/uiscenarios/01-install-esp32.webm
Binary file not shown.
Binary file not shown.
Binary file added docs/assets/uiscenarios/02-first-look-esp32.webm
Binary file not shown.
Binary file added docs/assets/uiscenarios/03-second-look.webm
Binary file not shown.
Binary file added docs/assets/uiscenarios/04-scenario-testing.webm
Binary file not shown.
Binary file removed docs/assets/uiscenarios/install-firmware.webm
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/contributing/documentation-standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Every page serves one of four reader needs, and only one. This is [Diátaxis](ht
| **Learning** | **Tutorial**: a lesson to follow. `gettingstarted.md`, `tutorials/`. | **Explanation**: why it is shaped this way. `explanation/`. |
| **Working** | **How-to**: one task you already have. `how-to/`. | **Reference**: facts, fast. `reference/`, the generated technical pages, the catalog rows. |

**The folder under `docs/` is the type.** A page's path says which cell it sits in. So `how-to/building.md` is a how-to by location, and a reader never has to be told. The nav labels stay reader-facing ("Understanding projectMM" over "Explanation"), because the type is a writer's tool.
**The folder under `docs/` is the type.** A page's path says which cell it sits in. So `how-to/building.md` is a how-to by location, and a reader never has to be told. The nav labels stay reader-facing ("Understanding MoonLight" over "Explanation"), because the type is a writer's tool.

The test for any page is the cell it sits in. A tutorial that stops to explain, or a reference that starts to teach, is two pages: move the other half to where it belongs.

Expand Down
Loading
Loading