
BenzyChat
A clean, standalone FiveM roleplay chat. It replaces the stock chat with color-coded local and global commands (/me, /do, /ooc, /leo, /med, …), draws each message as a dark glass bubble in the top-left corner — the sender's name, the command type in its own color, and the text — and gives players a polished top-center typing box with real command autocomplete and sent-line recall. Opening the box turns the bubbles into a scrollable recent-message view. Each player picks how chat shows (fade on new message, always on, or hidden), and every message can be mirrored to Discord. No framework, no database, no dependencies.
Made by Samuel Benzy of Benzy Development.
Features
- Local + global commands —
/me,/do,/ooc,/leo,/medout of the box, each with an auto-generated global twin (/gme,/gooc, …). Local messages reach only players within range; global messages reach the whole server. - Color-coded types — the type label (
me,ooc, …) is drawn in its own color so you can tell messages apart at a glance. Every command and color is set inconfig.lua. - On-screen bubbles — dark, slightly transparent bubbles that come down from the top-left corner: the sender's FiveM name, the colored command type, an optional GLOBAL tag, and the message in white. Up to three at a time.
- A proper typing box — a top-center glass pill with Tab autocomplete (cycle-complete a command into the box) and ↑ / ↓ recall of your own sent lines. Opening it turns the top-left bubbles into a mouse-wheel-scrollable view of the recent messages.
- Per-player visibility — a toggle key cycles active (show on a new message, then fade), always (keep the last three pinned), and hidden (never show). Each player's choice is remembered.
- No-command behavior — decide what plain text with no
/commanddoes: nothing, a local message, or a global one. - Discord logging — paste a webhook URL and every message posts a tidy embed with the command and scope;
@everyonecan't ping. - A true drop-in — it
provideschat, so other resources'chat:addMessagelines still show as bubbles and theirchat:addSuggestioncommands still autocomplete. Foreign commands (/pay,/engine, …) keep working. - Standalone — no framework (ESX/QBCore) and no database required.
How it works
- The client shows the bubbles and the typing box. Press the open key to type; on Enter, one of BenzyChat's commands goes to the server with the exact text, a foreign command is handed off to whatever registered it, and plain text follows the no-command setting.
- The server is the authority: it re-validates every command (clients are never trusted), trims and length-caps the text, and works out the recipients — everyone for a global command, only players in range for a local one. Then it renders on each recipient's client and logs to Discord.
- Everything visual — the colors, positions, bubble timing, and theme — is read from
config.luaand applied to the UI when it loads, so a config change is all it takes to restyle.
Requirements
- A FiveM server. That's it — BenzyChat is standalone.
Installation
- Place the
BenzyChatfolder in your server'sresourcesdirectory. - Add BenzyChat to your
server.cfg:BenzyChat replaces the stock chat (it declaresensure BenzyChatprovide 'chat') and stops the built-inchatresource automatically whenever it starts, so you don't need to touch it inserver.cfg. - (Optional) Set a Discord webhook to log chat — paste a URL into
Config.Webhooksinconfig.lua. - Open
config.luaand set the commands, colors, and theme to taste. - Restart the server (or
ensure/restart BenzyChat).
Press T in-game to open chat (rebindable in Settings → Key Bindings → FiveM). Run /debugbenzychat from the server console (or an admin) for a quick state report and sample bubbles.
Configuration
Everything is configured in config.lua, and every option has a comment above it explaining what it does. The highlights:
Commands
| Option | What it does |
|---|---|
Config.Commands | The command list — each row's Command, Label, Color, and Description. Add Global = false or Range = 30.0 to any row. Prefix any command with g in-game for its global twin. |
Config.NoCommandBehaviour | What plain text with no /command does — 'none', 'local', or 'global'. |
Bubbles
| Option | What it does |
|---|---|
Config.Bubbles.Position | Where the bubble stack sits — see Positions. |
Config.Bubbles.Duration | Milliseconds a bubble stays before it fades (the active mode only). |
Input & visibility
| Option | What it does |
|---|---|
Config.Input.Position | Where the typing box sits (default top-center). |
Config.Visibility.Default | The mode a player starts on — 'active', 'always', or 'hidden'. |
Config.Visibility.ToggleKey | The default key that cycles the modes (rebindable). |
Theme, Discord & locale
| Option | What it does |
|---|---|
Config.Theme | The surface color, text/name colors, accent, and corner radius. |
Config.Webhooks | A URL per scope (Local, Global, Plain) — leave blank to skip, use the same URL to log everything to one channel. |
Config.Locale | Active language code (default 'en'). |
Commands
Every command below has a global twin — prefix it with g to send it server-wide: /me → /gme, /ooc → /gooc, and so on.
| Command | Type | What it does |
|---|---|---|
/me <action> | Local | An action you perform — John Doe waves. |
/do <detail> | Local | Describe the scene or surroundings. |
/ooc <message> | Local | Out-of-character chatter to nearby players. |
/leo <message> | Local | Law-enforcement chatter. |
/med <message> | Local | Medical / EMS chatter. |
/g<command> … | Global | The global twin of any command above — reaches the whole server. |
Plain text typed without a leading /command follows Config.NoCommandBehaviour. Add, remove, or recolor any command in Config.Commands.
Keys: T opens the typing box; L cycles the visibility mode. Both are rebindable in Settings → Key Bindings → FiveM. In the box: Enter sends, Esc cancels, Tab / Shift+Tab complete a command, ↑ / ↓ recall your last lines, and the mouse wheel scrolls the history.
Visibility modes
Each player presses the toggle key (default L) to cycle how chat shows on their screen. No matter the mode, opening the typing box always shows the recent messages.
| Mode | What it does |
|---|---|
active | A bubble appears when a new message arrives, then fades after Config.Bubbles.Duration. The default. |
always | The last few messages stay pinned on screen at all times. |
hidden | Bubbles never show — you only see messages by opening the box. |
Set the starting mode with Config.Visibility.Default; each player's own choice is then remembered across sessions.
Positions
Set Config.Bubbles.Position and Config.Input.Position to one of:
top-left top-center top-right
center-left center-right
bottom-left bottom-center bottom-right
Bubbles default to top-left and the typing box to top-center, so the two never overlap.
Discord logging
Paste a webhook URL and every message posts an embed — the sender (name + id), the message, the command, and the scope. Leave a scope's URL blank to skip it, or use the same URL for all three to log everything in one channel.
- Per scope:
Config.Webhooks.Local,Config.Webhooks.Global,Config.Webhooks.Plain. - Safe by design: player text only ever goes inside the embed, which Discord never turns into a mention, so a message containing
@everyonecan't ping.
Integrating with other resources
BenzyChat is a drop-in chat, so most resources need no changes. The docs cover the rest:
- docs/EVENTS.md — BenzyChat's own events and the stock
chat:*events it keeps working. - docs/EXPORTS.md — raise a bubble on a client, or broadcast a message from the server.
- docs/INTEGRATIONS.md — replacing the stock chat, how other resources' output still shows, and Discord logging.
Because it provides chat, any resource that calls TriggerEvent('chat:addMessage', …) or chat:addSuggestion keeps working with no changes.
Notes
- Bubbles are purely visual and client-side. A message shows, fades, and is gone; opening the box shows the last few again as a scrollable recent view. Nothing is stored server-side.
- Local chat never leaves range. The server sends a local message only to players who should see it, so out-of-range clients can't sniff it (no metagaming).
- It replaces the stock chat. BenzyChat stops the built-in
chatresource automatically whenever it starts, so the two never run side by side — noserver.cfgchange needed.
Troubleshooting
- Turn on debug logging first — set
Config.Debug = true, restart, and watch the server console + each client's F8. Every message logs its command, scope, and recipient count./debugbenzychatprints a state report. - Two chat boxes — BenzyChat stops the built-in
chaton its own (withConfig.Debugon you'll see "stopped the built-in chat resource" in the console). If a box still shows, another resource is running its own chat — stop that one. - A local message reaches no one — local chat carries 20m and reaches nearby players (globals reach everyone). Give a command its own
RangeinConfig.Commandsto change how far it carries. - A command does nothing — check the command exists in
Config.Commands(names are case-insensitive). - Another script's command isn't in the autocomplete — For a command and its help text to appear, BenzyChat needs to be running when that resource registers it —
ensure BenzyChatnear the top of yourserver.cfgfor the fullest hints. - Discord isn't logging — confirm the URL is set in
Config.Webhooksand that the resource can reach Discord. Debug logging shows each post's result. - The box won't open / I'm stuck — check the open key in Key Bindings. If a reload ever leaves you stuck, the resource releases focus on stop.
Support
Need help? Visit support.benzy.lol.
Credits
Made by Samuel Benzy of Benzy Development.
Website: https://benzy.lol