> For the complete documentation index, see [llms.txt](https://edseries-plugins.gitbook.io/p/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://edseries-plugins.gitbook.io/p/pinnaduels/setting-up/custom-textures.md).

# Custom Textures & Resource-Pack Menus

The duel menus are PinnaPrison GUI files (`plugins/PinnaPrison/guis/pinnaduels/`), so they can look like anything your resource pack can draw: a full picture as the background, your own icons on every button, custom tooltip frames, and live numbers (ELO, rank, queue size...) written with your own digits right on the background. This page shows how.

## How it fits together

A resource-pack menu is still a normal chest menu, built from three layers:

1. **The background**: a picture from your pack, placed in the menu **title**.
2. **The buttons**: menu items that wear your pack's models and tooltip frames.
3. **Live numbers**: digits from your pack written into the title by PinnaDuels' `_glyphs` placeholders, plus models or stack sizes on the items.

The server only sends the title and the items. The pack on the player's game does the drawing, so every player needs your pack loaded. Players without it see vanilla items and unreadable characters in the title.

## 1. The background picture

A menu title is text, and text can show font images ("glyphs") from your pack. A glyph as large as the chest window covers the vanilla texture and becomes the background.

```yaml
# plugins/PinnaPrison/guis/pinnaduels/duels.yml
title: '&f:offset_-18::duels_main:'
rows: 5
```

| Part           | What it does                                                                                                                                                                                                                                                                                              |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `&f`           | Makes the title white. Title text is dark grey by default and glyphs take the colour of the text, so without `&f` the picture (and your digits) look dark.                                                                                                                                                |
| `:offset_-18:` | Moves the text cursor 18 pixels to the left. The title starts 8 pixels in from the left edge of the window, so the picture needs a negative offset to start at the edge. The right number depends on how your picture was drawn: change it one pixel at a time until the picture lines up with the slots. |
| `:duels_main:` | The picture itself (here an ItemsAdder font image called `duels_main`).                                                                                                                                                                                                                                   |

Set `rows` to the menu height your picture was made for.

### Writing glyphs for your pack plugin

| Pack made with | Picture                                                                                                                         | Offset                                                     |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| ItemsAdder     | `:name:`, or `%img_name%` through PlaceholderAPI                                                                                | `:offset_-18:` (or `%img_offset_-18%`)                     |
| Nexo or Oraxen | the glyph's PlaceholderAPI placeholder (for example `%nexo_<glyph-id>%` or `%oraxen_<glyph-id>%`), or the glyph's own character | the plugin's shift placeholder or character (see its docs) |
| Your own pack  | the character you gave the picture in your font file                                                                            | a character of a `space` provider with a negative width    |

Menu titles use `&` colour codes, not MiniMessage, so tags such as `<glyph:...>` or `<shift:...>` are shown as plain text. Use the PlaceholderAPI form or the raw character instead (PlaceholderAPI must be installed for `%...%`).

### Using your own font

If you make the pack yourself, add the picture and a few negative spaces to a font, for example `assets/minecraft/font/default.json`. Use characters from Unicode's private use area, which no language uses: here U+E000 for the picture and U+F801, U+F808 and U+F810 for spaces of -1, -8 and -16 pixels.

In the examples below, `<U+E000>` stands for that one character. In the JSON file write it as a JSON escape (a backslash, the letter `u` and the four hex digits `E000`), or paste the character itself.

```json
{
  "providers": [
    { "type": "space", "advances": { "<U+F801>": -1, "<U+F808>": -8, "<U+F810>": -16 } },
    { "type": "bitmap", "file": "mypack:gui/duels_main.png", "ascent": 13, "height": 204, "chars": ["<U+E000>"] }
  ]
}
```

The picture goes in `assets/mypack/textures/gui/duels_main.png`. `height` is the height the picture is drawn at (204 = a 5-row chest window, 114 pixels plus 18 per row) and `ascent` how far it reaches above the title line (13 puts its top at the top of the window). `ascent` must never be larger than `height`, or the game ignores the whole font.

In the menu file, write the same escapes inside a double-quoted YAML string (YAML only reads escapes between double quotes), or paste the characters. -16, -1 and -1 make the same 18 pixel offset as `:offset_-18:`:

```yaml
title: "&f<U+F810><U+F801><U+F801><U+E000>"
```

## 2. Button textures

Menu items use PinnaPrison's item format. These are the keys that matter for a pack:

| Key                 | Use                                                                                                                                                                                                                                                                                                                                            |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `material`          | A vanilla material (`PAPER`...) or an item of your pack plugin: `itemsadder:<namespace>:<id>`, `nexo:<id>`, `oraxen:<id>`. Pack plugin items bring their own model, so they need no `custom-model-data`. `texture-<base64>` makes a custom head and `head-<player>` / `head-{player}` a player's head. An unknown material shows as a barrier. |
| `custom-model-data` | The model number your pack gives that material, e.g. `20030`. Tokens and placeholders work here too. `-1` or empty means none.                                                                                                                                                                                                                 |
| `tooltip-style`     | A tooltip frame from your pack, `namespace:id` (Minecraft 1.21.2+).                                                                                                                                                                                                                                                                            |
| `hide-tooltip`      | `true` shows no tooltip at all on hover (1.20.5+). The item can still be clicked.                                                                                                                                                                                                                                                              |
| `glow`              | The enchant shimmer, without a visible enchant.                                                                                                                                                                                                                                                                                                |
| `color`             | Tint for leather armour and potions: `'#RRGGBB'` or `'R,G,B'`.                                                                                                                                                                                                                                                                                 |

PinnaPrison menus have no `item-model` key: choose the model with `custom-model-data`, or use an item of your pack plugin as `material`. These keys work in the item sections of the PinnaDuels items too (`queued-item`, `no-tokens-item`, `empty-item`) and in the entries and page arrows of the lists.

### Custom model data

The number is read by the material's model in your pack. On Minecraft 1.21.4+ that is the item definition (for paper: `assets/minecraft/items/paper.json`, usually a `range_dispatch` on `custom_model_data`); older versions use `overrides` in `assets/minecraft/models/item/paper.json`. ItemsAdder, Nexo and Oraxen write these files for you: look up the number they gave your item, or use the item's id as `material`.

### Tooltip frames

`tooltip-style: 'mypack:gold'` uses `assets/mypack/textures/gui/sprites/tooltip/gold_background.png` and `gold_frame.png` from your pack (with `.png.mcmeta` files that set nine-slice scaling, like the vanilla tooltip). Placeholders work here too.

### Invisible items

A common trick is to draw the buttons into the background picture and put an invisible item on each button slot. Give those items a model with a fully transparent texture (a `custom-model-data` number your pack maps to an empty model). Add `hide-tooltip: true` to slots that should show nothing on hover, and leave it out on buttons so players can still read their name and lore.

### A full button

The ranked queue button with its own icon and frame for each state: ready to queue, waiting in the queue, and out of Duel Tokens.

```yaml
  queue:
    custom-item:
      type: 'pinnaduels-queue'
      # while the player waits in the queue
      queued-item:
        material: PAPER
        custom-model-data: 20031
        glow: true
        tooltip-style: 'mypack:rare'
        name: '&b&lSearching for a rival...'
        lore:
          - '&7Waiting for &f{waited}'
          - ''
          - '&cClick to leave the queue'
      # no Duel Tokens left
      no-tokens-item:
        material: PAPER
        custom-model-data: 20032
        tooltip-style: 'mypack:locked'
        name: '&c&lNo Duel Tokens'
        lore:
          - '&7Mine &f{next-token} &7more blocks for the next one.'
    slot: '22'
    update-interval: 20
    # ready to queue
    material: PAPER
    custom-model-data: 20030
    tooltip-style: 'mypack:gold'
    click-sound: 'UI_BUTTON_CLICK'
    name: '&a&lRanked Duel'
    lore:
      - '&7Tokens: &f{tokens}&7/&f{tokens-max}'
      - '&7In the queue: &f{queue}'
      - ''
      - '&aClick to join the queue'
```

The profile item (`pinnaduels-profile`) gives a `PLAYER_HEAD` the player's skin; give it `material: PAPER` and a `custom-model-data` instead if your design uses an icon. For an item of your pack plugin, replace `material` and `custom-model-data` with one line, for example `material: 'itemsadder:mypack:ranked_button'`.

## 3. Numbers drawn with textures

### Digits in the title: `title-glyphs`

PinnaDuels can write any of its placeholders with your own digits, so live numbers appear on the background picture itself. First tell it which character of your pack stands for each digit, in `plugins/PinnaDuels/config.yml`:

```yaml
title-glyphs:
  # Text that moves the title cursor {n} pixels ({n} is negative: to the left).
  offset: ':offset_{n}:'
  # 'character width text'
  chars:
    - '0 9 :duel_digit_0:'
    - '1 9 :duel_digit_1:'
    - '2 9 :duel_digit_2:'
    - '3 9 :duel_digit_3:'
    - '4 9 :duel_digit_4:'
    - '5 9 :duel_digit_5:'
    - '6 9 :duel_digit_6:'
    - '7 9 :duel_digit_7:'
    - '8 9 :duel_digit_8:'
    - '9 9 :duel_digit_9:'
    - ', 5 :duel_digit_comma:'
    - '# 9 :duel_digit_hash:'
    - '- 7 :duel_digit_dash:'
    - '/ 9 :duel_digit_slash:'
    - '% 9 :duel_digit_percent:'
```

Each line is the character, its width and the text written for it:

* **width** is how many pixels the glyph takes in the title: its drawn width plus the 1 pixel gap the game adds after every character. It is only used to centre values, so it must match your art.
* **text** must be the final text: an ItemsAdder `:name:` (ItemsAdder replaces it in the title) or the glyph's own character. A `%placeholder%` here is not read, because PlaceholderAPI never reads placeholders inside the value of another placeholder.
* Characters that are not in the list are left out, and colour codes in the value are removed first. Add every character your values can contain: `,` for 1,250, `#` and `-` if your texts use them, `/` for placements like 2/3, `%` for the win rate.
* `offset` must be text your pack turns into a move of `{n}` pixels. ItemsAdder's `:offset_{n}:` works as it is.
* Give the digit images the `ascent` that puts them at the height of your boxes on the background.

Run `/duel admin reload` after changing it. With an empty `chars` list the placeholders return the plain value.

Then add `_glyphs` or `_glyphs_center` to any PinnaDuels placeholder in the title:

| Placeholder                        | Writes                                                                                                                                           |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `%pinnaduels_<key>_glyphs%`        | the value with your digits, starting at the cursor                                                                                               |
| `%pinnaduels_<key>_glyphs_center%` | the value centred on the cursor; afterwards the cursor is back where it was, so the rest of the title keeps its place however long the number is |

`<key>` is any placeholder key: `elo`, `position`, `tokens`, `wins`, `winrate`, `queue_size`, `active_duels`... (see [Placeholders](/p/pinnaduels/reference/placeholders.md)).

### A worked title

A card that shows the player's rank, ELO and league emblem in three boxes of the background:

```yaml
title: '&f:offset_-18::duels_main::offset_-57:%pinnaduels_position_glyphs_center%:offset_-46:%pinnaduels_elo_glyphs_center%:offset_-55:%pinnaduels_league_glyph%'
```

1. `:offset_-18::duels_main:` draws the background; the cursor now stands at its right edge.
2. `:offset_-57:` moves the cursor back to the middle of the rank box, and `%pinnaduels_position_glyphs_center%` writes the rank centred there. The cursor returns to that middle point.
3. `:offset_-46:` moves on to the middle of the ELO box, where `%pinnaduels_elo_glyphs_center%` is centred the same way.
4. `:offset_-55:` moves to the emblem box, and `%pinnaduels_league_glyph%` draws the emblem of the player's league.

Every offset counts from the previous point, so measure the distances between the middles of your boxes on the picture. The numbers are filled in when the menu opens.

### League emblems

Each league (and `unranked`) can have a `glyph`, drawn by `%pinnaduels_league_glyph%` and `%pinnaduels_top_<n>_glyph%`:

```yaml
leagues:
  gold-1: {name: '&#FFD700Gold I', icon: '&#FFD700⚔', min-elo: 1425, item: GOLD_BLOCK, glyph: ':league_gold:'}
unranked:
  name: '&7Unranked'
  icon: '&7⚔'
  item: GRAY_DYE
  glyph: ':league_unranked:'
```

Like the digits, the glyph must be final text (an ItemsAdder `:name:` or the raw character).

### Numbers on the items

* The queue button's stack size is the number of players in the queue (`queue-amount: false` in its `custom-item` turns that off).
* `custom-model-data` accepts tokens and placeholders, so an item can change its model with a number, e.g. `custom-model-data: '{tokens}'` gives the tokens item model data 0 to 3, and your pack can draw a different icon for each. Use a material that no other item of your menus uses, because these low numbers would clash with your other models, and map the values with a `range_dispatch` in that material's item definition (Minecraft 1.21.4+):

```json
{
  "model": {
    "type": "minecraft:range_dispatch",
    "property": "minecraft:custom_model_data",
    "index": 0,
    "entries": [
      { "threshold": 1, "model": { "type": "minecraft:model", "model": "mypack:item/tokens_1" } },
      { "threshold": 2, "model": { "type": "minecraft:model", "model": "mypack:item/tokens_2" } },
      { "threshold": 3, "model": { "type": "minecraft:model", "model": "mypack:item/tokens_3" } }
    ],
    "fallback": { "type": "minecraft:model", "model": "mypack:item/tokens_0" }
  }
}
```

* The `_glyphs` placeholders also work in item names and lore, as long as your digit glyphs look right on a tooltip.

## Checklist

* Every player has your pack loaded (the server resource pack, or the hosting of your pack plugin), and it loads without errors.
* `&f` is the first thing in the title, and the offset lines the picture up with the slots.
* PlaceholderAPI is installed (the `_glyphs` placeholders and `%img_...%` need it).
* Every character your numbers can contain is in `title-glyphs.chars`, with the right width.
* `tooltip-style` needs Minecraft 1.21.2+ and `hide-tooltip` 1.20.5+, on the server and on the player's game. Item definitions in `assets/<namespace>/items/` (such as `range_dispatch`) need 1.21.4+.
* A barrier instead of your item means the `material` is misspelled, or its pack plugin isn't installed or doesn't know that id.
* After editing the menu files run `/pinna reload`; after editing `config.yml` (`title-glyphs`, league glyphs) run `/duel admin reload`. After changing the pack, rebuild it with your pack plugin and rejoin so the game loads the new version.
