Ir al contenido

El chat con emotes

Un mensaje de chat llega en partes: texto, emotes e imágenes de cheers. Widget.dom.renderMessage las convierte en un fragmento listo para añadir, con los emotes como <img> y el texto como texto.

manifest.json
{
"events": ["Twitch.ChatMessage", "Twitch.ChatMessageDeleted"],
"strings": { "es": {}, "en": {} },
"menu": {
"sections": [
{
"id": "chat",
"title": { "es": "Chat", "en": "Chat" },
"fields": [
{
"type": "number",
"id": "maxMessages",
"param": "maxMessages",
"label": { "es": "Máximo de mensajes", "en": "Maximum messages" },
"default": 20,
"min": 1,
"max": 100,
"step": 1
}
]
}
]
}
}
index.html
<div id="chat"></div>
style.css
html,
body {
margin: 0;
background: transparent;
}
#chat {
position: absolute;
inset: auto 0 0 0;
padding: 16px;
font: 600 28px system-ui, sans-serif;
color: #ffffff;
}
.message {
margin-top: 8px;
}
.message img {
height: 1.2em;
vertical-align: middle;
}
script.js
const chat = document.querySelector("#chat");
const maxMessages = Widget.parameters.int("maxMessages", 20);
Widget.on("Twitch.ChatMessage", (message) => {
const row = document.createElement("div");
row.className = "message";
row.dataset.messageId = message.messageId;
const name = document.createElement("strong");
Widget.dom.text(name, message.user);
const text = document.createElement("span");
text.append(Widget.dom.renderMessage(message.parts));
row.append(name, " ", text);
chat.append(row);
while (chat.children.length > maxMessages) chat.firstElementChild.remove();
});
Widget.on("Twitch.ChatMessageDeleted", ({ messageId }) => {
for (const row of chat.querySelectorAll(".message")) {
if (row.dataset.messageId === messageId) row.remove();
}
});
  • message.parts ya trae el mensaje troceado; no hace falta interpretar nada a mano. Las imágenes de emotes solo salen si son de una CDN permitida.
  • El nombre va con Widget.dom.text, nunca con innerHTML: un nombre con HTML no puede colar elementos.
  • El bucle while limita el número de mensajes. Sin él, un chat largo acumularía elementos sin parar y acabaría agotando la memoria (runtime_memory).
  • messageId identifica cada mensaje: cuando un moderador borra uno, llega Twitch.ChatMessageDeleted con el mismo id y lo quitas.
  • Más plataformas: Kick.ChatMessage y Youtube.Message traen los mismos campos, así que la misma función vale: llámala desde tres Widget.on.
  • Color del nombre: el evento trae color (el del usuario en su plataforma): name.style.color = message.color.
  • Insignias: message.badges es una lista con name e imageUrl; pinta cada una con Widget.dom.image(badge.imageUrl, { alt: badge.name }).
  • La plantilla Chat de «Nuevo widget» lleva todo esto y un menú completo de parámetros.