Stanza Templates

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.


Anatomy

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.


Built-in templates

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.


Auto-connect — how the matching works

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):

  1. Collect tags for every output port from the template, and for every actuator from the preset.

  2. 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.

  3. Stable-sort all pairs by descending score. Ties break by (outputIndex, actuatorIndex) for deterministic output.

  4. Greedy one-to-one assignment: take the highest-scoring unassigned pair, mark both endpoints used, repeat until no pairs remain.

  5. 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.

  6. 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 worked example

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.


Custom templates

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.


Source code

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

See also