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.
| Type | What it is | Made with |
|---|---|---|
customtag | a tag in front of the name: text and colour, both theirs | /cc customtag create <text> [colour] |
customcolor | the colour of what they write | /cc customcolor create <colour> |
customnick | the colour of their name | /cc customnick create <colour> |
customrank | the 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.
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.
| Drawn | First | Then | Then |
|---|---|---|---|
| The tag | customtag | tag | nothing |
| The name | customnick | nick_color | the name as it comes |
| The message | customcolor | chat_color | chat.default-color |
| The rank's prefix and suffix | customrank | rank_color | the 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.
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: trueThe 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, a51c4, 8a51c4, a named
colour like gold, a palette token like {primary}, or several of those separated by colons for a
gradient.
| Rule | Where |
|---|---|
A gradient may run through at most custom-colors.max-stops stops | default 4 |
- typed at the colour question leaves the tag without one | the tag is drawn in the chat's own colour |
| A colour that cannot be read is refused before anything is written | no token is taken |
custom-colors:
# How many colours a custom gradient may run through
max-stops: 4Both 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.
| Command | Removes |
|---|---|
/cc customtag delete | every 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.
| Command | Does |
|---|---|
/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