Twitch-style emotes for The Lounge IRC client. Renders emotes from 7TV, BetterTTV, and FrankerFaceZ inline in chat messages — both global and per-channel.
- Global emotes from 7TV, BTTV, and FrankerFaceZ (130+ emotes)
- Channel emotes — add any Twitch channel name to load their 7TV, BTTV, and FFZ emotes (800+ per channel)
- Emote picker — ☺ button in the chat bar opens a searchable emote palette with provider tabs
- Settings panel — gear icon in the picker to manage channel emote sources
- Auto-refresh — emote data refreshes every hour
- Hover tooltips — shows emote name and provider on hover
- Emote-only messages — messages with only emotes (up to 3) render at natural size
- Retina support —
srcsetwith 2x images for high-DPI displays - Natural sizing — emotes render at their native size with 128px max safeguards
- Accessible —
alttext andaria-labelon all emote images
thelounge install thelounge-plugin-emotesRestart The Lounge after installing. The plugin works out of the box — no configuration required.
- Fetches global emotes from 7TV, BTTV, and FFZ
- Injects the client-side script into The Lounge's HTML
- Starts rendering emotes in chat messages immediately
The plugin injects client.js by intercepting The Lounge's HTTP responses. If emotes don't appear after install, you can load the script manually:
Option A: Browser userscript (persistent)
Install Violentmonkey or Tampermonkey, then create a new script:
// ==UserScript==
// @name The Lounge Emotes
// @match https://your-lounge-url/*
// @grant none
// @run-at document-idle
// ==/UserScript==
const s = document.createElement("script");
s.src = "/packages/thelounge-plugin-emotes/client.js";
document.head.appendChild(s);Replace https://your-lounge-url/* with your instance URL.
Option B: Browser console (temporary)
Open developer tools (F12) and run:
const s = document.createElement("script");
s.src = "/packages/thelounge-plugin-emotes/client.js";
document.head.appendChild(s);This only lasts until page refresh.
| Command | Description |
|---|---|
/emotes |
Show emote count, active channels, and usage info |
/emotes search <term> |
Search emotes by name (max 25 results) |
/emotes refresh |
Force reload emote data from all providers |
/emotes channel add <name> |
Add a Twitch channel's emotes |
/emotes channel remove <name> |
Remove a channel's emotes |
/emotes channels |
List active channel emote sources |
Click the ☺ button in the chat input bar to open the emote picker:
- Search — filter emotes by name in real time
- Provider tabs — filter by All, 7TV, BTTV, or FFZ
- Click to insert — clicking an emote inserts its name into the chat input
- Settings — click the ⚙ gear icon to manage channel emote sources
Add any Twitch channel to load their third-party emotes:
- Open the emote picker → click ⚙ → enter a channel name (e.g.
xqc) - Or use the command:
/emotes channel add xqc
The plugin resolves the Twitch username to an ID via ivr.fi, then fetches channel-specific emotes from all three providers. Up to 10 channels can be added.
When emote names collide across providers or channels, the first one loaded wins:
- Global emotes: 7TV → BTTV → FFZ
- Channel emotes are added after globals (per channel, same provider order)
- Fetches emotes from 7TV, BTTV, and FFZ APIs on startup
- Resolves Twitch usernames → IDs via
api.ivr.fifor channel emotes - Caches emote data in memory and writes
emote-data.jsonto the package directory - Injects a
<script>tag into The Lounge's HTML response viahttp.ServerResponseprototype patch - Modifies Content-Security-Policy headers to allow emote CDN image sources
- Refreshes emote data every hour
- Persists channel configuration in The Lounge's persistent storage directory
- Fetches
emote-data.jsonand builds a regex from all emote names - Uses a
MutationObserverto watch for new chat messages - Walks text nodes in message content and replaces emote codes with
<img>elements - Provides the emote picker UI, settings panel, and hover tooltips
- Auto-injected via The Lounge's
Stylesheets.addFile()API - Emotes render at natural size with
max-height: 128px/max-width: 128pxsafeguards - Picker panel uses The Lounge's CSS custom properties for theme consistency
| Provider | Global API | Channel API | CDN |
|---|---|---|---|
| 7TV | /v3/emote-sets/global |
/v3/users/twitch/{id} |
cdn.7tv.app |
| BetterTTV | /v3/cached/emotes/global |
/v3/cached/users/twitch/{id} |
cdn.betterttv.net |
| FrankerFaceZ | /v1/set/global |
/v1/room/{username} |
cdn.frankerfacez.com |
- All emote URLs are validated as HTTPS before rendering
- Emote names are validated against a strict allowlist pattern (
/^[\w\-:()!]+$/) - Twitch IDs are validated as numeric before use in API calls
- HTTP responses are capped at 5MB to prevent memory exhaustion
- Redirect chains are limited to 3 hops
- Channel names are validated (
/^[a-zA-Z0-9_]{1,25}$/) - Maximum of 10 channel emote sources
- All external API calls use HTTPS with timeouts
- No user credentials or tokens are stored server-side
- The Lounge
^4.0.0 - Node.js
>=14.0.0
Contributions are welcome. Please open an issue first to discuss what you'd like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -am 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
MIT © Zendorea