Skip to content

Make an example your own

SDK 1.xWritten for core 1.53+ and gui 1.23+.

Goal: an app of your own, copied from the cookbook example closest to your idea, with its own id, name, icon and git repo, that builds next to the example without a clash and is ready for Publish an app.

You need: the recipe for that example done on the board (Start here and a first flash), and the crosspad-examples clone. Publishing later needs gh auth login.

An example is a complete app, but every name in it says “example”: its id, its folder, its icon, the name it registers, and the names in its C++. Two apps must not share any of these, so a copy that keeps them clashes with the example in the build. This page renames all of them in one pass. It uses Pads and LEDs as the starting point and my-instrument / MyInstrument as the new names; The names to change lists them for every example.

Prefer an empty app? Start from the template generates one with your names already in it.

WhatIn the exampleIn your appWhere it is used
App idexample-pads-ledsmy-instrumentid in crosspad-app.json, the folder crosspad-<id>, component_path, the catalog
App namePadsLedsMyInstrumentThe first argument of REGISTER_APP / REGISTER_APP_PL: the label in the simulator’s launcher, the name app start and mode_overlay_open_app() take. A C++ identifier, unique among all apps
Pad logic name"PadsLeds""MyInstrument"registerPadLogic("…") and the last argument of REGISTER_APP_PL (only apps that own the pads); the two must match
Iconassets/example-pads-leds.pngassets/my-instrument.pngThe third argument of REGISTER_APP, and icon in the manifest. Every app’s icons end up in one folder, so name it after the id
Header folderinclude/example-pads-leds/include/my-instrument/The #include lines
C++ namesPadsLeds_create, PadsLedsPadLogic, namespace example_padsMyInstrument_create, MyInstrumentPadLogic, namespace my_instrumentFunctions and classes outside an anonymous namespace are global: the same name in two apps fails to link

The other examples follow the same pattern:

ExampleApp nameNamespace
01-hello-screenHelloScreenexample_hello
02-pads-ledsPadsLedsexample_pads
03-play-samplePlaySampleexample_play
05-midi-outMidiOutexample_midi
07-tempo-transportTempoTransportexample_tempo
09-motionMotionexample_motion
10-ui-kitUiKitexample_ui

