Central registry of available CrossPad applications. Auto-discovered from GitHub repos with the crosspad-app topic, plus external repos listed in external-apps.json.
Want to publish your app? See How It Works for setup instructions.
- Arrange v0.9.0 — the status line sits in the status bar, centred where the CrossPad logo was (gui 1.17 statusbar_show_title), and the row it took goes to the tools at the foot: as tall as the screen leaves them, in the larger font, spread across the width; MOVE reads its axis as two arrows; requires gui 1.17
- Mixer v0.8.1 (0.7.2 merged in) — render() neither pans nor sends a channel whose block is silent (peak 0) -- the buses come out bit for bit the same, and every quiet channel saves two passes per send; a block of only NaN and zeros no longer reaches the buses (renderTap() still sums it); host tests in tests/, the scalar and the esp-dsp path
- Sampler v0.8.4 — a hold-mode release cuts the voice before the MIDI echo goes out (a host that reads USB MIDI slowly no longer holds the cut back); the waveform loader is marked running before its task is created, so a waveform no longer stays LOADING; a setting being turned in the pad editor stays turned on the next pad; requires core 1.45.0, the first core on main with PitchedInstrument::voiceCap() (0.8.3's 1.43.0 was the firmware line's release/core-1.43.0)
- Sampler v0.8.3 — the pitched editor's Voices goes up to the board's voice cap (PitchedInstrument::voiceCap(), which every setParams now meets); requires core 1.43.0
- Sampler v0.8.2 — a kit swap with no pad sounding starts on the first pad at once instead of 150 ms later (the wait stays while a pad sounds)
- Sampler v0.8.1 — + NEW finds a free kit name with stat(), and a name the card cannot answer for counts as taken ("card read failed"); no left (smaller firmware image)
| App | Version | Description | Platforms | Requires | Repo |
|---|---|---|---|---|---|
| App Store | 0.1.0 | Browse, install, and manage CrossPad apps from the registry | pc | core >=0.3.0, gui >=0.2.0 | CrossPad/crosspad-appstore |
| Arrange | 0.9.0 | Four audio tracks of bounced clips on a timeline | esp-idf, pc | core >=1.34.0, gui >=1.17.0 | CrossPad/crosspad-arrange |
| DAW Control | 0.4.1 | DAW controller surface: pads to the DAW, LED/text feedback from it (FL Studio, Ableton, REAPER); launches the DAW through the host hub | esp-idf, pc | core >=1.23.0, gui >=1.3.0 | CrossPad/crosspad-dawcontrol |
| Instructions | 0.2.0 | Markdown-based instructions and help viewer | esp-idf, arduino, pc | core >=0.3.0, gui >=0.2.0 | CrossPad/crosspad-instructions |
| Mixer | 0.8.1 | Audio mixer/router — dynamic IAudioNode channels, multi-output routing | pc, esp-idf | core >=1.44.0, gui >=1.14.0 | CrossPad/crosspad-mixer |
| Pad Mixer | 0.2.1 | Sixteen faders, one per pad | esp-idf, pc | core >=1.21.0, gui >=1.12.0 | CrossPad/crosspad-pad-mixer |
| Piano | 0.1.0 | Synth piano with parameter sliders, presets, octave control | pc | core >=0.3.0, gui >=0.2.0 | CrossPad/crosspad-piano |
| Recorder | 0.4.2 | Record a sample from the mics, the line-in or the pads, and trim it to a loop | esp-idf, pc | core >=1.28.0, gui >=1.14.0 | CrossPad/crosspad-recorder |
| Sampler | 0.8.4 | Sample player with 16 pads, waveform editing, kit management | esp-idf, arduino | core >=1.45.0, gui >=1.16.0 | CrossPad/crosspad-sampler |
| Sequencer | 0.3.2 | Record, loop and erase scenes on the pads | esp-idf, pc | core >=1.23.0, gui >=1.13.0 | CrossPad/crosspad-pattern-seq |
| Serial Monitor | 0.1.0 | UART serial monitor with baud rate selection, auto-scroll, clear | pc | core >=0.3.0, gui >=0.2.0 | CrossPad/crosspad-serial-monitor |
| Slicer | 0.3.0 | Chop a loop into slices -- by its hits, into equal parts, or live on the pads -- and save it as a kit | esp-idf, pc | core >=1.31.0, gui >=1.14.0 | CrossPad/crosspad-slicer |
| Song | 0.2.0 | Arrange scenes on a timeline | esp-idf, pc | core >=1.21.0, gui >=1.12.0 | CrossPad/crosspad-song |
| Synthesizer | 0.1.0 | Polyphonic synth with 3 oscillators, ADSR, filter, effects | arduino | core >=0.3.0, gui >=0.2.0 | CrossPad/crosspad-synthesizer |
14 official app(s)
No community apps yet — add yours!
Open a terminal (Windows: PowerShell) and paste the line for your system. It installs everything the CrossPad needs, asks for a GitHub sign-in (the firmware repository is private until the OS opens), and opens CP Tools. It takes 15–30 minutes the first time; run it again any time — it only installs or repairs what is missing.
Windows
powershell -ExecutionPolicy Bypass -c "irm https://raw.githubusercontent.com/CrossPad/crosspad-apps/main/install/install.ps1 | iex"macOS / Linux
curl -fsSL https://raw.githubusercontent.com/CrossPad/crosspad-apps/main/install/install.sh | bashAfterwards: the CP Tools shortcut on the Windows desktop, or
~/CrossPad/cptools on macOS and Linux.
Step by step, with screenshots: install/README.md.
The CrossPad App Manager is one shared tool for every platform, with a CLI and an interactive TUI. The TUI is built for people who have never used git: it names tasks, not git operations.
The first line always says what to do next — an update waiting, an update that stopped halfway, a board running firmware for another board revision, a missing tool. Under it, what each waiting update brings (the apps' own commit messages).
| Key | Screen | What it does |
|---|---|---|
1 |
Update my CrossPad | download → firmware components → build → flash → check, one log; q or Ctrl+C stops a step, r retries from it. When the project is exactly a published release, the release's image is downloaded instead of compiling |
2 |
Add or remove apps | type to filter; Enter on an app picks what it follows: the latest release, development, or one version. A broken app folder is repaired from here |
3 |
Something's wrong | every check with its fix: board, firmware, tools, USB, internet, disk, project folder; go back to the versions from before; switch the board to its previous firmware slot; s saves a report for support |
4 |
Developer tools | workspace, device, registry, feature flags, profiles, board revision, raw build & flash, new app, submit an app to the catalog, settings |
/ |
Find an action | every action by name |
? |
Help | the keys of the screen you are on, and what the marks mean |
Mouse: the wheel scrolls, clicking a [key] label presses it
(CROSSPAD_NO_MOUSE=1 turns that off). NO_COLOR=1 drops colour;
CROSSPAD_PLAIN=1 (or tui --plain) prints plain text for screen readers.
| Platform | Status | App install dir | Build system |
|---|---|---|---|
| ESP-IDF | Full support: update, build, flash, check, recover | components/ |
idf.py |
| Arduino / PlatformIO | Apps, build, USB upload | lib/ |
pio |
| PC (simulator) | Apps and build; "Update" rebuilds the simulator | src/apps/ |
CMake |
The installer above sets them up. By hand: Git, Python 3.10+, and for
ESP-IDF, ESP-IDF 5.5. The GitHub CLI (gh, signed in) is needed only to
clone the private platform repository and to publish your own apps —
reading the catalog and updating public apps needs no account.
idf.py app-list # List compatible apps
idf.py app-install --app sampler # Install app as git submodule
idf.py app-install --app sampler --ref v1.0 # Install specific version/branch
idf.py app-remove --app sampler # Remove app submodule
idf.py app-update --all [--force] [--dry-run] # Update installed apps
idf.py app-track --app sampler --mode release|development|version|mine
idf.py app-manage # Launch the TUI
python3 tools/app_manager.py doctor # every check, with its fix (exit 1 if something is wrong)
python3 tools/app_manager.py support # zip of logs and findings for #support
python3 tools/app_manager.py status --json # also: list --json, doctor --json, device --jsonInstall the VsCode Task Buttons extension. Two buttons appear in the status bar:
| Button | Action |
|---|---|
$(package) CP Tools |
Opens the full interactive TUI |
$(zap) OTA |
One-click OTA flash via USB CDC |
Configuration is in .vscode/settings.json:
{
"VsCodeTaskButtons.tasks": [
{
"label": "$(package) CP Tools",
"task": "CrossPad: CP Tools"
},
{
"label": "$(zap) OTA",
"task": "CrossPad: OTA Flash"
}
]
}idf.py fullclean && idf.py build is required after adding or removing apps. CMake's file(GLOB) runs at configure time only — plain idf.py build won't discover new app directories.
python3 scripts/app_manager.py list # List compatible apps
python3 scripts/app_manager.py install sampler # Install
python3 scripts/app_manager.py remove sampler # Remove
python3 scripts/app_manager.py update --all # Update all
python3 scripts/app_manager.py sync # Sync manifest
python3 scripts/app_manager.py # Launch TUI (no args)Launch with python3 scripts/app_manager.py (no arguments) or via the VSCode toolbar button.
The same screens as above; building uses pio run, flashing pio run --target upload.
Same setup as ESP-IDF — install VsCode Task Buttons, then configure in .vscode/settings.json:
{
"VsCodeTaskButtons.tasks": [
{
"label": "$(package) CP Tools",
"task": "CrossPad: App Manager"
}
]
}pio run --target clean && pio runEasiest from the TUI — [N] New app on the dashboard. It is a form: fill the
id, name and description, cycle Publish with space between local only,
private GitHub repo and public GitHub repo, and the panel below previews
exactly what will be created — the directory, the two sources you are meant to
rewrite, the REGISTER_APP_PL line, and the repo slug if publishing. Creation
shows each step as it happens and ends on the build command, with [b] to run
it right there.
The same thing from the shell:
python3 <wrapper> new fishtank --name "Fish Tank" --privateGenerates a complete, working app from template/ and installs it
into the project: a pad handler, LVGL buttons and a slider, an animation timer,
and REGISTER_APP_PL registration, so it shows up in the launcher after one
clean build. Then rewrite the two source files — that is the point of it.
| Flag | Effect |
|---|---|
| (none) | Stays local: a plain directory in this project, tracked as local |
--private |
Creates a private GitHub repo under your account, pushes, installs it back as a submodule |
--public |
Same, public |
--owner |
Publish under an org instead of your account |
--no-install |
Generate only, leave the project alone |
Publishing needs gh auth login. A private repo is a fine place to start — the
registry only lists apps you deliberately add to external-apps.json.
The template deliberately shows the one rule that is easy to get wrong: pad callbacks arrive on the pad thread, LVGL is not thread-safe, so the pad handler only records events and the LVGL timer draws them.
The manager treats installed apps as owned, not as registry property, and doubles as the project's compile-time config tool.
| File | Written by | Checked in | Holds |
|---|---|---|---|
apps.json |
manager | yes | State: what is on disk |
crosspad.config.json |
you / TUI | yes | Intent: track policy per app, feature flags |
crosspad.local.json |
you / TUI | no | Personal overrides (own branches, dev flags) |
config/profiles/*.json |
you | yes | Named recipes: flags + app set |
.crosspad/ |
manager | no | Backups, generated build flags |
python3 <wrapper> track sampler local # hands off, this one is mine
python3 <wrapper> track mixer branch --ref my-work # follow my branch, ff-only
python3 <wrapper> track piano pinned # freeze at the current commit
python3 <wrapper> status # policy vs actual git state| mode (screen word) | update does |
|---|---|
registry (release, default) |
follows the newest v* release tag |
branch (development) |
follows the named branch; never switches branch |
pinned (version) |
nothing; reports when newer exists |
local (mine) |
nothing at all; the worktree is yours |
The CLI takes either word. Settings → Early features switches every app on the latest release to development (and back) in your personal config.
The declared mode is intent. Observed git state overrides it: an app that is
dirty, ahead of origin, on an unexpected branch, or pointing at a fork is
blocked whatever its mode. update --all updates the clean apps and prints a
skip table for the rest; --force proceeds but snapshots first.
python3 <wrapper> backup sampler # snapshot local work
python3 <wrapper> restore sampler --list # what is available
python3 <wrapper> restore sampler # replay the newestA backup lands in .crosspad/backups/<app>/<ts>/ and holds tracked changes as a
patch, untracked files as a tarball, commits that exist nowhere on origin as a
git bundle, and every stash as its own patch. Restore replays patches and files
in place and fetches the bundle into refs/crosspad-backup/<ts>/* — rebuilding
history stays your call. remove always backs up first when local work exists.
Flags come from crosspad-core/include/crosspad/config/features.schema.json,
the machine-readable twin of the Marlin-style Configuration.h.
python3 <wrapper> config # show flags, * = overridden
python3 <wrapper> config FEAT_PAD_EDITOR off # set one
python3 <wrapper> config --gen # regenerate build flagsChosen values live in crosspad.config.json, never in the submodule header, so
configuring a build does not dirty crosspad-core for everyone else. Only
deviations from the header default are emitted, into
.crosspad/build_flags.cmake (ESP-IDF, PC — include()d by the top-level
CMakeLists.txt) and .crosspad/build_flags.ini (PlatformIO, applied by a
pre: extra script). An untouched project builds exactly as the headers say.
The TUI screen [C] Configure renders the same catalog as a menuconfig tree
with help text and requires validation.
python3 <wrapper> device # exits 2 when the device differsEvery build bakes in the submodules it was made of — component, registry id,
commit, manifest pin, dirty flag — and reports them in the same APPVER: format
on all three platforms:
| Platform | How it answers |
|---|---|
| ESP-IDF | APP_VERSIONS over CDC |
| Arduino | APP_VERSIONS on the serial console |
| PC | ./bin/CrossPad --versions |
The manager diffs that against the checkout, so "is this actually running my
code?" stops being guesswork. Same view on the TUI's [D] Device screen. A
board in USB audio mode exposes no CDC — switch it back with the SysEx
F0 7D 1B 00 F7 on its own MIDI port. An app kept in-tree rather than as a
submodule reports ref=in-tree, because its commit is the parent repo's.
python3 <wrapper> profile list
python3 <wrapper> profile show lite # dry-run diff against the project
python3 <wrapper> profile apply liteA profile is a recipe — feature flags plus the app set with track modes. Apply
shows the plan first; apps the profile omits are kept unless you pass
--remove-extra, and apps that are protected or carry local work are never
removed.
python3 scripts/app_manager.py # TUI
python3 scripts/app_manager.py list # and every other command aboveApps go to src/apps/. "Update my CrossPad" updates the apps and rebuilds
the simulator; Developer tools → OTA Flash runs it.
- Each app repo has the GitHub topic
crosspad-appand contains acrosspad-app.jsonwith metadata - CI runs
build_registry.pyevery 6 hours which:- Discovers all repos with the
crosspad-apptopic in the CrossPad org - Merges in any external repos from
external-apps.json - Generates
registry.json+ updates this README - Sends Discord notifications for new apps, platform additions, and version updates
- Discovers all repos with the
- The result is
registry.json— fetched by the app manager (cached locally for 1 hour) - Apps are installed as git submodules into the platform's library directory
- The build system auto-discovers installed components at configure time
crosspad-apps/ ← This repo (registry + shared core)
registry.json ← Auto-generated, consumed by app manager
crosspad_app_manager.py ← Shared core (downloaded by platform wrappers)
build_registry.py ← CI: discovers repos, builds registry
diff_registry.py ← CI: detects changes for Discord notifications
platform-idf/ ← ESP-IDF platform repo
idf_ext.py ← Registers idf.py app-* commands
tools/app_manager.py ← Thin wrapper, auto-downloads shared core
apps.json ← Local manifest of installed apps
ESP32-S3/ ← Arduino platform repo
scripts/app_manager.py ← Thin wrapper, auto-downloads shared core
apps.json ← Local manifest of installed apps
-
Add
crosspad-app.jsonto your app repository:{ "name": "My App", "id": "my-app", "version": "0.1.0", "description": "What it does", "category": "music", "icon": "my-icon.png", "component_path": "components/crosspad-my-app", "platforms": ["esp-idf", "arduino"], "requires": { "crosspad-core": ">=0.3.0", "crosspad-gui": ">=0.2.0" }, "changelog": [ "0.1.0: Initial release" ] } -
Add the
crosspad-apptopic to your repo:gh repo edit CrossPad/crosspad-my-app --add-topic crosspad-app
-
CI will auto-discover your app on next run (every 6h), or trigger manually.
From CP Tools: Developer tools → Submit an app to the catalog checks your
crosspad-app.json and repository and opens the pull request for you.
By hand — for repos outside the CrossPad org, open a PR adding your repo to external-apps.json:
{
"repo": "your-user/your-crosspad-app",
"url": "https://github.com/your-user/your-crosspad-app.git",
"branch": "main"
}Your repo must also contain a crosspad-app.json with valid metadata.
| File | Purpose |
|---|---|
registry.json |
Auto-generated registry (consumed by app manager) |
crosspad.config.json |
(in each project) Track policy + feature flags — intent |
config/profiles/*.json |
(in each project) Named build recipes |
crosspad_app_manager.py |
Shared core — all app management + TUI logic |
install/install.sh, install/install.ps1 |
One-command setup for macOS/Linux and Windows |
tests/ |
Tests of the core, run on Windows, macOS and Linux by CI |
build_registry.py |
CI: discovers repos by topic, builds registry |
diff_registry.py |
CI: compares registries, outputs changes for notifications |
external-apps.json |
Community/third-party app repos (add via PR) |
COMMUNITY_APPS.md |
Auto-generated full list of community apps |