Skill Tree JSON Format

The format of a JSON file that defines a skill tree, placed in the skilltrees folder of your namespace (data/<namespace>/skill_trees/<name>.json).

The format of a JSON file that defines a skill tree, placed in the skill_trees folder of your namespace (data/<namespace>/skill_trees/<name>.json). A skill tree file only defines the tree itself. Its tab, background, and the powers every holder of the tree gets by default. The individual skills that appear in the tree are not defined here; each skill lives in the power file it unlocks, via Skill Tree Power Data (the same way Origins badges live on their powers).

How a tree reaches a player: by default (auto_grant: true) every player has the tree. Set auto_grant: false to hide it until it is explicitly granted with Grant Skill Tree (Entity Action Type) from an origin’s power, an item, another power’s action, or any other entity-action source. Revoke Skill Tree (Entity Action Type) takes it away again (purchased skills are remembered and come back if the tree is re-granted). Because grants are stored per player and only change on those actions, there is no per-tick condition checking. A tree can additionally carry a condition for the cases a stored grant can’t express — see Tying a tree to an origin.

Fields

FieldTypeDefaultDescription
nameText ComponentemptyThe display name of the tree’s tab.
descriptionText ComponentemptyThe description of the tree’s tab.
iconIcon{"item": "minecraft:grass_block"}The item or texture shown as the tree’s tab icon.
frametask | goal | challengetaskThe border drawn around the tree’s tab icon, matching the advancement frames.
backgroundIdentifieroptionalThe texture used as the background of the tree screen.
default_powersArray of IdentifieroptionalPowers granted to every player who has the tree (e.g. a point-earning power). Removed when the tree is revoked.
orderInteger0Tab order among trees — lower values come first; ties keep load order.
auto_grantBooleantrueIf true, every player automatically has this tree (revoking has no lasting effect). If false, the tree is hidden until granted via the grant action.
conditionEntity Condition TypeoptionalIf set, the tree only counts for players who fulfil it — see Tying a tree to an origin.
refundableBooleantrueIf true, players can shift-click a purchased skill in the tree screen to un-buy it — the power is removed and its point cost returned (only allowed while no purchased skill depends on it). Set false to make purchases permanent (admins can still unbuy via the /apoli:skill_tree command).

Tying a tree to an origin

auto_grant and the grant/revoke actions are stored state: once a player has a tree, they keep it until something takes it away. condition is the live half — a tree whose condition is false still remembers everything the player bought, but none of its powers apply and its tab is hidden. When the condition becomes true again, the purchases come straight back.

That is what ties a tree to an origin, so its skills don’t follow the player into their next one:

{
	"name": "Pyromancy",
	"condition": {
		"type": "origins:origin",
		"layer": "origins:origin",
		"origin": "my_pack:ember"
	}
}

A tree with no condition is global — every player keeps its powers through any number of origin changes, which is what you want for something like a server-wide progression tree.

The condition is re-evaluated whenever Origins reconciles a player’s origins (join, data-pack reload, orb, and every origin choice) — not every tick. A condition on something that changes constantly, like health or the time of day, will not track it in real time; gate on an origin, an advancement or a power instead.

Tree file or skill file?

A file in skill_trees/ is read as a skill — not a tree — when it has a parent field. That one field is the whole distinction:

The file has…It is…
no parenta tree; the fields above apply
a parenta skill inside a tree

So a pack can define its skills either way:

  • inside the power file, via Skill Tree Power Data — the power is the skill
  • as its own file in skill_trees/, naming the power(s) it unlocks

Both end up in the same tree and behave identically. Power-data skills win if both define the same id.

Skill file fields

FieldTypeDefaultDescription
parentIdentifierrequiredThe tree, or another skill, this one hangs off.
power / powersIdentifier or Array of IdentifiernoneThe power(s) buying this skill grants.
nameText Componentskill.<ns>.<path>.nameDisplay name.
descriptionText Componentskill.<ns>.<path>.descriptionDisplay description.
iconIcon{"item": "minecraft:grass_block"}Node icon — an item id, an item stack, or a texture.
frametask | goal | challengetaskBorder drawn around the node, matching the advancement frames.
costInteger0Points needed to buy it.
excludesArray of Identifier[]Skills that become unbuyable once this one is bought, and vice versa.
conditionEntity ConditionoptionalMust pass before the skill can be bought.
visibility_conditionEntity ConditionoptionalMust pass for the node to appear at all.
orderInteger0Sort order among siblings.

A skill with no power/powers is a free pass-through node: it can’t be bought, and its children treat it as already satisfied. Use it to branch a tree without charging for the branch point.

{
   "parent":"example_pack:parkour_skills",
   "power":"example_pack:double_jump",
   "icon":{
      "item":"minecraft:feather"
   },
   "cost":2,
   "condition":{
      "type":"apoli:advancement",
      "advancement":"example_pack:learned_to_jump"
   }
}

Every skill’s parent chain must end at a tree file. A skill whose chain never reaches one is dropped with a warning naming the file — it will not show up anywhere.

Example

{
	"name": "Parkour Skills",
	"description": "A skill tree that lets you earn parkour skills",
	"icon": {
		"item": "minecraft:stick"
	},
	"default_powers": [
		"example_pack:gain_points"
	],
	"auto_grant": false
}

This tree (example_pack:parkour_skills) stays hidden until something runs:

{
    "type": "apoli:grant_skill_tree",
    "skill_tree": "example_pack:parkour_skills"
}

A skill is then attached to the tree from inside its power file:

{
   "type":"apoli:multiple",
   "skill":{
      "parent":"example_pack:parkour_skills",
      "icon":{
         "item":"minecraft:feather"
      },
      "cost":2
   }
}

Screen controls

  • Drag with the left mouse button to pan the tree.
  • Mouse wheel zooms out/in (down to 25%), centered on the window. Hovering a node always pops a full-size info card, so small nodes stay readable while zoomed out. When the whole tree fits in the window it stays centered.
  • Opening the screen requests a fresh skill state from the server, so per-skill conditions are up to date the moment it opens (an open screen also refreshes live whenever the server pushes a new state).