Configuration
Every option in config.yml, channels.yml and the other module config files.
All of SlateChat's config files support MiniMessage and MineDown formatting, plus any PlaceholderAPI expansion you have installed. Each module has its own file so you're never staring at options you don't use.
Plugin placeholders
SlateChat exposes two placeholders of its own, under the chat identifier,
usable anywhere PlaceholderAPI is (including inside the channel formats below):
| Placeholder | Description |
|---|---|
%chat_color% | The player's currently selected chat color (legacy/HEX code). |
%chat_channel% | The display name of the player's currently focused channel. |
config.yml
Global messages, plus the switches that turn each module on or off.
# Sent when a player lacks permission for a channel or command
no_permission: '<red>You do not have permission!'
players_only: '<red>Only players can execute this command!'
# Sent to the sender with how many players saw their message
amount_readed: '<dark_purple><amount> players saw your message!'
no_one: '<red>No one readed your message! :c'
channel_command_usage: '<red>Usage: /ch <channel>'
channel_usage_message: '<red>Usage: /<command> <message>'
channel_changed: '<green>Channel changed to <channelName> - <channelCommand>'
invalid_channel: '<red>Invalid channel!'
# /slatechat messages
plugin_reloaded: '<green>Plugin reloaded.'
wiki_message: '<green>Documentation: <url>'
wiki_url: 'https://deepslate.ch/docs/plugins/slatechat'
# Update checker messages (see modules.update_checker below)
# Placeholders: <version> - the newer version found, <current> - the version you're running
update_available: '<yellow>A new SlateChat version (<green><version></green>) is available! You are running <red><current></red>.'
update_up_to_date: "<green>You're already running the latest version (<current>)."
update_check_failed: '<red>Could not reach GitLab to check for updates. Try again later.'
# The 3 below print to console via the console sender (an Audience, like a player) --
# MiniMessage renders as real color there too. Placeholders: <version>, <current>, <url>
update_console_log: '<gray>A new version (<version>) is available! You are running <current>. Download: <url></gray>'
update_console_up_to_date: '<gray>You are running the latest version (<current>).</gray>'
update_console_check_failed: '<red>Could not check for updates.'
# Mirror every chat message to console
log_to_console: true
console_log: '[<channel>] <player>> <message>'
# Render colors as real ANSI escapes in console/log file instead of plain text.
# Hover/click never show up in console either way, on or off.
console_format_colors: false
# Verbose logging: the processed message + raw component JSON for every message. Noisy.
debug: false
modules:
# -- Chat --
chatcolor: true # Per-player chat color, /chatcolor (opens a GUI with no argument)
focus: true # Let players lock to a default channel with /ch
filter: true # Word filtering (blocked_words / replace)
tell:
enable: false # /tell, /msg, /w, /r, /socialspy -- off by default, formats live in tell.yml
joinquit:
enable: false # Custom join/quit/first-join messages -- off by default, formats live in joinquit.yml
chatformat:
spam:
enable: false
limit: 10 # Max repeated characters before a message is blocked
message: '<green>Message canceled because contain spam.'
flood:
enable: false # Block sending the same message twice in a row
message: '<green>You cannot send a message like the previous message.'
lowercase: false # Force messages to lowercase
title_format: false # Force-capitalize the first letter of every message
pride: true # <pride> MiniMessage tag on/off, server-wide (independent of chat.colored)
# -- Integrations --
discordsrv: true # Detect DiscordSRV and bridge channel messages to it
discordsrv_send: false # Forward chat to DiscordSRV, per-channel (off by default, avoids duplicates)
itemsadder: true # ItemsAdder compatibility: resolve its :name: font images in chat (no-op without ItemsAdder)
# -- Maintenance --
update_checker: true # Check GitLab for a newer release on startup (async, fail-silent)Picking which channel goes to Discord
With discordsrv_send: true, a SlateChat channel is only forwarded if its
name is a key in DiscordSRV's own Channels option
(plugins/DiscordSRV/config.yml) — e.g. Channels: {"global": "123456789"}
forwards only the global channel, and anything left out simply isn't
sent. If DiscordSRV's own built-in chat listener is also relaying raw
vanilla chat regardless of channel, set DiscordChatChannelMinecraftToDiscord: false
in DiscordSRV's config so SlateChat's per-channel forwarding is the only
path to Discord.
ItemsAdder compatibility
With itemsadder: true (the default), any :name: font image ItemsAdder
registers — emoji, rank/prefix badges (including one set via
%luckperms_prefix%), custom icons — resolves through ItemsAdder's own
FontImageWrapper.replaceFontImages() API wherever SlateChat renders text,
including that font image's permission, if it has one set in ItemsAdder's
config. Nothing to configure on ItemsAdder's side, it just needs to be
installed and enabled. See the formatting
guide for the
syntax.
channels.yml
Defines every channel. Keys must be unique, and local is the default
channel new players start in — don't remove it.
local:
format: '<yellow>[Local] <player><blue><bold>> <yellow>%chat_color%<message>'
command: 'l'
enable: true
broadcast: false
radius: 200
restrict: false
actionbar: true
permission: chat.local
global:
format: '<gray>[Global] <player><blue><bold>> <gray>%chat_color%<message>'
command: 'g'
broadcast: true
radius: 0
restrict: false
actionbar: false
permission: chat.globalPrefixes/suffixes are opt-in
The default formats above don't depend on LuckPerms — add placeholders like
%luckperms_prefix% directly into a channel's format if you want ranks
shown, resolved through PlaceholderAPI.
| Key | Meaning |
|---|---|
format | The message format. Supports <player>, <message>, PAPI placeholders and %chat_color% |
command | What /ch <command> matches, alongside the channel's name |
enable | Only used on local — whether the default channel is active |
broadcast | If true, ignores radius and reaches every online player |
radius | Block radius the message reaches when broadcast is false. 0 means same world only |
restrict | If true, only players with permission can use this channel |
actionbar | Show the sender an action bar read receipt for this channel |
permission | Node checked when restrict is true, and reported by /ch tab-completion |
Add as many extra channels as you want under this file, they all support the
same keys as global.
color.yml
Backs the /chatcolor command.
enable_rgb: true # Allow hex colors; disable to only accept legacy codes
clear_keywords:
- 'clear'
- 'remove'
- 'reset'
only_players: '<red>Avaliable only for players!'
no_permission: '<red>You do not have permission!'
invalid: '<red>Type an valid hex color! /chatcolor #<color>'
removed: '<green>Your chat color was removed!'
success: '<green>The color of your chat was changed to %chat_color%this<green>.'/chatcolor <color> accepts a hex code (#4DC3FF, needs enable_rgb: true),
a legacy code (&c), or a MiniMessage color tag (<red>, <#4dc3ff>) —
solid colors only, no gradients/rainbow. Any of the configured
clear_keywords removes the color instead of setting one.
/chatcolor with no argument opens a GUI instead of printing a usage
message (still needs chat.setcolor): the 16 standard colors as dyed
leather chestplates (a real RGB match per color, not an approximated icon),
a reset button, and a book that opens an anvil-based hex picker — type a
color into the rename field, a live preview recolors as you type, click it
to apply.
menu:
title: '<dark_gray>Choose your chat color'
reset_name: '<gray>Reset to default'
hex_button_name: '<yellow>Custom hex color...'
hex_title: '<dark_gray>Type a hex color'
hex_prompt: '<gray>Type a hex code, e.g. #4DC3FF'
hex_picker: true
hex_picker_command: ''
itemsadder:
color_item: ''
book_item: ''
reset_item: ''
filler_item: ''
canvas_item: ''
preview_item: ''The color grid itself isn't configurable
Which 16 colors, their layout, and the dark/normal pairing are fixed — only the text above is.
| Key | Meaning |
|---|---|
hex_picker | true (default) — the book opens SlateChat's own anvil hex picker. false — the book doesn't appear at all. custom — the book still appears, but clicking it runs hex_picker_command as the player instead. |
hex_picker_command | Only read when hex_picker: custom. Run as whichever player clicked the book (leading / optional). |
itemsadder.* | Optional per-role ItemsAdder item ID (namespace:id) to reskin that icon. Blank, ItemsAdder not installed, or the ID not registered — falls back to the plain vanilla item every time, no errors. |
Why hex_picker: custom exists
The anvil is the only built-in Minecraft inventory with a live text-input
field, which the hex picker's type-and-preview relies on — but unlike
every other screen in this GUI, Paper's API has no way to give an
already-open anvil a real Component title, only a legacy string set
after the fact. That means the custom-font GUI-texture trick that works
on the main menu's title can't apply to the anvil specifically. If that
matters to you, set hex_picker: custom and point it at your own GUI
plugin's own "open" command instead, rather than SlateChat reaching past
Paper's own API to force a title onto the anvil.
color_item / canvas_item / preview_item need leather armor
SlateChat only dyes these per-color if the resolved item's meta is
actually LeatherArmorMeta under the hood. For canvas_item and
especially preview_item (the hex picker's live, recolors-on-every-keystroke
preview) this isn't cosmetic — a custom item that isn't leather armor
loses the color preview entirely: it'll look identical no matter what hex
you type, only the name changes. book_item/reset_item/filler_item
have no such requirement, they're purely cosmetic either way.
tell.yml
Backs /tell (aliases /msg, /w), /r, and /socialspy. Whether the
module runs at all is modules.tell.enable above — off by default, so
it doesn't start competing with a tell/msg solution you already run.
tell:
format_sent: '<gray>[me -> <target>] <white><message>'
format_received: '<gray>[<player> -> me] <white><message> <reply>'
format_spy: '<dark_gray>[spy] <player> -> <target>: <message>'
reply_button: "<hover:show_text:'Click to reply'><click:suggest_command:'/r '><gray>[reply]</gray></click></hover>"
console_log: '[TELL] <player> -> <target>: <message>'
restrict: false
usage: '<red>Usage: /tell <player> <message>'
reply_usage: '<red>Usage: /r <message>'
target_offline: '<red><target> is not online.'
self_tell_blocked: '<red>You cannot message yourself.'
no_reply_target: '<red>You have nobody to reply to.'
socialspy_on: "<green>Socialspy enabled -- you will now see other players' tells."
socialspy_off: '<yellow>Socialspy disabled.'| Key | Meaning |
|---|---|
format_sent / format_received / format_spy | The three lines a tell produces — what the sender sees, what the recipient sees, and what a /socialspy watcher sees. Placeholders: <player> (sender), <target> (recipient), <message>, <reply> |
reply_button | The clickable [reply] snippet substituted wherever <reply> appears in a format above — suggests /r in chat, doesn't send anything on its own |
console_log | Always logged, even for a conversation hidden from socialspy by chat.tell.spy.bypass — reuses log_to_console/console_format_colors from config.yml |
restrict | If true, requires chat.tell to use the command at all. The node itself isn't configurable — see Permissions |
Keep the quoted hover/click arguments plain
A color tag nested inside show_text:'...'/suggest_command:'...'
trips up the MiniMessage parser. <gray> around the visible [reply]
itself, outside the quotes, is fine.
Socialspy is per-player and persists across relogin/restart. A player
another plugin has vanished never shows up in /tell's tab-complete or as a
valid target (indistinguishable from offline), unless the sender has
chat.tell.vanish.bypass.
joinquit.yml
Whether the module runs at all is modules.joinquit.enable above — off
by default, so it doesn't start competing with a join/quit message
plugin you already run.
joinquit:
join: '<yellow><player> joined the game.'
quit: '<yellow><player> left the game.'
first_join: '<green>Welcome <player> to the server for the first time!'| Key | Meaning |
|---|---|
join | Shown when a returning player joins. Leave blank ("") to suppress |
quit | Shown when a player leaves. Leave blank ("") to suppress |
first_join | Shown instead of join the very first time a player ever logs in |
Placeholders: <player> always; <online>/<max> (current/max player
count) are supported but left out of the defaults — add them to any format
above if you want them. A player with chat.join.bypass never triggers any
of the three, in either direction — meant for staff, covers vanished admins
too without needing to detect any particular vanish plugin's state.
filter.yml
Word filtering. Matching is case-insensitive.
# Censored (replaced with asterisks) wherever they appear
blocked_words:
- 'bitch'
- 'damn'
# left->right replacement, e.g. every "barney" becomes "swarley"
replace:
- 'barney->swarley'focus.yml
Forces players into a channel while they're in specific worlds, regardless
of what they last picked with /ch.
worlds:
- dummy:globalEach entry is world:channel — replace dummy with a real world name and
global with the channel you want enforced there.
