BetoDeck: cómo terminé programando mi propio Stream Deck

agosto 28, 2026
·
Beto Castelao

El problema: demasiadas pestañas para pasarla bien

Con un grupo de amigos empezamos a streamear en Twitch y Kick sin ninguna pretensión: la idea era jugar, cagarnos de risa y que quien quisiera nos viera. Nada de esto es nuestro trabajo, así que la última cosa que quería era que se sintiera como uno.

El problema es que ni el streaming más casero se salva de la fragmentación de herramientas. Para tener una transmisión mínimamente prolija terminás manejando en simultáneo:

  • OBS Studio para cambiar de escena entre el juego, las intros y las pausas.
  • Twitch e Kick al mismo tiempo, cada uno con su propio chat, su propia forma de cambiar título/categoría y su propia API.
  • Discord para hablar con los que juegan conmigo, sin que el audio de la llamada se cuele donde no corresponde.
  • Spotify para la música de fondo.
  • Un mezclador de audio para no tapar la voz con el juego, ni el juego con Discord.
  • Y, en paralelo, estar mirando el chat para no perderme nada mientras jugás algo que te exige las dos manos.

Todo eso son mínimo seis u ocho ventanas o pestañas abiertas, cada una peleando por tu atención. La solución «de mercado» es un Stream Deck físico, pero son caros, y esto lo hacemos por diversión — no íbamos a poner esa plata en un hobby de fin de semana. Así que, siendo programador, hice lo que cualquier programador con demasiado tiempo libre y una tablet gráfica en el escritorio haría: me construí el mío.

Así nació BetoDeck.


¿Qué es exactamente BetoDeck?

BetoDeck es mi centro de control personal para transmitir sin volverme loco. Es una aplicación web que corre localmente y que centraliza todo lo que antes tenía repartido en mil pestañas: control de OBS, chat unificado de Twitch y Kick, mezclador de audio, reproductor de Spotify, gestión de título/categoría en vivo, y un panel de macros y automatizaciones a medida.

La uso desde una tablet XP-Pen Artist 15.6 apoyada al lado del monitor principal, así que todo el diseño está pensado para tocarse con el lápiz o el dedo sin tener que mirar el teclado ni salir del juego. De ahí también sale la estética: una interfaz oscura, con acentos en cian y magenta, tipografía monoespaciada y un aire ciberpunk que, sinceramente, hace que administrar un stream se sienta más a pilotear una nave que a rellenar un formulario.


Arquitectura: mantenerlo simple, mantenerlo rápido

Cuando empecé a pensar cómo construir esto, la prioridad número uno era la latencia. Un panel de control que tarda en reaccionar es peor que no tener panel: si aprieto «cambiar de escena» quiero que cambie ya, no medio segundo después mientras mis amigos me putean por el micrófono abierto.

Con esa premisa, descarté cualquier framework pesado y armé una arquitectura deliberadamente chica:

┌─────────────────────┐         WebSocket / HTTP        ┌──────────────────────┐

│   BetoDeck Frontend  │ ───────────────────────────────▶│   BetoDeck Server     │

│  HTML5 + CSS3 + JS   │◀─────────────────────────────── │   Node.js (bridge)    │

│  vanilla + Vite      │        estado en tiempo real     └──────────┬────────────┘

│  (tablet XP-Pen)     │                                             │

└─────────────────────┘                                             │

                                            ┌────────────────────────┼────────────────────────┐

                                            ▼                        ▼                         ▼

                                   OBS WebSocket v5           Twitch (Helix + IRC)        Kick (sockets)

                                   control de escenas,        chat, título,               chat, título,

                                   audio, grabación, live     categoría, eventos          categoría, eventos

Runtime — Node.js como puente local. El servidor no vive en ningún hosting: corre en mi propia máquina, al lado de OBS, y actúa de intermediario entre la interfaz que veo en la tablet y todos los servicios externos. Habla HTTP para las acciones puntuales (guardar un título, disparar una macro) y WebSockets para todo lo que necesita sentirse instantáneo: el estado de las escenas, los niveles de audio, los eventos del chat y las alertas.

Frontend — HTML5, CSS3 y JavaScript vanilla, empaquetado con Vite. Descarté React (y cualquier otro framework de componentes) a propósito. Para un panel que se actualiza constantemente con datos en tiempo real —niveles de VU, mensajes de chat, contadores— el overhead de un virtual DOM no aporta nada que no pueda resolver con manipulación directa del DOM y un puñado de funciones bien organizadas. Vite se usa solo como empaquetador y servidor de desarrollo, para tener recarga en caliente mientras itero sobre la interfaz, sin traer un framework entero solo por eso.

