Skip to content

User Guide Templates

Adam Burdík edited this page Sep 29, 2026 · 2 revisions

Templates

A template arranges variables, groups, literal text, and blank lines into a lore layout.

Node types

Node Purpose
text "..." A literal line. MiniMessage formatting only, no data lookup.
var "name" Renders a declared variable's value. Supports prefix/suffix.
group "name" each="..." empty="..." Renders a declared group's elements.
blank An empty lore line.

Conditional lines with collapse-if-empty

Any node can take collapse-if-empty="<group-id>". If that group rendered zero elements, the node itself is skipped. This lets you write section headers and separators that only appear when there's actually something to show:

template "weapon_default" {
    text "<red>Hello, World"
    
    blank collapse-if-empty="enchantments"
    text "<gold>Enchantments:" collapse-if-empty="enchantments"
    group "enchantments" each="<yellow><ench_name> <ench_level_roman>" empty="skip"
    text "<gold>-------------" collapse-if-empty="enchantments"
    
    blank collapse-if-empty="attributes"
    text "<gray>When in Main Hand:" collapse-if-empty="attributes-main-hand"
    
    group "attributes-main-hand" each=" <attr_color><attr_value> <attr_name>" empty="skip"
    text "<red>This is footer!"
}

If the item has no enchantments, the header, group, and divider all vanish. Only "Hello, World" and "This is footer!" remain, with no leftover gap.

A full "vanilla-style" tooltip template

template "vanilla" {
    group "enchantments" each="<gray><ench_name> <ench_level_roman>" empty="skip"

    blank collapse-if-empty="attributes"
    text "<gray>When in Main Hand:" collapse-if-empty="attributes-main-hand"
    group "attributes-main-hand" each=" <attr_color><attr_value> <attr_name>" empty="skip"
    text "<gray>When in Off Hand:" collapse-if-empty="attributes-off-hand"
    group "attributes-off-hand" each=" <attr_color><attr_value> <attr_name>" empty="skip"
    text "<gray>When Equipped:" collapse-if-empty="attributes-any"
    group "attributes-any" each=" <attr_color><attr_value> <attr_name>" empty="skip"
    text "<gray>When on Head:" collapse-if-empty="attributes-head"
    group "attributes-head" each=" <attr_color><attr_value> <attr_name>" empty="skip"
    text "<gray>When on Chest:" collapse-if-empty="attributes-chest"
    group "attributes-chest" each=" <attr_color><attr_value> <attr_name>" empty="skip"
    text "<gray>When on Legs:" collapse-if-empty="attributes-legs"
    group "attributes-legs" each=" <attr_color><attr_value> <attr_name>" empty="skip"
    text "<gray>When on Feet:" collapse-if-empty="attributes-feet"
    group "attributes-feet" each=" <attr_color><attr_value> <attr_name>" empty="skip"
}

Sections

section "name" { ... } groups a block of template nodes under a name, so another template can reuse it via extends + insert, instead of copy-pasting the same lines into every child.

template "vanilla" {
    section "enchantments" {
        group "enchantments" each="<gray><ench_name> <ench_level_roman>" empty="skip"
    }

    section "attributes" {
        blank collapse-if-empty="attributes"
        text "<gray>When in Main Hand:" collapse-if-empty="attributes-main-hand"
        group "attributes-main-hand" each=" <attr_color><attr_value> <attr_name>" empty="skip"
        ...
    }
}

Rendered on its own, a template with sections works like one without them. Each section's contents render inline, in the order the sections are declared. Sections only matter once another template extends this one.

Extending with insert lets a child decide where each section goes, instead of everything from the parent being appended after the child's own content:

template "vanilla_extended" extends="vanilla" tooltip-style="simple" {
    var "rarity"

    insert "enchantments"

    blank collapse-if-empty="description"
    group "description" each="<gray><line>" empty="skip"

    insert "attributes"
}

This renders rarity, then the enchantments section, then description, then attributes. That order is something the parent alone cannot express.

Two modes, decided per child:

  • No insert used at all. The child falls back to plain append: everything from the parent comes first (sections rendered inline, in their declared order), then the child's own nodes. This is the original extends behavior, unchanged.
  • Any insert used. The child switches to fully explicit placement. Every parent section must be placed somewhere with its own insert, or the config fails to load with an error naming the missing section. This stops a forgotten insert from silently dropping content. You either use insert and place everything, or you don't use it and get the whole parent for free.

A parent's sections are also visible to a grandchild further down an extension chain, unless the grandchild redefines a section with the same name. In that case its own version wins.

Extending templates

extends reuses another template's nodes and appends new nodes after them:

template "vanilla_extended" extends="vanilla" {
    blank collapse-if-empty="description"
    group "description" each="<gray><line>" empty="skip"
    var "rarity"
}

This renders everything from vanilla, then the description block, then rarity, in that order, since new nodes are appended at the end.

Resourcepack integration

tooltip-style applies a tooltip-style data component to the item:

template "vanilla_extended" extends="vanilla" tooltip-style="simple" {
	blank collapse-if-empty="description"
	group "description" each="<gray><line>" empty="skip"
	var "rarity"
}

Applying a template to an item

Items reference their template via a single PDC tag (template_id). Whenever that item changes in a way that should affect lore (enchanted, crafted, repaired, or set manually via command), the plugin rebuilds the lore from the current template + current PDC/item data.

/lore set template weapon_default
/lore set variable rarity epic
/lore set group description Example description.\nThis will be on second line\nThird line

Use \n (or actual newlines in the command) to write a group with multiple lines. /lore set group accepts any number of values.

User Guide

Developer API

Plugin Integrations

Clone this wiki locally