Development
This page is for developers who want to modify the AutoColor scripts, run the test suite, or build this documentation site. It assumes familiarity with Lua and with REAPER scripting (ReaScript). It describes how the repository is organised, how to run the tests and build the docs, how the generated parts of the docs are produced, and how the site is published.
Repository layout
The repository contains the shipped scripts, the ReaPack manifest, the tests, the documentation site and the icon sources:
Reaper/ mirrors REAPER's resource path; this is what gets installed Scripts/MXM_AutoColor/ MXM_AutoColor_*.lua entry points, added to REAPER's Action List lib/ the shared library; lib/gui/ is the configuration window Data/toolbar_icons/ the two toolbar icons, with 150/ and 200/ hi-DPI copiesColor/ the ReaPack manifest, and nothing elsedev/ author-only probes and helpers, deliberately not shippedtests/ the test suite, which runs outside REAPERicon/ icon.svg and icon-gui.svg, the masters every icon output is rendered fromdocs/ this site (Astro + Starlight)docs/DECISIONS.md why the script is built this way, and what was tried firstdocs/RESEARCH.md verified external facts: SWS, ReaImGui, REAPER preferencesindex.xml the ReaPack index, generated by reapack-index; never edit by handScripts and library
The scripts need no build step. REAPER runs the .lua files from the directory where they are installed.
Each file named MXM_AutoColor_*.lua is an entry point: a script that appears in REAPER’s Action List. The entry points are thin. The logic lives in modules under lib/, and each module’s header comment explains its own design.
All colouring follows one pipeline, defined in lib/apply.lua. The pipeline has two steps:
plan()receives the names and current colours and icons of tracks, items, regions and markers, matches the names against the rules, and returns a list of changes. It does not write anything to the project.commit()writes a list of changes into the project. It is the only function that writes.
The preview in the configuration window calls plan() without calling commit(). The preview therefore runs the same code that applying the rules runs, which is why it shows exactly what Apply would change.
Within lib/, only the modules under lib/gui/ use ReaImGui. The configuration window is the only script that needs ReaImGui.
Why the manifest is in Color/
Reaper/ has the same directory structure as REAPER’s resource path. A manual installation is therefore a single copy that merges Reaper/ into the resource path, and the ReaPack package installs the same tree.
The ReaPack manifest is Color/MXM_AutoColor.lua. It is kept outside Reaper/ so that it is never installed into REAPER. Its @provides lines list the shipped files by their path from the repository root, such as /Reaper/Scripts/MXM_AutoColor/lib/*.lua. The file .reapack-index.conf excludes .github, dev, docs, icon and tests from the package.
The Color/ directory cannot be renamed. ReaPack identifies a package by its index name, its category and its package name. The category is the name of the directory that contains the manifest, so Color/ is the category. Renaming the directory would change the package identity and orphan every existing installation.
The category does not appear in the installed path. Every @provides line retargets its file with a ../ prefix, for example > ../MXM_AutoColor/lib/. ReaPack resolves that prefix but does not let it go above the index’s own directory. Users install from the merged index named MXM Scripts, so the package installs to Scripts/MXM Scripts/MXM_AutoColor/. The installed tree below that directory matches Reaper/Scripts/MXM_AutoColor/.
Tests
The test suite runs outside REAPER, against simulated versions of the REAPER and ReaImGui APIs. One part of it, the unit tests, can also run inside REAPER.
Running the full suite
The suite needs a standalone Lua interpreter (version 5.4 or newer) and python3. On macOS, install Lua once with Homebrew:
brew install luaThen run the suite from the repository root with either command:
make test./tests/run.shWhen every test passes, the last line of the output is ALL GREEN. When any test fails, the last line is FAILURES -- see above, and the output of the failing suite is printed above it. The runner exits with status 0 only when every suite passes, so it can be used in CI or in a pre-commit hook.
The suite does not touch REAPER, a REAPER project, or your config.json. Every test writes its scratch files under tests/.tmp/.
What the suite covers
Two mock modules stand in for the real APIs:
tests/mockreaper.luasimulates the parts of the REAPER API that the scripts use. It reproduces REAPER’s awkward behaviour on purpose, for example that the master track has no name and that media items have no name of their own (only their takes have names).tests/mockimgui.luais a stub ReaImGui that accepts every call and draws nothing. It lets the real drawing code run, which proves that every drawing path executes without errors. It cannot show whether the window looks right.
tests/run.sh runs these suites in order:
| Suite | What it tests |
|---|---|
unit (MXM_AutoColor_RunTests.lua) | The regex engine, the matcher, colours, the configuration file, and the apply pipeline |
integration.lua | The real action scripts, end to end, against the mock REAPER |
autoloop.lua | The automatic apply loop that runs while the auto-toggle is on |
startup.lua | The autostart entry that AutoColor adds to Scripts/__startup.lua |
gui.lua | The configuration window’s logic, such as saving, undo and the preview |
render.lua | The configuration window’s drawing code, against the mock REAPER and the stub ReaImGui |
| differential regex fuzz | The regex engine compared with Python’s re |
AutoColor uses its own regular-expression engine, written in pure Lua (lib/regex.lua). The differential fuzz test checks that engine against Python’s re module. tests/fuzz_gen.py generates random patterns and subject strings, and records the result Python’s re gives for each one. tests/fuzz_run.lua then runs the same patterns through lib/regex.lua and reports every result that differs. The generated patterns use only ASCII and a subset of the regex syntax on which both engines are meant to agree exactly. The runner repeats the fuzz test with three fixed seeds (12345, 777 and 2024), so every run tests the same patterns.
tests/README.md describes each suite and both mocks in more detail.
Running the unit tests inside REAPER
The unit tests can also run inside REAPER. Run the action MXM_AutoColor_RunTests.lua from REAPER’s Action List. It prints a summary to the ReaScript console. It does not change the open project and does not write config.json.
Continuous integration
.github/workflows/tests.yml runs ./tests/run.sh on every push to any branch and on every pull request. It installs Lua 5.4 because REAPER embeds Lua 5.4.
These docs
The documentation site is built with Astro and its documentation theme Starlight. The site’s source is in docs/. Building it requires Node.js and npm.
Run these commands from the repository root:
make docs # build the site and serve it at http://localhost:4321/Reaper-AutoColor/make docs-dev # run a live-reload development server, for writingmake docs-build # build the static site into docs/dist/Running make with no target lists every available target. make docs, make docs-dev and make docs-build run npm install in docs/ if the dependencies are not installed yet. They then run the matching npm script in docs/. For example, cd docs && npm install && npm run dev is equivalent to make docs-dev.
Each page is a Markdown file under docs/src/content/docs/. The sidebar is defined by the sidebar array in docs/astro.config.mjs. A new page must be added in both places: as a file, and as an entry in the sidebar array.
The icon
The icon is drawn by hand in two SVG master files, and every other icon file is rendered from them:
icon/icon.svgis the main AutoColor icon.icon/icon-gui.svgis the same icon with a gear in the centre. It is used only for the toolbar button that opens the configuration window.
To re-render every icon output after editing a master, run:
make icon| Output | Rendered from | Purpose |
|---|---|---|
Reaper/Data/toolbar_icons/mxm_toolbar_autocolor.png, plus copies in 150/ and 200/ | icon.svg | The toolbar button for the auto-toggle. It ships with the scripts. |
Reaper/Data/toolbar_icons/mxm_toolbar_autocolor_gui.png, plus copies in 150/ and 200/ | icon-gui.svg | The toolbar button for the configuration window. It ships with the scripts. |
docs/public/favicon-16.png, favicon-32.png, favicon-48.png, favicon.svg | icon.svg | The site’s browser-tab icon |
docs/public/toolbar-autocolor.svg, toolbar-autocolor-gui.svg | icon.svg, icon-gui.svg | The toolbar icons shown on the Installation page |
icon/autocolor-128.png | icon.svg | The image in the repository README |
The masters are kept outside Reaper/ because they are source files that REAPER does not install. The toolbar PNGs are inside Reaper/ because REAPER does install them.
A REAPER toolbar icon is a 90×30 PNG that holds three 30×30 cells side by side. The cells show the button’s normal state, its hover state, and its active state. REAPER finds the hi-DPI versions by looking for a file with the same name in the 150/ and 200/ subdirectories. docs/scripts/icon.mjs contains the render code and documents why the icons use their margin and their state colours. Both were chosen by measuring REAPER’s own toolbar icons.
make icon is not part of the docs build. The rendered files are committed to the repository, so the icons only need re-rendering when a master changes.
Diagrams
The colouring diagrams under docs/src/assets/usage/diagrams/ are generated, not drawn. Do not edit these SVG files by hand.
docs/scripts/diagrams.py holds one scenario per diagram. A scenario lists the tracks, the rules and the options. The script computes every colour in the diagram with a Python port of the plan() step from lib/apply.lua (see Scripts and library).
make docs-diagrams # redraw every diagram, after editing a scenariomake docs-diagrams-verify # check the Python port against the real apply.luamake docs-diagrams is not part of the docs build. Run it after editing a scenario.
Because the diagrams are computed by a port, the port can drift away from the real Lua code. make docs-diagrams-verify detects that drift. It runs docs/scripts/diagrams_verify.lua, which feeds the same scenarios to the real apply.plan() and prints the colours it chose. It then compares those colours with the port’s colours and reports every scenario that differs. The check needs a standalone lua. Without one, it prints a message saying that the diagrams were not checked, and exits successfully.
Screenshots
Every screenshot is taken by hand. The configuration window is a ReaImGui script running inside REAPER, so there is no way to capture it automatically in CI.
Screenshots are stored under docs/src/assets/<section>/, for example docs/src/assets/usage/. Pages reference them by relative path. To replace a screenshot, overwrite the image file; no Markdown edit is needed.
If a page references an image file that does not exist, the build fails with [ImageNotFound] Could not find requested image. There is no placeholder image. When you add a figure to a page, add the image file in the same change.
Publishing
.github/workflows/deploy-docs.yml builds docs/ and deploys the result to GitHub Pages. The workflow runs on every push to main that changes a file under docs/ or the workflow file itself. It can also be started manually from GitHub.
GitHub Pages requires a paid plan for private repositories. The workflow therefore skips itself while the repository is private, and runs normally once the repository is public.
The published URL is https://michal-bartak.github.io/Reaper-AutoColor/. The site and base settings in docs/astro.config.mjs encode that URL. If the repository is renamed, update both settings.