Conectividad — tres integraciones bien distintas entre sí:

  • OBS WebSocket v5: el protocolo oficial de OBS Studio. Se usa tanto para comandar (cambiar de escena, iniciar grabación, arrancar el live) como para escuchar (saber qué escena está al aire, qué fuentes de audio están activas, el estado de la transmisión) y mantener esa información sincronizada en la interfaz sin que yo tenga que hacer nada.
  • Twitch Helix + IRC: Helix (la API REST de Twitch) se encarga de todo lo que es actualizar título y categoría del canal; el chat, en cambio, se escucha por IRC, que es el protocolo histórico de Twitch para mensajes en tiempo real.
  • Kick (sockets): Kick no comparte infraestructura con Twitch, así que hubo que resolver una integración completamente aparte para leer su chat y actualizar título/categoría — con su propio modelo de eventos y sus propias categorías, que además no coinciden con las de Twitch.

Tener tres proveedores distintos hablando protocolos distintos (WebSocket binario/JSON de OBS, IRC de Twitch, sockets propios de Kick) y lograr que todos aparezcan fusionados en una sola interfaz coherente es, honestamente, la parte más entretenida de todo el proyecto.


Recorrido por la interfaz

El panel fijo: chat global y estado del sistema

La mitad izquierda de la pantalla es fija y siempre visible, sin importar en qué pestaña del panel derecho esté trabajando. Ahí vive el GLOBAL_CHAT_FEED: un feed que fusiona en una sola línea de tiempo los mensajes de Twitch y Kick, cada uno etiquetado con su plataforma de origen ([TW], [KK]) y coloreado distinto para diferenciarlos de un vistazo. Arriba de todo tengo un botón grande de mute de Discord para la llamada — el que más uso, sin excepción, porque es el que necesito poder tocar a ciegas cuando alguien grita algo que no era para el stream.

Debajo del chat, un bloque de estado muestra la escena activa de OBS en tiempo real («ESCENA · Bread&Fred») junto con las fuentes de audio que están sonando en ese momento («AUDIO ACTIVO · 2»: SpotifySound, Bread&FredSound), y más abajo un Alert Feed con el log de eventos: cambios de escena reportados por OBS ([OBS] 11:02:42 a. m. Escena → EstamosIniciando) y eventos de las macros de juego ([MUERTES] 10:55:41 a. m. +1 · van 1). Es, en la práctica, la consola de logs del stream, siempre a la vista.

En la barra superior, un vistazo rápido me confirma que todo está sano: LINK OK, usuarios de Twitch y Kick conectados (TW betoglhf / KK betoglhf), uso de CPU y FPS de OBS (CPU 1% FPS 60 DROP 0%), y el estado del live (LIVE OFF AIR o en vivo, con espectadores por plataforma).

Directorio de OBS: todas mis escenas, a un toque

La pestaña OBS · Directorio lista todas mis escenas configuradas como una grilla de botones: desde las de transición (EstamosIniciando, EstamosTerminando, YaVolvemos) hasta una escena por cada juego que jugamos con el grupo (TheQuarryEsc, PubgEsc, PeakEsc, DeadbyDBD, FortniteEsc, PartyAnimalsEsc, DiabloEsc, Fallout, Palworld, Directive8020, entre otras), más escenas utilitarias como Counter1.6, capturas de pantallas secundarias (EscenaPantalla2, EscenaPantalla3) y overlays especiales como ChatPop, Alertas o bread&fredKills. La escena activa se resalta con un borde magenta y un punto de estado, así que en medio del juego solo necesito reconocer el color, no leer el texto.

Cada botón dispara una llamada por OBS WebSocket que cambia de escena al instante y, gracias al listener permanente de eventos, el resto de la interfaz (el bloque de estado del panel izquierdo, las fuentes de audio activas) se actualiza solo, sin que yo tenga que refrescar nada.

Mezclador de audio multicanal

La pestaña Audio · Sonidos es un mezclador completo con un slider por canal — micrófono, audio de Discord, Spotify, y una fuente separada por cada juego que suena distinto (FortniteSound, DiabloSound, PubgAud, DBDSound, Quarry, PartyAnimalsSounds, UniversimSound, SonidoChrome, entre otros). Cada canal muestra su estado (Activo/muteado), el nivel actual en dB y un botón de mute individual, además de un pequeño VU-metro debajo del slider para ver el nivel en tiempo real. Esto reemplaza directamente lo que antes resolvía saltando entre el mezclador de Windows, el de OBS y el de Discord — ahora está todo en un solo lugar, sincronizado con las fuentes reales de audio de OBS.

Spotify integrado

En Spotify · Stream puedo elegir la playlist activa (en este caso, «Stream ★»), ver la lista completa de temas con artista, y controlar la reproducción con Play, Stop y Cambiar (que elige un tema al azar dentro de la playlist) sin tocar la app de Spotify en ningún momento. Es un detalle chico, pero significa una ventana menos abierta y una interrupción menos en medio de una partida.

Título y categoría, para las dos plataformas a la vez

