Content generated with AI — it may contain mistakes.

The catalogue

Custom cosmetics

The four things a player makes for themselves, the rules that keep them printable, and what happens when one is edited or deleted.

Four kinds of cosmetic are not in any file. A player writes them, they belong to that player alone, and each one is a row in a table rather than an entry you curate.

TypeWhat it isMade with
customtaga tag in front of the name: text and colour, both theirs/cc customtag create <text> [colour]
customcolorthe colour of what they write/cc customcolor create <colour>
customnickthe colour of their name/cc customnick create <colour>
customrankthe colour their rank's prefix and suffix are repainted in/cc customrank create <colour>

They behave like any other cosmetic once they exist: they sit in a browser, they can be starred, they go into a loadout, they are named type:id in commands and placeholders. What is different is where they come from and who may wear them.

Where a player makes one

Two ways in, and they end at the same service.

From the browser

Every catalogue browser that pairs with one of the four — tags, chat colours, nick colours, rank colours — has a button that switches the grid from the catalogue to what the player made. While that list is open, a MAKE ONE button appears. It asks for the text, then for the colour, and writes the row.

From a command

/cc customtag create, /cc customcolor create, /cc customnick create and /cc customrank create do the same thing in one line, for a player who would rather type it.

The list of what a player made is a button rather than a tab on purpose: a kind nobody has made anything of would otherwise take a tab away from the catalogue on every browser, for every player, forever.

The balance is checked before the questions

Opening MAKE ONE with no create token left says so immediately and asks nothing. Asking somebody to write a tag and then telling them they could never have afforded it is the one order worth avoiding. The token itself is taken later, by the service, which checks the balance again.

The id is the row number

A custom cosmetic is keyed by the database row it was written as. The forty-second row anybody ever made is customtag:42, and it stays customtag:42 for as long as it exists.

The text cannot be the identity — two players may write the same word — and neither can the colour, since a gradient has colons in it and colons are what separate a type from an id. The row number is the only thing that is unique, stable and safe to print.

Ownership follows from the row rather than from a permission. The owner owns it the way a permission would: permanently, with nothing to expire. Nobody else can equip it, and there is no node that would let them — a custom cosmetic declares permission: false, so the usual exyliachatcosmetics.<type>.<id> node grants nothing here.

What a player made wins

Both slots can be filled at once — a player may own a catalogue tag and have written their own — so something has to decide. What they made wins, in all four places, because it is the more deliberate choice.

DrawnFirstThenThen
The tagcustomtagtagnothing
The namecustomnicknick_colorthe name as it comes
The messagecustomcolorchat_colorchat.default-color
The rank's prefix and suffixcustomrankrank_colorthe rank as it wrote itself

A rank colour has no say over the name, custom or not. It paints the prefix and the suffix, which is what a rank owns; the name is the player's.

What a custom tag has to survive

The text is checked in a fixed order, and the first rule it fails is the one the player is told about. Nothing is written and no token is taken until every one of them has passed.

The permission

exyliachatcosmetics.customtag.create, default true. Denied here, nothing else is even asked.

Length

Between custom-tags.min-length and custom-tags.max-length, counted in code points so that a character outside the basic plane counts as one and not two.

The characters that are never text

<, >, {, }, &, §, % and \ are refused outright, whatever pattern allows.

`pattern`

A regular expression matched against the whole text. A pattern that does not compile is treated as no pattern at all.

`blacklist`

Words the text may not contain, matched case-insensitively anywhere inside it.

Uniqueness

With custom-tags.unique on, a text somebody else already holds is refused.

The create token

Taken last, so a refused tag costs nothing, and taken before the row is written, so a second click finds the balance already short.

The third step is the one that matters most and the one easiest to widen by accident. Those eight characters are what the text module reads as an instruction rather than as text: a tag is drawn as literal text and named in menus as formatted text, so a character that opens a MiniMessage tag, a palette token, a legacy colour code or a placeholder is never part of a name. The check is not inside pattern; it runs before it and regardless of it. An owner who widens pattern to let players use punctuation still cannot get < into a tag.

plugins/ExyliaChatCosmetics/config.yml
custom-tags:
  min-length: 2
  max-length: 16
  # What the text may contain, as a regular expression over the whole text
  pattern: '[A-Za-z0-9_\-]+'
  # Words a custom tag may not contain, case-insensitively
  blacklist:
    - admin
    - staff
    - owner
  # Whether two players may not hold the same text
  unique: true

The colour

A custom tag may name a colour and does not have to; the three custom colours are nothing but one. Either way the colour is written in the ordinary grammar — #8a51c4, &#8a51c4, 8a51c4, a named colour like gold, a palette token like {primary}, or several of those separated by colons for a gradient.

RuleWhere
A gradient may run through at most custom-colors.max-stops stopsdefault 4
- typed at the colour question leaves the tag without onethe tag is drawn in the chat's own colour
A colour that cannot be read is refused before anything is writtenno token is taken
plugins/ExyliaChatCosmetics/config.yml
custom-colors:
  # How many colours a custom gradient may run through
  max-stops: 4

Both rules are enforced while the player types, in the input itself, and again by the service when it writes. The first is a courtesy; the second is what actually holds.

Editing keeps the row number

Changing one costs an edit token, which is a separate balance from the create token and is never touched by a creation. What comes back is the same row: same id, same key, same everything except what it reads or what colour it is.

That is deliberate, and it is the whole reason edits are done this way rather than as a delete and a create. A tag that is worn stays worn. A colour that is starred stays starred. A loadout that names it still names it. What changed is what the cosmetic looks like, not which cosmetic it is.

A custom tag being edited goes through the same seven checks as a new one, minus the create token and plus an edit token. Uniqueness ignores the row being edited, so a player may re-save the text they already hold.

Deleting refunds nothing

A token buys the act of writing, not the row it wrote. Deleting one gives nothing back, and there is no way to reclaim a balance short of /cca tokens give.

CommandRemoves
/cc customtag deleteevery custom tag the player has
/cc customcolor delete <id>one custom chat colour, by row number
/cc customnick delete <id>one custom nick colour
/cc customrank delete <id>one custom rank colour

A row that is worn is taken off before it stops existing. Nothing can own it afterwards, so leaving it equipped would only be a line that draws nothing.

Writing one for somebody

/cca customtag set <player> <text> [colour] writes a custom tag for a player without spending a token and without asking for the create permission. Everything else still applies: the length, the eight forbidden characters, pattern, blacklist and uniqueness are all checked exactly as they would be for the player themselves.

That is the point of it. The text rules are not a quota — they are what keeps a slur out of chat, and staff writing a tag for a player is not a reason to skip them.

CommandDoes
/cca customtag set <player> <text> [colour]writes one, free, rules enforced
/cca customtag clear <player>removes every custom tag they made
/cca customcolor clear <player>removes every custom chat colour they mixed
/cca customnick clear <player>the same for nick colours
/cca customrank clear <player>the same for rank colours

All of them sit under exyliachatcosmetics.admin.

Something missing on this page? Tell us on Discord