Variants and presets
Ship several versions of one model part, know which one Punchy! draws, let players pick by item name, and add particles that show only on enchanted items.
-
Punchy! Studio
This page has not been translated into Finnish yet, so it is shown in English. Read in English
On this page
A variant is a second version of a model part: the same lantern with sparks instead of smoke, or one that only shows when the item has a certain name. Punchy! loads every definition in your pack and then draws one of them for the held item, so making a variant is mostly a question of making the right one win. This page is for pack makers who already have a model part definition and want to ship presets, named versions, or particles that depend on enchantments.
Before you start
- Install Punchy! 3.0 or newer from Modrinth or CurseForge. This page was checked against Punchy! 3.0 for Fabric on Minecraft 26.3.
- Have the lantern pack from Model part definitions working:
definitions/lantern.json,geo/lantern.geo.json,textures/lantern.pngandanimations/lantern.animation.json. Every example below reuses those files. That page gives the text of the definition, the geometry and the clips, how to draw the texture (a flat orange 16 by 16 square is enough) and thepack.mcmeta. Keep everything below in that one pack. - Know how to reload. Press F3+T in a world after you change a file. Punchy! reads your definitions and compat files again, and the chat says
[Debug]: Reloaded resource packswhen it is done. - For the Studio steps you need Punchy! Studio, from Modrinth or CurseForge.
How Punchy! picks one variant
A variant is not a special kind of file. It is an ordinary definition that lists the same item as another definition. Punchy! never merges two definitions and never fills the gaps of one from another, so every variant is a complete file of its own.
For each held item Punchy! then picks exactly one definition. The pick depends on three things:
- The item’s name. A definition with a
customNameanswers only stacks that carry that name. - The sort order of the ids. Among unnamed definitions that list the item, the first one wins. Ids are sorted as text, ignoring letter case, starting with the namespace. A folder name is part of the id, so folders decide who wins.
- The pack that holds the file. Two packs that ship a file at exactly the same path are one id. Minecraft uses the file from the pack higher in the list, as it does for every other resource.
| Situation | What Punchy! draws |
|---|---|
| Two unnamed definitions list the item | The one whose id sorts first. The other one is shadowed. |
| A named definition lists the item and the stack carries its name | The named definition. |
| Two named definitions share a name | The one whose id sorts first. |
| A named definition lists the item and the stack has no name, or another name | The vanilla model. No unnamed definition is used for that item. |
| No definition lists the item | The vanilla model. |
There are four more ways to change how one model part looks, and none of them needs a second file:
| You want | Use | Read |
|---|---|---|
| A different clip in water, rain, at night or in a biome | Several idle entries in model, each with a condition | Item clips and Conditions |
| A different texture or geometry for what a bucket holds | dynamic_ | Dynamic textures |
| Another geometry, or other keys, while you use the item or cast a rod | state_ | Model part definitions |
| Extra particles while the item has certain enchantments | enchantment_ in a compat file | Enchantment variants below |
Make two presets and switch between them
You will add two presets to the lantern pack, a spark version and a calm version, and then change which one shows by renaming a folder. Nothing else changes: the presets use the same geometry, texture and clips as the base lantern.
Model parts draw only in first person. In third person the item keeps its vanilla model, so switch the camera to first person whenever you test a preset.
- In your pack, open
assets/minecraft/punchy/model_parts_items/definitions. The baselantern.jsonfrom the definitions page is in it. - Make a folder
a_sparkand save the first file below in it aslantern.json. - Make a folder
b_calmand save the second file below in it aslantern.json. - Press F3+T in a world, then hold a lantern in first person. The ids sort as
a_spark, thenb_calm, then the baselantern.json, so the spark preset wins. Its crit particles are small and the arm covers part of the lantern, so the Studio check below is the surest way to see which preset Punchy! picked. - Rename the folder
a_sparktoz_sparkand reload with F3+T. Nowb_calmis first, so Punchy! draws the calm preset, which has no blur halo around the flame and no particles. You may not be able to tell the two apart in first person, so check the pick in Studio as well. - Rename
b_calmtoz_calmand reload. The ids now sort as the baselantern.json, thenz_calm, thenz_spark, so the base lantern with its smoke is back.
The spark preset, definitions/a_spark/lantern.json:
{
"items": ["minecraft:lantern", "minecraft:soul_lantern"],
"geo": "minecraft:punchy/model_parts_items/geo/lantern.geo.json",
"texture": "minecraft:punchy/model_parts_items/textures/lantern",
"animations": [
"minecraft:punchy/model_parts_items/animations/lantern.animation.json"
],
"modelPartsAnimation": [
{ "type": "idle", "name": "lantern_sway" },
{
"type": "idle",
"name": "lantern_still",
"inside_water": true,
"disable_all_particles": true,
"skip_blend_in": true,
"skip_blend_out": true
},
{ "type": "attack", "name": "lantern_swing" }
],
"bone_emission": { "strength": 100, "blur": true, "flame": 100 },
"particles": [
"particle(type=minecraft:crit, bone=flame, rate=6, life=0.5, size=0.02, velocity=0:0.02:0)"
]
}
The calm preset, definitions/b_calm/lantern.json. It sets the flame glow to 40 and leaves blur off, so the flame has no halo around it, and it has no particles at all:
{
"items": ["minecraft:lantern", "minecraft:soul_lantern"],
"geo": "minecraft:punchy/model_parts_items/geo/lantern.geo.json",
"texture": "minecraft:punchy/model_parts_items/textures/lantern",
"animations": [
"minecraft:punchy/model_parts_items/animations/lantern.animation.json"
],
"modelPartsAnimation": [
{ "type": "idle", "name": "lantern_sway" },
{
"type": "idle",
"name": "lantern_still",
"inside_water": true,
"skip_blend_in": true,
"skip_blend_out": true
},
{ "type": "attack", "name": "lantern_swing" }
],
"bone_emission": { "flame": 40 }
}
Video coming soon
Check who wins in Punchy! Studio
You do not have to guess the order. Studio lists it.
- Join a world, hold a lantern, switch to first person and press F6. That is the default key for Open Animation Editor under Punchy Studio in the key binds. If the editor opens in the Third Person perspective, pick First Person with the switch between the menus and the workspace tabs.
- Open the Model workspace, then choose File > Open Model Part… (Ctrl+O).
- In the Model Parts Library, stay on Resource Packs and type
lanternin Search definitions and items. - Select each definition. The rows share the name
lantern, so read the first line of the detail pane: it shows the full id with the folder. The pane’s entry forminecraft:lanternsays rendered, shadowed by another definition, blocked by the named definition, or never matches. A definition Punchy! throws away is marked dropped by Punchy, with the reason.
Video coming soon
Keep a preset small
A preset only needs to differ in the keys that make it different. Everything else stays the same text, so point it at the files the base already uses:
geo,textureandanimationsname the base’s files by id. Do not copy the geometry or the texture into the preset’s folder: a definition loads its files by the exact id you write, wherever they sit.- Change only what the preset is about. The keys that usually differ are
particles,bone_emission,bone_texture_anim,bone_textures(a different texture on one bone),modelPartsAnimationanddisplay. - Keep the same file name in every preset folder, here
lantern.json, so the folder is the only thing that tells them apart.
A model part you make in Studio exports with its own geometry, texture and clips, named after its File Name in the Definition tab. To share one set of files between presets, open the exported definition in a text editor, point geo, texture and animations at the base files, and delete the copies.
Ship presets to players
The active preset is whichever definition wins, so a player’s choice has to come from the files. Pick the way that suits your pack:
- A folder to rename. Ship the presets in subfolders of
definitionswith sort prefixes like the ones in the steps above (a_,b_andz_), and tell players to put0_in front of the folder they want and reload. Numbers sort before letters, so a0_folder beats the rest. It is the same idea as the steps above, with a different prefix. - A parked folder. Keep inactive presets in a folder beside
definitions, such asassets/minecraft/punchy/model_parts_items/presets/spark/lantern.json. Punchy! reads the files underdefinitions, so anything inpresetsis never loaded. To switch, the player copies a preset file overdefinitions/lantern.json. - A small pack per preset. Make each preset its own resource pack with one file in it, at the same path as the base:
assets/minecraft/punchy/model_parts_items/definitions/lantern.json. A player turns the preset pack on above the base pack in Options…, then Resource Packs…, and Minecraft uses the file from the pack that is higher in the list. This is the one choice a player can make without opening a folder.
In Studio, the Export First in Order switch in the Definition tab (and in the export dialog) writes the definition to definitions/0_punchy_studio/. Use it when your preset has to beat a definition from another pack.
Variants chosen by the item’s name
A named definition is the one variant a player can pick in game: renaming an item on an anvil switches the model. You will give the lantern two named looks, one for a lantern renamed Sun Lantern and one for Moon Lantern.
Do this in a copy of the pack. A named definition shuts out every unnamed definition for its item, so your plain lantern.json and the presets stop answering for lanterns.
- In
definitions, make a foldernames. The folder means nothing to Punchy!. It only keeps the files together and sorts them. - Save the first file below as
definitions/names/sun_lantern.json. - Save the second file below as
definitions/names/moon_lantern.json. - Reload with F3+T, then give yourself a lantern with
/give @s minecraft:lantern. - Hold it. It draws as the plain vanilla lantern, because named definitions cover lanterns and this stack has no name.
- Rename it to
Sun Lanternon an anvil and hold it again. Punchy! now draws the lantern model from your pack, not the vanilla lantern, usingsun_lantern.json. Rename another lantern tomoon lantern: capital letters and spaces at the ends do not matter, somoon_lantern.jsondraws. The two files differ in the flame glow (100 with a blur halo for the sun, 35 with no blur for the moon) and in the particles (flame for the sun, end rod for the moon), but the two models look alike in daylight, so tell them apart by the name you gave.
definitions/names/sun_lantern.json:
{
"items": ["minecraft:lantern"],
"customName": "Sun Lantern",
"geo": "minecraft:punchy/model_parts_items/geo/lantern.geo.json",
"texture": "minecraft:punchy/model_parts_items/textures/lantern",
"animations": [
"minecraft:punchy/model_parts_items/animations/lantern.animation.json"
],
"modelPartsAnimation": [
{ "type": "idle", "name": "lantern_sway" },
{ "type": "attack", "name": "lantern_swing" }
],
"bone_emission": { "strength": 100, "blur": true, "flame": 100 },
"particles": [
"particle(type=minecraft:flame, bone=flame, rate=4, life=0.6, size=0.03)"
]
}
definitions/names/moon_lantern.json:
{
"items": ["minecraft:lantern"],
"customName": "Moon Lantern",
"geo": "minecraft:punchy/model_parts_items/geo/lantern.geo.json",
"texture": "minecraft:punchy/model_parts_items/textures/lantern",
"animations": [
"minecraft:punchy/model_parts_items/animations/lantern.animation.json"
],
"modelPartsAnimation": [
{ "type": "idle", "name": "lantern_sway" },
{ "type": "attack", "name": "lantern_swing" }
],
"bone_emission": { "flame": 35 },
"particles": [
"particle(type=minecraft:end_rod, bone=flame, rate=2, life=1.2, size=0.02)"
]
}
Video coming soon
A few things follow from the rule:
- The stack’s custom name is compared, not its hover text or lore. The text is trimmed and compared without letter case.
nameworks as an alias: when a definition has nocustomNamekey, itsnamekey does the same job. UsecustomNamein your own files so the intent is clear.- The soul lantern is untouched here, because neither named file lists it. Any unnamed definition that lists
minecraft:soul_lanternstill draws for it. - An unnamed lantern model cannot sit next to named ones. Name every look you want, as in Match a renamed item.
- In Studio, the Definition tab has a Custom Name field in the Items panel.
Enchantment variants
An enchantment variant adds particles while the held item has certain enchantments. It lives in a compat file, and it works on any item, with or without a model part. You will make a diamond sword that crackles on every swing, burns when it has Fire Aspect, and puffs clouds when it has Knockback or Sweeping Edge.
A model part definition can hold an enchantment_variants list of its own, which changes keys of that definition, such as its texture, while the item has the enchantments. Punchy! 3.0 applies that list only on Minecraft 1.21.11. On every other version it is read and does nothing, so use the compat file below.
- In your pack, create the folder
assets/minecraft/punchy/compat/. - Save the file below as
sword_enchants.jsonin it. - Join a world, run
/give @s minecraft:diamond_sword, hold it in first person and swing it. Crit particles appear at the sword on every swing. - Run
/enchant @s minecraft:fire_aspect 1and swing again. Flames join the crit particles. - Run
/enchant @s minecraft:sharpness 3and swing. Soul fire flames join too, because the second variant needs both enchantments. - Give yourself a new sword and run
/enchant @s minecraft:knockback 1. Clouds appear, because the third variant needs only one of its two enchantments.
{
"itemSpecific": {
"minecraft:diamond_sword": {
"kind": "SWORD",
"particle_emitters": [
"particle(type=minecraft:crit, target=item_center, trigger_attacking=true, count=2, life=0.4, size=0.05)"
],
"enchantment_variants": [
{
"enchantments": ["minecraft:fire_aspect"],
"particle_emitters": [
"particle(type=minecraft:flame, target=item_center, trigger_attacking=true, count=4, life=0.6, size=0.06)"
]
},
{
"enchantments": [
"minecraft:fire_aspect",
{ "id": "minecraft:sharpness", "min_level": 3 }
],
"priority": 1,
"particle_emitters": [
"particle(type=minecraft:soul_fire_flame, target=item_center, trigger_attacking=true, count=4, life=0.6, size=0.06)"
]
},
{
"enchantments": ["minecraft:knockback", "minecraft:sweeping_edge"],
"match": "any",
"priority": 2,
"particle_emitters": [
"particle(type=minecraft:cloud, target=item_center, trigger_attacking=true, count=3, life=0.5, size=0.05)"
]
}
]
}
}
}
What each swing fires, by what the sword carries:
| The sword has | Emitters that fire on a swing |
|---|---|
| No enchantments | crit |
| Fire Aspect | crit, flame |
| Fire Aspect and Sharpness 3 or more | crit, flame, soul fire flame |
| Sharpness 5 only | crit |
| Knockback or Sweeping Edge | crit, cloud |
How Punchy! builds that list:
- It starts with the entry’s own emitters, here the crit.
- It adds the emitters of every variant that matches, from the lowest
priorityto the highest. Two variants with the same priority keep the order of the file. - An emitter written twice with the same text counts once.
- It checks the held stack again every frame, so taking an enchanted sword out of your hand changes the particles at once.
- When a variant matches, the entry’s list replaces the emitters of the item’s group in
item. The group’s emitters are not added on top. - The emitters draw in first person.
On an item that has a model part, an emitter can name a bone, as bone=flame does on the lantern, and the particles come out of that bone. Without a model part, use target=item_center. Particles explains every emitter key.
A variant lives in an itemSpecific entry, and an entry can be for one renamed item. Write the key minecraft:diamond_sword#fancy with "renamed": "Fancy sword", and only swords with that name use that entry and its variants. Compat rules explains the key.
Make it in Punchy! Studio
- Join a world, hold a diamond sword, switch to first person and press F6 (or the key you set for Open Animation Editor). If the editor opens in the Third Person perspective, pick First Person with the switch between the menus and the workspace tabs.
- Open the Bindings workspace with Ctrl+B. Select your destination pack in the Rules outliner and press New Compat File. In the dialog, double-click File Name to select the
my_rules.jsonalready in it, typesword_enchantsand press New Compat File. Studio adds.jsonand selects the new file. On export it writes the file toassets/minecraft/punchy/compat/in that pack. - With the new file selected, press Edit as Text. A new file is empty and has no
itemSpecificsection yet, so write the entry by hand:{ "itemSpecific": { "minecraft:diamond_sword": {} } }. Press Ctrl+Enter to Apply the text. - Select the
minecraft:diamond_swordtarget underitemSpecific, open the Enchantment Variants panel and press Add Variant. A new variant asks for Sharpness. - In the variant’s first row, replace
minecraft:sharpnesswithminecraft:fire_aspect. That box is Enchantment, and the two small boxes after it are Lowest Level and Highest Level (they read 1 and any until you type, and hovering a box shows its name). Use them for a range, Add Enchantment for a second requirement, and the Match and Priority fields as in the table below. - In Variant 1 Emitters, press Add Emitter. A new emitter is a flame particle at the item’s center. A variant without an emitter is dropped, and Studio says so in the panel.
- In the emitter’s Timing and Triggers panel, tick Attacking. An emitter with no trigger fires all the time.
- Press Ctrl+Enter to Apply, then Ctrl+E to export. Hold the enchanted sword and swing it.
Once a file has an itemSpecific section, Add Target on that section adds further items to it.
Video coming soon
Keys of an enchantment variant
| Key | Type | Default | What it does | Example |
|---|---|---|---|---|
enchantment_ | list | The variants of this entry. Also written enchantment. Within one entry every variant is kept, and each matching variant adds its emitters. When two compat files give the same item entry, variants with the same enchantments text and the same match merge into one. | [ { ... }, { ... } ] | |
enchantmentsRequired | list | What the held item must carry. Each element is an enchantment id, or an object with id, min_level and max_level. A value that is not a list, or a list with no valid id, drops the variant. | ["minecraft: | |
match | string | all | any, in any letter case, applies the variant when one listed enchantment matches. Any other value, or none, needs every one of them. | |
priority | integer | 0 | The order the matching variants add their emitters, lowest first. It never decides whether a variant matches. | 2 |
particle_Required | emitter, text or list | The emitters this variant adds, in the three ways to write an emitter. Punchy! also reads particle, particle, particles, particle_, particle, particle_ and particle here. A variant with no emitter is dropped. |
| Key | Type | Default | What it does | Example |
|---|---|---|---|---|
idRequired | enchantment id | The enchantment, such as minecraft:. The namespace is optional: sharpness reads as minecraft:. A plain text element instead of an object is an id that needs level 1 or more. | "minecraft: | |
min_level | integer | 1 | The lowest level that counts. Also minLevel. A negative number becomes 0, and 0 matches an item that does not carry the enchantment at all. | 3 |
max_level | integer | no limit | The highest level that counts. Also maxLevel. A negative number means no limit. | 5 |
A level has to be a JSON number. A level written as text, such as "3", is ignored and the default is used.
Why my variant does not show
- Two definitions for one item. Only the one whose id sorts first draws, and the other is shadowed. That is normal. Open the Model Parts Library in Studio to see which one wins.
- A mistake drops the first preset, and the next one draws. A definition with no valid item,
geoortextureis thrown away without a message, so the next definition in the order takes over and looks like a wrong choice. A definition that points at a geometry file that does not exist stays, still wins and draws nothing, so the vanilla model shows and the presets after it never get a turn. - The folder is not under
definitions. Punchy! reads the.jsonfiles undermodel_parts_items/definitions. Only when that folder holds no files does it fall back to any.jsonundermodel_parts_itemswhose path contains/definitions/. A preset inmodel_parts_items/presetsis never loaded. A folder calledpresetsinsidedefinitionsis loaded. - A capital letter or a space in a name. Minecraft resource ids allow only lower case letters, digits,
_,-and.(plus/between folders). Keep every file and folder name underdefinitionsto those characters, because a name with a capital letter or a space is not a valid id. - A field with the wrong JSON type. Some fields with the wrong JSON type make Punchy! drop the whole definition without a message, such as
items,animationsormodelPartsAnimationthat is not a list,displaythat is not an object, or a field of an animation entry that holds a list or an object where one value belongs. The next definition in the order takes over. Check each key against the tables in Model part definitions. - You are testing in third person. Model parts draw only in first person, so a preset never shows in third person. Switch the camera to first person.
- A named definition covers the item. An unnamed stack gets the vanilla model, even though an unnamed definition lists it. See Variants chosen by the item’s name.
- A blank custom name.
"customName": ""is ignored, and the definition counts as unnamed. Thenamekey is not tried in its place.nameis read only when thecustomNamekey is missing. - A tag in
items. A definition that lists#minecraft:swordscompetes for every sword. It can shadow a preset made for one sword. - The same path in two packs. Minecraft hands Punchy! only the file of the higher pack. The file in the lower pack never loads, so it cannot act as a second variant.
- An enchantment variant that does nothing. Check these in order. The key is in a compat file, in an
itemSpecificentry.enchantmentsis a list. At least one id in it is real; a bare id such assharpnessreads asminecraft:sharpness, so the namespace is optional. The variant has an emitter, and the emitter has a trigger that fires. Amin_levelof 0 matches every item, so use 1 or more. See Compat rules for what drops a whole compat file. - No reload. Press F3+T after every change.
Related pages
- Model part definitions has every key of a definition and the full rule for which one covers an item.
- Resource packs shows how pack order and id order work together.
- Particles explains every emitter key, trigger and glow setting.
- Compat rules holds the
itemSpecificentries that carry enchantment variants. - Item clips and Conditions pick a clip by water, weather, time and biome inside one definition.
- Dynamic textures swaps a texture or geometry by what a bucket holds.
- Model parts is the overview of the whole system.
Last checked against the mod on 29 October 2026.