Cómo funciona una acción
Lo que Vovó hace con una acción desde el momento en que una escena la muestra: lo que garantiza, y con qué no puede contar una acción. Para quien escribe acciones para entregar o vender; cómo escribir una está en Acciones.
Una página propia
Cada acción es un documento propio, en un marco que le da la página de la escena: su HTML, con su style.css y su script.js escritos dentro, el script al final, así que se ejecuta cuando el HTML ya está ahí. Una acción rota no tumba a las demás. Una escena muestra sus acciones una sobre otra, en su orden, la primera abajo.
El marco no recibe clics ni teclas: un overlay se mira, nunca se pulsa. Lo que hace quien lleva el directo, lo hace en el pad, en el panel de la acción o en Personalizar, y llega a la acción como un evento.
Una acción solo escucha un evento mientras una página abierta la muestra, y solo en el perfil activo. Sin ninguna página abierta, nada cuenta los seguimientos.
Sin red, nada guardado en el navegador
Una acción alcanza sus propios archivos y lo que Vovó le sirve, y nada más. Las imágenes, los sonidos, los vídeos y las fuentes vienen de los archivos de la acción, por su nombre, o de una dirección que dio un evento (un emote, una carátula, un archivo elegido en Personalizar), nunca de internet. Su código y sus estilos son solo script.js y style.css: ningún script ni hoja de estilos desde un archivo o desde fuera, nada de eval, nada de workers. fetch, XMLHttpRequest y WebSocket se rechazan, también para los archivos de la propia acción, así que los datos que necesita van en su script. El almacenamiento del navegador (localStorage, cookies, IndexedDB) no está ahí: lo que una acción guarda, lo guarda en vovo.state.
Lo que necesita de fuera se lo pide a Vovó, dentro de los permisos que declara: una línea en el chat, un webhook por su nombre, un sonido del pad, un clip en su reproductor oficial.
Cada página abierta la ejecuta
La misma acción se ejecuta allí donde su escena esté abierta: en OBS, en la ventana de vista previa de la escena, en una pestaña del navegador, en dos fuentes a la vez. Cada copia recibe los mismos eventos y dibuja lo mismo. Por eso una página solo dibuja y reproduce, y lo que debe pasar una vez se le pide a Vovó, que lo hace una sola vez para las páginas que lo piden al manejar un mismo evento: una línea en el chat, un sorteo, una voz, un webhook, un sonido del pad, una fuente en OBS, un evento propio de la acción.
Vovó distingue la llamada de una página de la de otra por el evento que se está manejando. Una llamada hecha después de que el listener terminara (tras un await, cuando acaba una animación, en un temporizador) indica el evento al que responde con { event: e }, el objeto que recibió el listener; sin eso, Vovó no puede distinguir una segunda página de una segunda vez.
vovo.on("raid", async (e) =>
{
const gift = await vovo.draw(["a hug", "a song", "a dance"]);
vovo.show("raid", { user: e.user, gift: gift.value });
vovo.chat.send(e.user + " gets " + gift.value + "!", { event: e });
});
Lo que una página empieza por sí sola no tiene ningún evento detrás: un setInterval de la acción corre en todas las páginas, y también lo que hace al cargar. Vovó solo puede guiarse entonces por lo que se pide (la misma línea en el chat, la misma voz, el mismo webhook o evento propio en 5 segundos es uno solo), así que lo que cuenta, o debe pasar una vez, va en el disparador timer, que es de la app y uno solo para todas las páginas.
Estado, nunca repetición
vovo.state lo guarda Vovó, no la página. Una página que carga (OBS al iniciarse, una fuente actualizada, el pánico al terminar, Vovó abierta de nuevo) lo tiene entero antes de que su script se ejecute, y una clave definida en una página llega a las demás al momento, sin aviso, ya que ellas manejaron el mismo evento. Los eventos nunca se repiten: una página que no estaba cuando llegó una incursión no se entera después. Por eso una acción guarda en su estado todo lo que debe volver a mostrar (la cuenta de una meta, los nombres de un sorteo, cuándo acaba una cuenta atrás) y dibuja a partir de él al cargar.
function draw()
{
document.getElementById("count").textContent = vovo.state.count || 0;
}
vovo.on("follow", () =>
{
vovo.state.count = (vovo.state.count || 0) + 1;
draw();
});
draw();
- Vuelve a definir la clave cuando cambia lo que guarda:
vovo.state.names = names.concat([user]). Una lista o un objeto cambiado en su sitio (push) no se guarda. - Cambia el estado en el propio listener, antes de cualquier
await: así todas las páginas parten del mismo estado y llegan al mismo. Tras unawaitotra página puede haber escrito ya, así que escribe lo que no depende de lo que hay (el nombre de un ganador, una hora), nunca uno más de lo que tiene. - Una clave guarda 64 KB como máximo, en JSON, y su nombre 64 caracteres.
Lo que es actual, y lo que es lectura continua
Cuatro eventos son un valor tanto como un momento: obs.scene, media.track, twitch.viewers y screen.shared. Una acción que carga recibe al momento el más reciente de cada uno que escucha, como si acabara de pasar, así que muestra la canción que suena sin esperar a la siguiente. Vuelve a llegar en cada carga, en cada página, sin ningún evento detrás: dibuja a partir de él, y no le respondas con lo que debe pasar una sola vez.
audio.level, screen.color, input.move y speech.text son lecturas, hasta 60 por segundo: se entregan y se olvidan, y solo se leen mientras una página abierta muestra una acción que las escucha. Mantén ligeros sus listeners, y deja que el CSS haga el movimiento.
Cargar, recargar y el pánico
Una página puede cargar en cualquier momento, y más de una vez: OBS inicia una fuente cuando su escena se muestra, puede apagarla mientras está oculta y actualizarla al volver a mostrarse, y Vovó carga una acción de nuevo cuando cambian su código o sus archivos. El pánico limpia todas las escenas a la vez y vuelve a cargar sus acciones, lo que detiene lo que estuvieran haciendo; cuando termina, cargan una vez más y parten de su estado. Nada llega a una acción durante el pánico, y nada de lo que llegó entretanto se reproduce después; el valor de un control se conserva, porque es estado.
Así que una acción vuelve bien solo con su estado, en cualquier momento, sin contar con nada que la página anterior dejara a medias.
El escenario
Una acción dibuja en un escenario en píxeles CSS cuyo lado corto es 1080: 1920 × 1080 para un directo en 16:9, sea cual sea su resolución (una fuente en 4K lo dibuja nítido al doble de tamaño), 1080 × 1920 para uno vertical, otra forma para una pantalla de otra forma. Su documento tiene el tamaño del escenario y es transparente, así que 100vw por 100vh es la imagen entera, y lo que no dibuja deja ver el juego. Una acción hecha para los directos de otras personas no da por hecha la forma: coloca las cosas desde los bordes y en porcentajes, y usa @media (orientation: portrait) para un directo vertical.
El navegador de OBS
OBS muestra las escenas en un navegador propio, más antiguo que el del editor y la ventana de vista previa de Vovó (Chromium 127 en OBS 32), que puede funcionar sin la ayuda de la tarjeta gráfica. Comprueba una función nueva de CSS o JavaScript contra esa versión antes de contar con ella, y mira la acción en el propio OBS antes de entregarla. Allí el sonido suena al momento, sin clic, y va al directo: nada que sea solo para quien hace el directo cabe en una acción.
Una página no tiene consola en OBS. Los errores que la acción no captura, y lo que Vovó tiene que decir de sus llamadas, llegan a la consola de Vovó con el nombre de la acción y la línea; console.log no. Para eso, abre la dirección de la vista previa en un navegador (vovo dev la muestra) y usa sus herramientas de desarrollo.
Ritmos y límites
- Chat: una línea de 500 caracteres; 20 líneas en 30 segundos para todas las acciones, una por segundo para cada una.
- Webhooks: 16 KB de JSON; 30 por minuto, uno por segundo para cada acción.
- Clips y vídeos: 3 esperando aprobación para cada acción.
- Cámaras: 4 mostrándose a la vez, y 4 ajustes de cámara por acción.
- Una llamada de voz: 300 segundos como máximo.
- Un botón mostrado trabajando: 15 minutos como máximo.
- Estado: 64 KB por clave.
- Un paquete: 200 archivos, 32 MB cada uno y 128 MB en total;
index.html,style.cssyscript.js, 2 MB cada uno.
Una llamada que supera su ritmo se queda fuera, nunca en cola: su promesa se rechaza, diciendo por qué.
Antes de entregarla
- Recarga la escena en medio de todo lo que hace: vuelve bien, a partir de su estado.
- Abre la escena dos veces, en OBS y en la ventana de vista previa, y activa cada disparador: una línea en el chat, un sonido, una cuenta.
- Activa y desactiva el pánico mientras muestra algo.
- Pruébala en un perfil vertical, y en el propio OBS.
- Pide solo los permisos que usa, y di qué es en Comportamiento: su autor, su sitio y una línea.
- Dale un id, y una versión mayor cada vez que la entregues, para que su actualización encuentre la acción que reemplaza y diga qué versión trae.
- Di bajo qué licencia la entregas, con su texto completo cuando las condiciones sean tuyas.