Esta es la pestaña que más dolores de cabeza me ahorró. Twitch y Kick manejan categorías de juegos completamente distintas —ni el listado ni los IDs coinciden— así que la pestaña Live · Título separa ambos formularios: uno busca y guarda la categoría en Twitch vía Helix, el otro hace lo mismo contra la API de Kick, cada uno con su propio título editable y su botón de guardado independiente. Antes esto significaba entrar al dashboard de cada plataforma por separado cada vez que cambiábamos de juego; ahora son dos textareas y dos botones, sin salir del panel.

Macros y automatización: el toque gamer

Dev / Chat · Macros es el panel que más uso durante el juego en sí, porque agrupa acciones de un solo toque para todo lo que antes eran combinaciones de teclado o clics en otra ventana:

  • Control de stream: INICIAR REC, INICIAR LIVE.
  • Toggles de audio con estado visual (punto verde/rojo): Microfono, Discord, Spotify, SonidoJuegoAct.
  • EscenaJuegoAct: un atajo que apunta siempre a «la escena del juego que estoy jugando ahora», sin tener que recordar cuál es.
  • PANIC: el botón de pánico — corta todo lo sensible de una sola vez cuando pasa algo que no tiene que ir al aire.
  • Controles de Spotify replicados acá (SPOTIFY PLAY, SPOTIFY NEXT, SPOTIFY STOP) para no tener que cambiar de pestaña.
  • CLEAR CHAT: limpia el feed del chat unificado.
  • Accesos directos de contenido: Ultimo Video De Youtube, Canal Discord, BetoDeck (probablemente enlaces rápidos que uso para responder al chat cuando preguntan).
  • CLIP 90S: dispara la captura del buffer circular de OBS de los últimos 90 segundos — para guardar esa jugada o ese momento de chat sin cortar la transmisión.
  • MUERTE +1 / RESET 0: un contador de muertes hecho a medida. Cada toque suma uno, queda registrado en el Alert Feed ([MUERTES] 10:55:41 a. m. +1 · van 1) y, por dentro, actualiza un archivo local que un source de texto en OBS lee y muestra en pantalla — así el contador se ve al aire sin que yo tenga que escribir nada a mano.
  • NUEVO MSG: para mandar un mensaje manual al feed, típicamente para avisos del sistema tipo «Panel táctil sincronizado correctamente.»

Una de las macros más lindas de ver en funcionamiento es la vista previa: cuando activo la pestaña de macros, arriba aparece un recorte en vivo de la escena que está al aire en ese momento (por ejemplo, la escena EstamosIniciando con el cartel «ESTAMOS ARRANCANDO…»), así confirmo de un vistazo que lo que la gente ve coincide con lo que yo creo que está pasando — sin necesidad de tener OBS abierto en otro monitor.


Bajo el capó: detalles que no se ven en las capturas

Algunas decisiones técnicas que no son evidentes mirando la interfaz, pero que son las que hacen que todo esto se sienta sólido en vivo:

Estado centralizado, no consultas bajo demanda. En lugar de que la interfaz le pregunte al servidor «¿qué escena está activa?» cada vez que la necesita, el servidor Node.js mantiene una conexión persistente por WebSocket con OBS, Twitch e Kick, escucha sus eventos, y empuja los cambios al frontend apenas ocurren. Esto es lo que permite que el contador de CPU/FPS, la escena activa o el estado de «Activo» de cada canal de audio se actualicen solos, sin polling y sin que la interfaz tenga que refrescarse.

Un feed unificado sobre dos formatos distintos. Twitch IRC y los sockets de Kick no comparten ni estructura de mensaje ni modelo de eventos. El servidor normaliza ambos a un formato común antes de emitirlos al frontend, que es lo que permite que el chat se vea como un solo feed coherente en lugar de dos widgets pegados con cinta.

Automatizaciones con estado propio. El contador de muertes no es solo un botón que suma un número en pantalla: persiste en un archivo local que OBS lee como fuente de texto, lo que significa que sobrevive a un reinicio del panel y se puede reutilizar desde cualquier escena sin reconfigurar nada.

Diseño pensado para lápiz y dedo, no para mouse. Al usar la tablet XP-Pen como pantalla de control, cada botón está dimensionado y espaciado pensando en precisión de dedo/lápiz, no de cursor. Los degradados y bordes con glow en CSS no son solo estética: ayudan a que el estado activo/inactivo de cada botón se distinga de un vistazo rápido, sin tener que leer texto en medio de una partida.


Filosofía: programar para resolver problemas propios

Más allá de la lista de funcionalidades, lo que más me gusta de BetoDeck es lo que representa: la idea de que programar no tiene que estar separado de las cosas que uno hace por diversión. No lo armé para venderlo ni para sumar una línea genérica al currículum — lo armé porque un viernes a la noche, en medio de una partida con amigos, me di cuenta de que estaba perdiendo más tiempo cambiando de ventana que jugando.

Ese es, en definitiva, el resumen de BetoDeck: agarrar un problema chico y concreto del día a día, y resolverlo con las herramientas que uno ya sabe usar. Que programar y transmitir con amigos se sientan, por una vez, como la misma actividad.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *