Reference for FixoStanzaTemplate — reusable stanza patterns that auto-wire to a preset's actuators using semantic tag matching.
Why templates exist
Wiring up an 18-actuator hexapod's legged-gait lobe by hand is tedious and error-prone. A stanza template captures the pattern (lobe type + output port tags + control widget hint) once; instantiation against a real preset runs Jaccard similarity matching to assign each lobe output to the best-matching actuator automatically. The user reviews and tweaks afterwards.
A FixoStanzaTemplate carries:
| Field | Description |
|---|---|
name, title, description, icon |
Display metadata |
lobeType |
Name of the FixoLobeType this template uses |
namedWidget |
UI hint for the control widget ("CarSteeringWidget", etc.); empty falls back to SliderBankWidget |
expectedOutputs |
QVector<FixoPort> — output ports the lobe will produce, each with semantic tags |
expectedInputs |
QVector<FixoPort> — input ports the control widget will produce |
Stored as fixoType: "stanza-template" in fixo.json. See the JSON schema.
Three stanza templates ship with libfixo:
differential-drive| Lobe type | wheeled |
| Control widget | CarSteeringWidget |
| Output ports | left_motor tagged ["wheel", "left", "motor"]right_motor tagged ["wheel", "right", "motor"] |
| Input ports | throttle ([-1, 1]), steering ([-1, 1]) |
Auto-connects to actuators tagged ["wheel", "left"] and ["wheel", "right"] (or supersets).
tracked-drive| Lobe type | tracked |
| Control widget | CarSteeringWidget |
| Output ports | left_track tagged ["track", "left"]right_track tagged ["track", "right"] |
| Input ports | throttle ([-1, 1]), steering ([-1, 1]) |
hexapod-walk| Lobe type | legged_gait |
| Control widget | (none — fallback SliderBankWidget) |
| Output ports | 18 ports: leg_<N>_coxa, leg_<N>_femur, leg_<N>_tibia for N in 0…5, each tagged accordingly |
| Input ports | speed, steering |
Designed to pair with the hexapod preset template which expands the actuators with matching semantic tags.
FixoAutoConnect::greedyAssign(outputs, actuators, includeZeroScore) runs when a stanza template is instantiated against a preset's actuators (and inside the preset editor when the user clicks Auto-connect on a stanza's pose-mapping):
Collect tags for every output port from the template, and for every actuator from the preset.
Score every (output, actuator) pair using Jaccard similarity:
score = |tags_out ∩ tags_act| / |tags_out ∪ tags_act|
Implemented as FixoPort::jaccard(QStringList, QStringList). A perfect match is 1.0; no overlap is 0.0.
Stable-sort all pairs by descending score. Ties break by (outputIndex, actuatorIndex) for deterministic output.
Greedy one-to-one assignment: take the highest-scoring unassigned pair, mark both endpoints used, repeat until no pairs remain.
Skip zero scores by default (no semantic overlap at all). Pass includeZeroScore = true for a "connect anyway" fallback that fills remaining outputs in deterministic order.
The result is a QVector<FixoMapping> ready to plug into a FixoStanza.
QVector<FixoMapping> FixoAutoConnect::greedyAssign(
const QVector<FixoPort> &outputs,
const QVector<FixoActuator> &actuators,
bool includeZeroScore = false);
A differential-drive template's outputs are tagged:
left_motor → ["wheel", "left", "motor"]
right_motor → ["wheel", "right", "motor"]
Against a preset whose actuators are tagged ["wheel", "left"] and ["wheel", "right"]:
| Output | Actuator | |∩| | |∪| | Jaccard |
|---|---|---|---|---|
| left_motor | ["wheel", "left"] | 2 | 3 | 0.667 |
| left_motor | ["wheel", "right"] | 1 | 4 | 0.250 |
| right_motor | ["wheel", "left"] | 1 | 4 | 0.250 |
| right_motor | ["wheel", "right"] | 2 | 3 | 0.667 |
Greedy assignment picks left_motor → ["wheel", "left"] (0.667), then right_motor → ["wheel", "right"] (0.667). The motor tag in the output set adds no preference between the two actuators, but it doesn't hurt either; what matters is the left / right distinction.
Anyone can author a custom template by dropping a fixo.json with fixoType: "stanza-template" into <personality>/fixo/stanza-templates/. FixoLibrary::scan() picks it up; it appears in the preset editor's stanza-add menu alongside the built-ins.
The recommended workflow is duplicate-to-edit: open FixoStanzaTemplateManager in the Studio, duplicate the closest built-in, rename, and edit the JSON.
| Class | Header |
|---|---|
FixoStanzaTemplate |
libfixo/fixo/preset/FixoStanzaTemplate.hpp |
FixoStanzaTemplateBook |
libfixo/fixo/library/FixoStanzaTemplateBook.hpp |
FixoAutoConnect |
libfixo/fixo/port/FixoAutoConnect.hpp |
FixoPort::jaccard |
libfixo/fixo/port/FixoPort.hpp |