The profile system lets you define named animation modes with a priority level, then activate and deactivate them at runtime. The highest-priority currently-active mode wins and drives the strand.
Built-in Profiles
Three ready-made profiles are available in hitlib/profiles/classic.hpp.
Mode Index Table
| Index | Name | Classic | Modern | Showy |
| 0 | Showoff | rainbow | rainbow | - |
| 1 | Idle | magenta flow | pink pulse | purple flow |
| 2 | Alliance Red | red pulse | red pulse + orange bg | white pulse / red bg |
| 3 | Alliance Blue | blue pulse | blue pulse + cyan bg | white pulse / blue bg |
| 4 | Scoring | green pulse | green flash | teal pulse |
| 5 | Matchloading | yellow pulse | yellow pulse | - |
| 6 | Endgame | warn -> white -> cycle | solid green -> pulse | yellow -> rainbow |
strand.activateMode(1);
strand.activateModeTimed(4, 1500);
strand.deactivateMode(1);
strand.detachProfile();
Ready-made Classic, Modern and Showy LED profiles.
const Profile classic
Classic profile instance.
Definition classic.hpp:106
Custom Profiles
1. Write setup functions
Driver for a single WS2812B-compatible LED strip on a VEX ADI port.
Definition led_strand.hpp:53
void flash(uint32_t color, uint32_t onMs, uint32_t offMs, uint32_t bgColor=0x000000)
Blink the whole strip on and off.
void rainbow(uint8_t speed)
Scroll a full HSV rainbow across the strip.
2. Declare modes
{"Idle", 10, myIdle, nullptr},
{"Alert", 80, myAlert, nullptr},
};
Describes a single named animation mode within a Profile.
Definition led_profile.hpp:38
An immutable, statically-allocated collection of ProfileMode entries.
Definition led_profile.hpp:68
3. Attach and activate
strand.attachProfile(&myProfile);
strand.activateMode(0);
Exported from Pattern Studio
Pattern Studio writes the three steps above for you, and can put the result straight into your project.
Show it your PROS project once - Export > Choose PROS Project..., or drag the project folder onto the window - and Deploy writes include/hitlib_studio.hpp every time you click it. Re-deploying overwrites that one file, so changing a port or adding a mode is: click Deploy, rebuild.
What you write once
#include "hitlib_studio.hpp"
namespace myRobot = hitlib::profiles::myRobot;
void initialize() {
hitlib::studio::begin();
}
void opcontrol() {
myRobot::strand.activateModeTimed(myRobot::mode::endgame, 30000);
}
begin() registers every strand in the design, starts its refresh task at the design's interval, attaches each profile and activates each strand's first mode. A second call does nothing, so a routine that re-runs its own init is safe.
The exported file opens with this same snippet as a comment, filled in with your design's real identifiers and mode names.
What the file contains
Each strand gets its own namespace under hitlib::profiles:
namespace myRobot {
constexpr uint8_t adiPort = 6;
constexpr uint8_t length = 63;
constexpr uint32_t refreshMs = 25;
constexpr uint8_t brightness = 80;
namespace mode {
constexpr uint8_t idle = 0;
constexpr uint8_t endgame = 1;
}
namespace detail { }
inline const ProfileMode modeTable[] = { ... };
inline const Profile profile = {"My Robot", modeTable, 2};
inline void apply(LedStrand& s);
inline void apply(LedGroup& g);
inline LedStrand strand{adiPort, length, refreshMs};
}
}
namespace hitlib::studio {
inline LedGroup groups[1];
inline LedGroup& group = groups[0];
inline void begin();
inline void begin(LedGroup& existing);
}
Definition classic.hpp:51
The constexpr hardware values are why the strand on the robot matches the one in the preview: the port, length and refresh interval come from the design rather than being retyped. strand is an ordinary hitlib::LedStrand built from those constants - every API call still works on it directly. The mode:: constants replace counting rows in modeTable to work out what index activateMode() wants.
Fitting it to your own code
The strand and the group are optional. Two ways to opt out, each one line:
hitlib::studio::begin(yourGroup);
puts the design's strands into a group you already own and attaches their profiles, leaving init(), start() and the refresh interval to you. Or:
#define HITLIB_STUDIO_NO_AUTOWIRE
#include "hitlib_studio.hpp"
and the file defines no strands and no group - only the profile and the constants:
namespace myRobot = hitlib::profiles::myRobot;
hitlib::LedStrand myRobotStrand(myRobot::adiPort, myRobot::length, myRobot::refreshMs);
void initialize() {
group.
add(&myRobotStrand);
group.
init(myRobot::refreshMs);
myRobot::apply(group);
}
Owns a set of LedStrand pointers and fans all animation commands out to each strand simultaneously.
Definition led_group.hpp:39
void add(LedStrand *strand)
Register a strand with this group.
void init(uint32_t refreshMs=20)
Initialize hardware on all registered strands.
void start()
Start the group refresh task.
void activateMode(uint8_t modeIdx)
Push a persistent mode onto the mode stack.
One deployed header per project: it defines hitlib::studio, so two in one build would define begin() twice. Keep every strand in one document, which is what Deploy exports.
Multiple strands
Deploy writes the whole document, so multi-strand designs need nothing extra. Two separately exported headers can collide: if both have an Idle mode, each defines its own setup function for it and they cannot share a .cpp.
namespace left = hitlib::profiles::left;
namespace right = hitlib::profiles::right;
void initialize() {
hitlib::studio::begin();
}
void opcontrol() {
left::strand.activateMode(left::mode::idle);
right::strand.activateMode(right::mode::idle);
}
Strands designed at different refresh intervals get a group each, since a group ticks everything it owns at one rate. begin() handles that; it is still one call.
Strand names become namespace names, so each strand needs a distinct one. Pattern Studio blocks the export until they are unique.
Exporting to a file instead
Export > Export Current Strand as C++... and Export All Strands as C++... still save through a normal file dialog, for a project Pattern Studio cannot see or a header you want to check in by hand. The generated code is identical.
Mode Stack Rules
- Modes are stored in a priority stack, the highest-priority active mode wins.
- Multiple modes can be active simultaneously, the winner updates every tick.
- Timed modes auto-expire, persistent modes stay until deactivateMode() is called.
- Calling activateModeTimed() on an already-timed mode extends its deadline rather than creating a duplicate entry.
Sequencer
hitlib::Sequencer drives multi-phase endgame / event sequences inside onActivate and onTick profile callbacks.
{2000, phase1},
{8000, phase2},
};
Forward declaration.
Definition led_sequencer.hpp:46
One phase in the animation sequence.
Definition led_sequencer.hpp:53
Phases loop indefinitely until the mode is deactivated.