The fixo.json schema

File format for Fixo types, presets, and templates

Reference for the file format every Fixo resource is stored in. Each fixo.json is self-contained — it declares its kind via fixoType, supplies metadata, and references sibling source files by relative path. The folder name is cosmetic; only the file content matters to FixoLibrary.

Discovery in one sentence

FixoLibrary::scan(builtinDir, customDir) walks both trees recursively, parses every fixo.json it finds, and routes each one to the matching Book by fixoType value.


Common fields (all fixoType values)

Field Type Required Description
fixoType string yes Discriminator: "actuator-type", "sensor-type", "lobe-type", "board-type", "preset", "stanza-template", "preset-template"
name string yes Stable id used in cross-references (kebab-case by convention)
title string no Display title (defaults to name)
description string no Short user-facing description
icon string no Filename of an SVG sibling, or a :/... resource path
sources string[] no Sibling files (.hpp, .cpp, .h, .c) that the firmware generator includes when this resource is used
mainHeader string no One of sources — the header the generated firmware actually #includes
builtin bool no true for resources that ship in the libfixo qrc; false (default) for user-authored files

fixoType: "actuator-type"

{
  "fixoType": "actuator-type",
  "name": "rc-servo",
  "title": "RC servo",
  "description": "Standard hobby RC servo (PWM, 500-2500 µs)",
  "icon": "rc-servo.svg",
  "sources": ["rc-servo.hpp"],
  "mainHeader": "rc-servo.hpp",
  "builtin": true,

  "pinCount": 1,
  "pinPurposes": ["pwm"],

  "valueRep": {
    "totalBits": 16,
    "fractionalBits": 0,
    "isSigned": false,
    "isFloat": false
  }
}
Field Type Required Description
pinCount int yes How many pins one instance occupies
pinPurposes string[] yes Length must equal pinCount; e.g. ["pwm"], ["pwm", "direction"]
valueRep.totalBits int yes Total bits in the wire-encoded value
valueRep.fractionalBits int no For fixed-point values; default 0
valueRep.isSigned bool no Default false
valueRep.isFloat bool no If true, the value is IEEE-754 float; ignores fractional bits

fixoType: "sensor-type"

{
  "fixoType": "sensor-type",
  "name": "encoder",
  "title": "Rotary encoder",
  "sources": ["encoder.hpp"],
  "mainHeader": "encoder.hpp",
  "builtin": true,

  "pinCount": 2,
  "pinPurposes": ["channel_a", "channel_b"],
  "sensorType": "encoder"
}
Field Type Required Description
pinCount int yes Pins per instance
pinPurposes string[] yes One label per pin
sensorType string yes One of: digital_input, analog_input, encoder, counter, limit_switch, tachometer

fixoType: "lobe-type"

{
  "fixoType": "lobe-type",
  "name": "legged-gait",
  "title": "Legged gait engine",
  "sources": ["legged-gait.hpp", "inverse-kinematics.hpp"],
  "mainHeader": "legged-gait.hpp",
  "builtin": true,

  "placement": "both",
  "inputParameters": ["speed", "steering"],
  "outputPorts": [
    {"name": "leg_0_coxa",  "tags": ["leg_0", "coxa", "joint"], "min": -1.0, "max": 1.0},
    {"name": "leg_0_femur", "tags": ["leg_0", "femur", "joint"], "min": -1.0, "max": 1.0}
  ]
}
Field Type Required Description
placement enum yes "board-only", "native-only", or "both"
inputParameters string[] no Names of runtime-tunable parameters (e.g. speed, steering)
inputPorts port[] no Lobe inputs (used by the control widget)
outputPorts port[] no Lobe outputs (matched against actuators by tags)

A port object has the shape { "name": str, "tags": [str], "min": number, "max": number, "direction": "Input" | "Output" }. See the data model.


fixoType: "board-type"

{
  "fixoType": "board-type",
  "name": "arduino-uno",
  "title": "Arduino Uno",
  "description": "ATmega328P-based board (14 digital, 6 analog)",
  "icon": "arduino-uno.svg",
  "sources": ["arduino-uno.hpp"],
  "mainHeader": "arduino-uno.hpp",
  "builtin": true,

  "boardName": "arduino-uno"
}
Field Type Required Description
boardName string yes Name of the matching record in libboard's board database (provides pin map, MCU details, USB IDs, bootloader config)

