Deepslate Studios
SlateChat

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):

PlaceholderDescription
%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.global

Prefixes/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.

KeyMeaning
formatThe message format. Supports <player>, <message>, PAPI placeholders and %chat_color%
commandWhat /ch <command> matches, alongside the channel's name
enableOnly used on local — whether the default channel is active
broadcastIf true, ignores radius and reaches every online player
radiusBlock radius the message reaches when broadcast is false. 0 means same world only
restrictIf true, only players with permission can use this channel
actionbarShow the sender an action bar read receipt for this channel
permissionNode 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.

KeyMeaning
hex_pickertrue (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_commandOnly 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.'
KeyMeaning
format_sent / format_received / format_spyThe 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_buttonThe clickable [reply] snippet substituted wherever <reply> appears in a format above — suggests /r in chat, doesn't send anything on its own
console_logAlways logged, even for a conversation hidden from socialspy by chat.tell.spy.bypass — reuses log_to_console/console_format_colors from config.yml
restrictIf 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!'
KeyMeaning
joinShown when a returning player joins. Leave blank ("") to suppress
quitShown when a player leaves. Leave blank ("") to suppress
first_joinShown 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:global

Each entry is world:channel — replace dummy with a real world name and global with the channel you want enforced there.

On this page