Custom Classes

In NeoOrigins, a class is not a separate system — it’s an ordinary origin that lives in the special neoorigins:class layer. Every player picks an origin (layer 1) and a class (layer 2); the class screen is the second selection screen shown on first join.

Because a class is just an origin, everything in PACK_FORMAT.md about Origin JSON and Power JSON applies directly. This page covers only what’s class-specific.

The class layer

The built-in class layer is defined at data/neoorigins/origins/origin_layers/class.json with order: 2. Classes are intentionally passive: all built-in class powers are passive or condition-gated, so a class never consumes a keybind slot. Keep custom classes to passive/attribute/condition powers — active (keybinded) powers in the class layer are not the intended design and the class power list is treated as always-on, not slotted.

You do not need to edit the built-in class.json. Any layer file whose path is class is automatically folded into neoorigins:class, regardless of namespace. So ship your own:

data/<yourpack>/origins/origin_layers/class.json

{
  "name": "origins.layer.class",
  "origins": [
    "yourpack:class_alchemist"
  ]
}

Your class is appended to the existing list — all built-in classes are kept, and you never have to maintain a copy of the mod’s list. (Opt out of the fold with "standalone": true if you deliberately want a separate screen.)

Alternative: overriding the built-in layer

You can place a file at the exact built-in path data/neoorigins/origins/origin_layers/class.json, but this replaces the list entirely — you must re-list every built-in class you want to keep, and re-sync on every mod update. Prefer the additive method above unless you specifically want to remove built-in classes (the [classes] config toggles are usually the better tool for that).

The class origin JSON

Identical to any origin (data/<yourpack>/origins/origins/<id>.json). Conventions used by the built-ins:

{
  "name": "origins.yourpack.class_alchemist.name",
  "description": "origins.yourpack.class_alchemist.description",
  "icon": "minecraft:brewing_stand",
  "impact": "none",
  "order": 21,
  "powers": [
    "yourpack:class_alchemist_resilience",
    "yourpack:class_alchemist_antidote"
  ],
  "upgrades": []
}
  • icon — item shown in the class picker.
  • impact: "none" — classes don’t carry an origin “impact” rating; always none.
  • order — position in the class screen (built-ins occupy 1–20; use 21+ to append after them).
  • powers — passive/condition powers only (see above).
  • upgrades — optional advancement-driven promotion to another class; see the working examples/class_tier_up/ datapack and the Upgrades section of the examples README.

Naming convention: prefix the origin id and its powers with class_ (class_alchemist, class_alchemist_resilience). Not required by the code, but it keeps packs consistent with the built-ins.

Lang keys

Same derivation as any origin/power:

  • origins.<namespace>.<class_id>.name / .description
  • power.<namespace>.<power_id>.name / .description

Or use literal components ({"text": "Alchemist"}) directly in the JSON if you don’t want a resource/language pack — handy for self-contained datapacks.

Defaults and config

  • No class chosen: if a player closes the picker with an origin but no class, NeoOrigins auto-assigns neoorigins:class_nitwit (a deliberate no-effect default) so starting equipment and pending grants still resolve.
  • Disabling built-ins: the [classes] section in config/neoorigins/content.toml toggles each built-in class. Disabled classes are removed after data load (still assignable via /neoorigins set).
  • No classes at all: if every class is disabled, the class selection screen is skipped entirely and only the origin layer is shown.

See also