The id is always example- plus the folder name without its number. Replace Motion with care: it is also part of other names in that example (MotionGesture, MotionModel.hpp), so rename Motion_create, Motion_destroy and the REGISTER_APP line one by one.

  1. Copy the example’s folder into the firmware project, under the name crosspad-<your id>. The build looks for apps only in folders named crosspad-*. Copy from your crosspad-examples clone, not from an example you installed: an installed copy carries a .crosspad-example marker for install.py.

    Terminal window
    cp -r examples/02-pads-leds ~/CrossPad/components/crosspad-my-instrument
    cd ~/CrossPad/components/crosspad-my-instrument

    You should see: crosspad-app.json, CMakeLists.txt, assets, include, src and tests in the new folder.

  2. Rename the folder and files that carry the old names.

    Terminal window
    mv include/example-pads-leds include/my-instrument
    mv include/my-instrument/PadsLedsPadLogic.hpp include/my-instrument/MyInstrumentPadLogic.hpp
    mv assets/example-pads-leds.png assets/my-instrument.png
    mv src/PadsLedsApp.cpp src/MyInstrumentApp.cpp
    mv src/PadsLedsPadLogic.cpp src/MyInstrumentPadLogic.cpp

    The build compiles every .cpp in src/, whatever its name, so the source file names are only for you. The header folder and the icon must match the names in the code, which the next step changes.

  3. Replace the three old names in every text file. Match case: PadsLeds and example_pads are case-sensitive names.

    Terminal window
    grep -rlI -e PadsLeds -e example-pads-leds -e example_pads . | xargs perl -pi -e 's/PadsLeds/MyInstrument/g; s/example-pads-leds/my-instrument/g; s/example_pads/my_instrument/g'
    grep -rnI -e PadsLeds -e example-pads-leds -e example_pads .

    You should see: no output from the second command (Windows: no results for any old name). src/MyInstrumentApp.cpp now ends with REGISTER_APP_PL(MyInstrument, nullptr, "my-instrument.png", and the pad logic name "MyInstrument".

  4. Describe your app in crosspad-app.json. The id, the icon and component_path are already right; set name, description and category (music, audio, tools or other; the examples use example), and start version and changelog at your first version. Manifest fields explains each field.

    {
    "name": "My Instrument",
    "id": "my-instrument",
    "version": "0.1.0",
    "description": "What it does, in one line",
    "category": "music",
    "icon": "my-instrument.png",
    "component_path": "components/crosspad-my-instrument",
    "platforms": ["esp-idf", "pc"],
    "requires": {
    "crosspad-core": ">=1.53.0",
    "crosspad-gui": ">=1.23.0"
    },
    "changelog": [
    "0.1.0: first version"
    ]
    }

    Keep requires as the example had it: UI kit’s asks for gui >=1.23.1. Draw your own 48 × 48 px icon over assets/my-instrument.png when you have one.

  5. Build it into the firmware, from the project root (~/CrossPad, Windows C:\CrossPad\firmware) with ESP-IDF loaded, as in 2. Build the firmware. The example can stay installed next to your app: with every name changed, the two do not clash. Each one takes one of the board’s 24 app slots, so remove the example with tools/install.py --target idf … --remove from the examples clone when you no longer need it.

    Terminal window
    cd ~/CrossPad
    idf.py -B build_v2 fullclean
    idf.py -B build_v2 -DSDKCONFIG=sdkconfig.v2 build

    For a v1 board, use build_v1 and sdkconfig.v1. Used the one-line installer? Use crosspad-idf in place of idf.py.

    You should see: the lines under Check it worked while CMake configures, and Project build complete. To flash, run: at the end.

    If not: multiple definition of at link time means a global name still matches another app’s: go back to step 3. The app missing from the list: a new app does not show up. Asset collision while configuring: the icon still has another app’s file name.

  6. Give the app its own git repository and push it to GitHub, so it can be published and cloned into the simulator. tests/build/ is the host test’s build folder (step 7); keep it out of the repo.

    Terminal window
    cd ~/CrossPad/components/crosspad-my-instrument
    echo "tests/build/" > .gitignore
    git init -b main
    git add -A
    git commit -m "My Instrument, from the pads-leds example"
    gh repo create you/crosspad-my-instrument --public --source . --remote origin --push

    you is your GitHub user name. The examples are GPL-3.0-or-later, and so is an app made from one: keep the SPDX-License-Identifier line at the top of each file, and add the licence text as LICENSE (copy it from the crosspad-examples clone).

    You should see: gh end with ✓ Pushed commits to ….

  7. Keep the host test. tests/test_pads_leds.cpp still tests your model (PadsModel.hpp); its build file lives in crosspad-examples, not in the example’s folder. Copy crosspad-examples’ tests/CMakeLists.txt into your app’s tests/ and change its two globs: ../examples/*/tests/*.cpp becomes *.cpp and ../examples/*/include becomes ../include. Then build and run it from the app’s folder as in Test it on your computer, without -R.

    You should see: 100% tests passed, 0 tests failed out of 5 for the copied pads-leds test.

To run the app in the PC simulator too, clone its repo into the simulator’s apps folder, ~/crosspad-pc/src/apps/crosspad-my-instrument (Windows C:\crosspad-pc\src\apps\crosspad-my-instrument), and rebuild the simulator. Work in one of the two copies and pull in the other, so they do not drift apart.

The firmware build from step 5 lists your app while CMake configures (somewhere inside each list, not at the end):

Generated app_registry_init.cpp with N apps: ...;MyInstrument;...
Assets: staged 1 assets from component 'crosspad-my-instrument'

After a flash, the app opens as MyInstrument, the same way as the example did (Opening an app).