fixoType: "preset"

{
  "fixoType": "preset",
  "name": "hexy-explorer",
  "version": 1,
  "board": "arduino-mega2560",
  "actuators": [
    {
      "type": "rc-servo",
      "name": "leg_0_coxa",
      "pin": 22,
      "trim": 0,
      "min": -90, "max": 90,
      "reverse": false,
      "semanticTags": ["leg_0", "coxa"]
    }
  ],
  "sensors": [],
  "stanzas": [
    {
      "id": "walk",
      "lobeType": "legged-gait",
      "namedWidget": "JoystickWidget",
      "mapping": [
        {"lobePort": "leg_0_coxa", "actuatorIndex": 0}
      ],
      "inputs": [
        {"name": "speed",    "min": 0.0,  "max": 1.0, "default": 0.5},
        {"name": "steering", "min": -1.0, "max": 1.0, "default": 0.0}
      ]
    }
  ]
}

Field-by-field semantics live in Fixo Data Model. The schema validator only enforces the shapes; cross-references (e.g. that type resolves to a known actuator type) are checked at preset-load time.


fixoType: "stanza-template"

{
  "fixoType": "stanza-template",
  "name": "differential-drive",
  "title": "Differential drive",
  "description": "Two-wheel tank steering with throttle and turn inputs",
  "builtin": true,

  "lobeType": "wheeled",
  "namedWidget": "CarSteeringWidget",
  "expectedOutputs": [
    {"name": "left_motor",  "tags": ["wheel", "left", "motor"]},
    {"name": "right_motor", "tags": ["wheel", "right", "motor"]}
  ],
  "expectedInputs": [
    {"name": "throttle", "min": -1.0, "max": 1.0},
    {"name": "steering", "min": -1.0, "max": 1.0}
  ]
}

When instantiated against a preset, FixoStanzaTemplate::instantiate(stanzaId, actuators) runs auto-connect (Jaccard tag-similarity, greedy one-to-one assignment) and returns a fully-populated FixoStanza with the mapping set. See Stanza Templates.


fixoType: "preset-template"

{
  "fixoType": "preset-template",
  "name": "hexapod",
  "title": "Hexapod walker",
  "description": "Six-legged walker with three joints per leg",
  "builtin": true,

  "parameters": {
    "board":    {"type": "board-type", "default": "arduino-mega2560"},
    "name":     {"type": "string"},
    "legCount": {"type": "int", "default": 6}
  },
  "preset": {
    "name":  "{{name}}",
    "board": "{{board}}",
    "actuators": [],
    "sensors":   [],
    "stanzas": [
      {"id": "walk", "lobeType": "template:hexapod-walk"}
    ]
  },
  "forEachActuators": [
    {
      "countParameter": "legCount",
      "pattern": {
        "type": "rc-servo",
        "name": "leg_{{index}}_coxa",
        "semanticTags": ["leg_{{index}}", "coxa"]
      }
    }
  ]
}

The substitution language is documented in Preset Templates. Key points:

  • {{paramName}} is substituted in any string field
  • parameters[...].type is one of "board-type", "int", "string"
  • forEachActuators expansion is driven by an int parameter (countParameter); {{index}} substitutes per iteration
  • lobeType: "template:..." refers to a FixoStanzaTemplate to expand at instantiate time
  • Arithmetic ({{a * b}}) is not supported — use a single int parameter for the count

Discovery layout

A typical custom storage tree looks like this:

<personality>/fixo/
├── presets/
│   └── hexy-explorer.fixo.json
├── actuator-types/
│   └── my-custom-servo/
│       ├── fixo.json
│       └── my-custom-servo.hpp
├── lobe-types/
│   └── my-trim-lobe/
│       ├── fixo.json
│       └── my-trim-lobe.hpp
├── stanza-templates/
└── preset-templates/

Folders are organisational only. FixoLibrary::scan() walks recursively; it'll route a file regardless of the directory it sits in.


See also

In this section
Topics
reference hardware fixo schema json
See also