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:

  1. What is this skin called?
  2. Where are its resource files stored?
  3. Which item categories does it support?
  4. 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 skin
  • display - controls how it looks in the GUI
  • content - 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:

  • sword
  • mace
  • trident
  • axe
  • pickaxe
  • shovel
  • hoe
  • spear
  • bow
  • crossbow
  • shield
  • fishing_rod
  • elytra

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_1 and layer_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 all means every valid material in that category
  • materials like wood, stone, iron, gold, diamond, netherite for tools (sword, axe, pickaxe, shovel, hoe)
  • materials like wood, stone, iron, gold, diamond, netherite for spears
  • materials like leather, chainmail, iron, gold, diamond, netherite for armor (helmet, chestplate, leggings, boots)
  • material copper is supported for tool and armor categories if your server's Minecraft version is 1.21.9+
  • spear items themselves require Minecraft/Paper 1.21.11+, regardless of material
  • copper can also be used for spear once both conditions are true: the server supports copper materials (1.21.9+) and spear exists (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, and elytra don't support materials because each one maps to its own single vanilla base item.

type

Supported values are:

  • generate
  • model

For beginners, the simple rule is:

  • use generate when the resource is a PNG - SkinEngine will automatically generate a 2D item model from the texture
  • use model when the resource is a JSON model - this allows you to create custom, 3D item models for your items/helmets

[!WARNING] Item shield always uses model. You have to provide .json files for shields.

[!WARNING] Item trident always uses model. You have to provide a .json file for resources.main, and resources.throwing is optional.

[!INFO] Item elytra always uses generate. The main item texture comes from resources.main, and the wing texture comes from resources.wings.

For elytra, the resource roles are:

  • resources.main = the elytra item as it appears in inventories, hotbars, slots, and normal item rendering
  • resources.wings = the opened elytra wings texture used on the player's back while wearing it
  • resources.broken = an optional alternate item texture for the broken vanilla elytra item state when durability is depleted

[!INFO] Armor pieces for chestplate, leggings, boots always use generate - Minecraft currently doesn't support custom models for armor, except for helmets, so they are generated automatically from the armor layer_1 and layer_2 textures.

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 .png textures, .json models or .png.mcmeta animations must exist at the same place
  • This place is your content.folder id 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:

  • pulling for bow and crossbow
  • charged for crossbow
  • firework for crossbow
  • blocking for shield
  • cast for fishing_rod
  • throwing for trident
  • broken for elytra
  • wings for elytra

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.main is still the normal item texture
  • resources.wings is not the inventory item, it is the worn elytra wings texture
  • resources.broken is 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:

  1. write id
  2. add display.name and display.description
  3. set content.folder
  4. add one item entry with resources.main
  5. confirm the file paths exist
  6. reload and run /se zip
  7. only then add special states, costs, armor, or particles

That order makes mistakes much easier to debug.