Skin Files
Skin Files
Each .yml file in configs/skins/ defines one skin. A single skin can support one or multiple item and armor pieces.
If you are new to SkinEngine, it helps to think of a skin file as the place where you answer four questions:
- What is this skin called?
- Where are its resource files stored?
- Which item categories does it support?
- What special behavior does each category need?
The plugin then reads that file, validates every referenced path, and builds the final resource-pack data from it.
The mental model
A skin file has three main parts:
id- identifies the skindisplay- controls how it looks in the GUIcontent- tells SkinEngine which item types exist and which files belong to them
For skins for swords, maces, tridents, axes, pickaxes, shovels, hoes, spears, bows, crossbows, fishing rods, shields, and elytras:
content:
items:
<your items here>
For armor-focused skins, the armor bundle usually lives under:
content:
armor:
layer_1: ...
layer_2: ...
items:
<your armor here>
Beginner example
This is only a reference example. For full examples, see Example Custom Pack.
[!TIP] We also have free pre-made SkinEngine packs you can use as a starting point for your own packs. Browse Packs
This example shows the actual structure SkinEngine expects:
id: "lunar"
display:
name: "<#9fd3ff>Lunar</#9fd3ff>"
description:
- "<gray>A clean blue-themed weapon and armor skin.</gray>"
- "<dark_gray>Includes melee, ranged, shield, elytra, and armor support.</dark_gray>"
content:
folder: "lunar"
items:
sword:
materials:
- iron
- diamond
- netherite
type: generate
cost: 500
particle: CRIT
resources:
main: "sword.png"
mace:
type: generate
resources:
main: "mace.png"
trident:
resources:
main: "trident.json"
throwing: "trident_throwing.json"
spear:
materials:
- wooden
- iron
- diamond
type: generate
resources:
main: "spear.png"
bow:
type: generate
resources:
main: "bow.png"
pulling:
- "bow_pulling_0.png"
- "bow_pulling_1.png"
- "bow_pulling_2.png"
shield:
resources:
main: "shield.json"
blocking: "shield_blocking.json"
elytra:
cost: 900
particle:
effect: END_ROD
resources:
main: "elytra.png"
broken: "elytra_broken.png"
wings: "elytra_wings.png"
armor:
layer_1: "armor_layer_1.png"
layer_2: "armor_layer_2.png"
particle:
effect: DUST
data:
color: "#9fd3ff"
size: 1.0
items:
helmet:
materials: "all"
resources:
main: "helmet.png"
chestplate:
materials: "all"
resources:
main: "chestplate.png"
leggings:
materials: "all"
resources:
main: "leggings.png"
boots:
materials: "all"
resources:
main: "boots.png"
Main fields
id
This is the unique skin id. Every skin in the same pack needs its own id.
[!TIP] Keep it simple. Use English letters, numbers, and
_.
id: "lunar"
display.name
This is the visible skin name in the GUI. It supports MiniMessage formatting.
display:
name: "<#9fd3ff>Lunar</#9fd3ff>"
display.description
This is the description shown in the GUI. Your players can see it, so write it with them in mind.
Good descriptions usually:
- tell the player what the skin theme is
- stay short and do not overcomplicate it
- avoid listing every supported item type there
display:
description: "<white>This is my awesome Lunar skin!</white>"
content.folder
This tells SkinEngine where the actual resource files for this skin are stored.
[!TIP] We recommend leaving this as
"{id}"because it makes skins easier to keep organized in separate, easy-to-identify folders.
Example:
content:
folder: "{id}"
For id: "lunar", that resolves to:
/plugins/SkinEngine/packs/<pack_id>/resourcepack/skins/lunar/
Important rules:
{id}is supported and is often the cleanest option- the folder must stay inside the current pack
- the folder must actually exist, so create it yourself
content.items
Use content.items for normal item categories:
swordmacetridentaxepickaxeshovelhoespearbowcrossbowshieldfishing_rodelytra
Each entry tells SkinEngine:
- which materials are allowed
- which resource type is used
- which main file is used
- whether there are extra state files
- whether that category has a cost
- whether that category emits particles
elytra also uses content.items, but it has one extra rule: it needs a separate resources.wings texture for the actual elytra wings shown on the player's back.
content.armor
Use content.armor for armor skins.
That block does two things:
- define the shared armor textures with
layer_1andlayer_2 - define armor item entries under
content.armor.items
Recommended structure:
content:
armor:
layer_1: "armor_layer_1.png"
layer_2: "armor_layer_2.png"
items:
helmet:
materials: "all"
resources:
main: "helmet.png"
chestplate:
materials: "all"
resources:
main: "chestplate.png"
leggings:
materials: "all"
resources:
main: "leggings.png"
boots:
materials: "all"
resources:
main: "boots.png"
If the skin contains armor categories but the armor textures are missing or invalid, SkinEngine removes those armor entries from the final skin.
materials
materials decides which real vanilla materials can use that item entry.
Supported behavior:
- omitted or
allmeans every valid material in that category - materials like
wood,stone,iron,gold,diamond,netheritefor tools (sword, axe, pickaxe, shovel, hoe) - materials like
wood,stone,iron,gold,diamond,netheritefor spears - materials like
leather,chainmail,iron,gold,diamond,netheritefor armor (helmet, chestplate, leggings, boots) - material
copperis supported for tool and armor categories if your server's Minecraft version is1.21.9+ spearitems themselves require Minecraft/Paper1.21.11+, regardless of materialcoppercan also be used forspearonce both conditions are true: the server supportscoppermaterials (1.21.9+) andspearexists (1.21.11+,COPPER_SPEAR)- direct Bukkit material names like
DIAMOND_SWORD
Examples:
sword:
materials: "all" # supports all available sword materials
axe:
materials: # supports the following axe materials:
- iron
- diamond
- netherite
helmet:
materials: # supports the following helmet materials:
- LEATHER_HELMET
- CHAINMAIL_HELMET
- DIAMOND_HELMET
[!INFO] Items like
bow,mace,trident,crossbow,fishing_rod,shield, andelytradon't support materials because each one maps to its own single vanilla base item.
type
Supported values are:
generatemodel
For beginners, the simple rule is:
- use
generatewhen the resource is a PNG - SkinEngine will automatically generate a 2D item model from the texture - use
modelwhen the resource is a JSON model - this allows you to create custom, 3D item models for your items/helmets
[!WARNING] Item
shieldalways uses model. You have to provide .json files for shields.
[!WARNING] Item
tridentalways uses model. You have to provide a.jsonfile forresources.main, andresources.throwingis optional.
[!INFO] Item
elytraalways uses generate. The main item texture comes fromresources.main, and the wing texture comes fromresources.wings.
For elytra, the resource roles are:
resources.main= the elytra item as it appears in inventories, hotbars, slots, and normal item renderingresources.wings= the opened elytra wings texture used on the player's back while wearing itresources.broken= an optional alternate item texture for the broken vanilla elytra item state when durability is depleted
[!INFO] Armor pieces for
chestplate,leggings,bootsalways use generate - Minecraft currently doesn't support custom models for armor, except for helmets, so they are generated automatically from the armorlayer_1andlayer_2textures.
Extremely important note for the model type:
If your resource is a .json model, open the model .json file and make sure all referenced textures and parent models inside of it are NOT namespaced.
SkinEngine will not allow you to reference textures and models that exist outside the skin folder itself:
- This means that ALL resources, including your
.pngtextures,.jsonmodels or.png.mcmetaanimations must exist at the same place - This place is your
content.folderid for this skin
If you are confused, take a look at the Pack Structure skins example to see how it should look like.
Good examples:
No namespaces (meaning that the texture like crossbow_2.png exists next to this .json file)
{"texture_size":[20,20],"textures":{"2":"crossbow_2","3":"animations_1","4":"animations_2","particle":"crossbow_2"},"elements":[{...}]
Namespace minecraft: is allowed (SkinEngine can get default Minecraft game assets and use them)
{"texture_size":[20,20],"textures":{"1":"minecraft:item/arrow"},"elements":[{...}]
Bad example:
Custom namespaces like my_custom_namespace: are NOT allowed (this tells SkinEngine to look outside the skin folder, which will get rejected)
{"texture_size":[20,20],"textures":{"1":"my_custom_namespace:some_texture"},"elements":[{...}]
resources
Current skin files use resources.*, not the older flat resource field.
resources.main
This is the main file for the item entry.
It is required for every item entry.
Examples:
sword:
type: generate
resources:
main: "sword.png"
shield:
resources:
main: "shield.json"
State resources
Some item types support extra resource states:
pullingforbowandcrossbowchargedforcrossbowfireworkforcrossbowblockingforshieldcastforfishing_rodthrowingfortridentbrokenforelytrawingsforelytra
Example:
crossbow:
type: generate
resources:
main: "crossbow.png"
pulling:
- "crossbow_pulling_0.png"
- "crossbow_pulling_1.png"
- "crossbow_pulling_2.png"
charged: "crossbow_charged.png"
firework: "crossbow_firework.png"
trident:
resources:
main: "trident.json"
throwing: "trident_throwing.json"
elytra:
resources:
main: "elytra.png"
broken: "elytra_broken.png"
wings: "elytra_wings.png"
Those state files are optional, but if you define them they must exist inside the chosen content.folder.
For elytra, resources.wings is the one exception: SkinEngine treats it as required for a valid elytra skin. If you leave it out, the plugin falls back to elytra_wings.png, which still has to exist in the skin folder.
For clarity:
resources.mainis still the normal item textureresources.wingsis not the inventory item, it is the worn elytra wings textureresources.brokenis fully optional and only affects the broken inventory item state
cost
cost is optional and is defined per item entry.
Example:
sword:
cost: 500
SkinEngine accepts non-negative values. Decimal support depends on the configured economy provider.
Particles
Particles are optional and can be defined:
- on a normal item entry with
particle - on the armor bundle with
content.armor.particle
Examples:
sword:
particle: CRIT
content:
armor:
particle:
effect: DUST
data:
color: "#9fd3ff"
size: 1.0
Full runtime details are documented here:
How to build a skin file safely
If you are making your first skin, build it in this order:
- write
id - add
display.nameanddisplay.description - set
content.folder - add one item entry with
resources.main - confirm the file paths exist
- reload and run
/se zip - only then add special states, costs, armor, or particles
That order makes mistakes much easier to debug.