Documentación Crea un espectáculo de luces
Referencia de la API de entornos
Todo lo que un paquete de entorno puede declarar, recibir e importar. Esta es la versión 1 de la API de entornos.
Esta es la referencia para quien escribe un entorno del espectáculo de luces. Crear un entorno es el recorrido paso a paso, y Cómo funciona el espectáculo de luces explica de dónde salen los datos.
Dentro de una misma versión de la API solo se añaden cosas. Un paquete escrito para la versión 1 sigue funcionando en cualquier Rainy que hable la versión 1.
El paquete
Un paquete es un archivo .zip:
my-show.zip
rainy-environment.json the manifest
index.js the entry module
style.css optional
preview.jpg the picture people choose it by
… your own modules, libraries, shaders, images, fonts
El manifiesto está en la raíz del zip, o dentro de una única carpeta de primer nivel, que es lo que da la descarga de un repositorio.
| Límite | |
|---|---|
| Tamaño | 20 MB comprimido, 60 MB descomprimido, 500 archivos. |
| Tipos de archivo | js mjs json css wasm; imágenes png jpg jpeg webp avif gif svg; fuentes woff2 woff ttf otf; shaders y texto glsl vert frag wgsl txt md; datos bin ktx2 hdr; multimedia mp3 ogg mp4 webm. |
| Se omiten | Los archivos ocultos, node_modules y lo que añaden los compresores (__MACOSX, .DS_Store). |
| Se rechazan | Rutas absolutas, .., enlaces, otros tipos de archivo y todo lo que supere los límites. |
El manifiesto
rainy-environment.json:
| Campo | ||
|---|---|---|
manifest |
obligatorio | Versión del formato de este archivo: 1. |
api |
obligatorio | Versión de la API de entornos para la que se escribió el código: 1. Rainy rechaza un paquete escrito para una versión que no habla. |
id |
obligatorio | De 2 a 32 caracteres: letras minúsculas, dígitos y guiones, empezando por una letra. Instalar un paquete con el id de uno ya instalado lo sustituye. classic está reservado. |
name |
obligatorio | Se muestra en Ajustes y en el espectáculo. Hasta 60 caracteres. |
version |
obligatorio | Con la forma 1.2.3. |
entry |
obligatorio | El módulo que se carga: un archivo .js o .mjs del paquete. |
description |
Una línea para el selector. Hasta 300 caracteres. | |
author, license |
Se muestran en Ajustes. | |
homepage |
Una dirección http o https. |
|
styles |
Hasta 8 hojas de estilo, que se cargan mientras el entorno está en escena y se retiran cuando se va. Consulta Dar estilo al reproductor. | |
preview |
recomendado | La imagen de Ajustes: una imagen 16:9; 960 × 540 es de sobra. Sin ella, el entorno recibe una placa en blanco. |
layout |
stage (por defecto) o immersive. Consulta Diseños. |
|
requires |
Cualquiera de webgl, webgl2, webgpu. En un dispositivo que no tenga alguno de ellos, el entorno no se puede elegir. |
|
i18n |
name y description por código de idioma: { "es": { "description": "…" } }. |
La clase del entorno
La exportación por defecto del módulo de entrada es una clase. Rainy crea una instancia cuando el entorno sale a escena. Solo los cuatro primeros métodos son obligatorios.
| Método | Cuándo |
|---|---|
mount(ctx) |
Una vez, para construirlo todo. Puede devolver una promesa. |
update(S) |
En cada fotograma, primero: leer el espectáculo, lanzar efectos, mover las letras. |
render(S) |
En cada fotograma, después: dibujar. |
unmount() |
Una vez, para liberar lo que la página no puede liberar por ti: contextos WebGL, workers, temporizadores. |
resize(cssW, cssH, { tier, lowPower, scale }) |
En cada fotograma, antes de update. Sal enseguida cuando no haya cambiado nada. Dibuja a cssW × scale por cssH × scale. tier es 0 (completo), 1 o 2 (el más ligero). |
setScore(score) |
Ha llegado la partitura de la canción, o ha desaparecido (null). |
setTrack(track) |
{ id, title, artist, cover } de la canción en escena, o null. cover es la dirección de una imagen o null. |
onTrackChange() |
Ha empezado otra canción. |
leave() |
Otro entorno toma el relevo. Tu capa ya se está desvaneciendo. |
dropLyrics() |
Retira las letras de escena ahora. |
Cuando un entorno falla
Rainy retira el entorno del escenario, quita todo lo que añadió y continúa en Clásico cuando:
updateorenderlanzan una excepción tres fotogramas seguidos,- cualquier otro método lanza una excepción,
- cargar y montar tardan más de diez segundos, o
- el entorno llama a
ctx.fail(error).
Sigue retirado en ese dispositivo hasta que se recargue la página o se actualice el paquete. El error queda registrado en la consola del navegador.
ctx
Lo que recibe mount.
ctx.root |
Tu propia capa sobre el escenario: un elemento vacío que lo ocupa entero. Los canvas y el DOM van aquí. Rainy la hace aparecer tras mount, la desvanece cuando te vas y la elimina. Ignora el puntero salvo que pongas pointer-events en algo de su interior. |
ctx.lyrics |
La línea de tiempo de las letras, que también llega en cada fotograma como S.lyrics. |
ctx.asset(path) |
La dirección de un archivo de tu paquete. Las importaciones relativas y url() en tus hojas de estilo también funcionan como siempre. |
ctx.ui.safeArea() |
{ top, right, bottom, left }, cada uno de 0 a 1: qué parte de ese lado del escenario cubre el reproductor ahora mismo. |
ctx.ui.addButton({ icon, title, onClick, pressed }) |
Un botón propio en la barra del espectáculo. icon es marcado SVG, de 14 píxeles. Devuelve { el, setPressed(on), remove() }. |
ctx.ui.toast(message) |
Un aviso breve. |
ctx.ui.fontFamily |
La fuente de la interfaz, para el texto que dibujes tú. |
ctx.locale |
Idioma de la interfaz: en, ca, es o pl. |
ctx.id, ctx.manifest |
Tu id y tu manifiesto. |
ctx.api |
La versión de la API de este Rainy. |
ctx.fail(error) |
No puedes continuar. Rainy vuelve a Clásico. |
@rainy/lightshow
El único módulo de Rainy que importa un paquete.
| Exportación | |
|---|---|
API_VERSION |
1. |
TAU, clamp(v, a, b), lerp(a, b, t), smooth(t) |
Matemáticas. smooth es un smoothstep de 0 a 1. |
hsl(h, s, l), mixHue(a, b, t), mixRgb(a, b, t), toWhite(c, t) |
Color. Un color es [r, g, b], cada uno de 0 a 255. |
rgba(c, alpha) |
Un color como cadena CSS. |
paletteFor({ accentHue, key, mode, label, genre, swap }) |
La paleta de una sección, tal como la calcula el director. Para cuando necesitas los colores de una sección antes de que suene. |
stepEase(beat), altBeat(beat) |
Movimiento fijado al pulso: un valor que avanza un paso en cada pulso con un breve deslizamiento, y otro que oscila de un lado a otro en pulsos alternos. |
hash(n) |
Un número pseudoaleatorio repetible de 0 a 1. |
floorIndex(sortedArray, t) |
Índice del último elemento que es como mucho t, o -1. Para los arrays de tiempos de la partitura. |
LEAD, HOLD_MAX, REST_AFTER, HELD |
Los tiempos de las letras que comparten todos los entornos, en segundos. |
pickTransition(F, lineIndex, last) |
Cuál de los seis relevos recibe una línea de letra: slam, fall, flicker, sweep, collapse o lift. Sigue a la música y nunca se repite dos veces seguidas. |
MIN_FLASH_GAP, PHRASE_BARS |
Los límites del director: segundos entre destellos completos, y compases de una frase. |
S: el espectáculo
Llega a update y a render en cada fotograma.
S.F |
El fotograma musical. Consulta más abajo. |
S.t |
El tiempo de la canción en segundos, suavizado y desplazado por el desfase de sincronización del usuario. |
S.now, S.dt |
Reloj real y duración del fotograma, en segundos. Para lo que no es música. |
S.running |
La canción está sonando. Lanza los efectos puntuales solo cuando lo esté. |
S.I |
Intensidad, de 0,3 a 1. |
S.pulse |
{ k, s, h }: envolventes de bombo, caja y charles, de 0 a 1. |
S.phrase |
Qué frase de ocho compases de la sección es esta, desde 0. |
S.palette |
{ a, b, c, w, deep }: primario, secundario, terciario, blanco teñido y ambiente. |
S.accentHue |
Tono del color de acento del usuario, de 0 a 360. |
S.dim |
Atenuador general, de 0 a 1. Multiplica tu luz por él. |
S.flash(amount, color) |
Pide un destello, de 0 a 1. Limitado a tres destellos completos por segundo, y suavizado con Reducir destellos. |
S.blind(amount) |
Pide un cegador: un baño de blanco más lento. |
S.burst(amount) |
Pide una ráfaga: un refuerzo que se extingue en aproximadamente medio segundo. |
S.flashAmt, S.flashColor |
Lo que hay que dibujar de los destellos en este fotograma. |
S.blinderAmt, S.burstAmt |
Lo que hay que dibujar del cegador y de la ráfaga. |
S.prefs |
Los ajustes del usuario: reduceFlashing, disableLasers, showBgBlur, lowPower (booleanos) e intensity (auto, chill, balanced o hype). |
S.lyrics, S.lyricsOn |
La línea de tiempo de las letras, y si las letras están en escena ahora mismo. |
S.songId |
Id de la canción en escena. |
F: la música
S.F, el fotograma musical.
Con partitura, F.scripted es true y todo es exacto. Mientras una canción se sigue analizando, Rainy estima los mismos campos a partir del audio: no hay anticipación (nextIn y dropIn valen Infinity), y section es una suposición.
F.t |
El tiempo de la canción en segundos. |
F.bands |
{ sub, bass, mid, high, air, rms, harm }, cada uno de 0 a 1: energía por banda, volumen, y lo tonal que es el sonido. |
F.hits |
{ k, s, h }: fuerza de un bombo, una caja o un charles que ha caído en este fotograma; si no, 0. |
F.beat, F.bar |
Números de pulso y de compás, con decimales. |
F.beatPhase, F.barPhase |
Posición dentro del pulso y del compás, de 0 a 1. |
F.beatInBar |
De 0 a 3. |
F.period |
Segundos por pulso. |
F.newBeat, F.newBar |
En este fotograma ha empezado un pulso o un compás. |
F.section |
{ idx, label, t0, t1, key, mode, energy, density }. label es intro, verse, build, chorus, drop, breakdown u outro. |
F.sectionProgress, F.sectionBar |
De 0 a 1 a lo largo de la sección, y compases desde que empezó. |
F.nextSection, F.nextIn |
La sección que sigue, y segundos hasta ella. |
F.dropIn |
Segundos hasta el próximo drop. |
F.buildProgress |
De 0 a 1 a lo largo de una subida. |
F.stopDepth, F.stopIn |
Cuánto se ha entrado en un silencio, de 0 a 1, y segundos hasta el siguiente. |
F.events |
Lo que ha ocurrido en este fotograma: { type, t }, con type igual a drop, impact, stop o riser. |
F.profile |
{ genre, intensity }. genre es edm, pop, rock, hiphop, latin, chill u orchestral. |
F.tempoConf |
Lo seguro que está el analizador del tempo, de 0 a 1. |
F.jumped |
El usuario ha saltado a otro punto, o ha cambiado la pista. Cambia de golpe, no deslices. |
F.running |
La canción está sonando. |
La partitura
Lo que recibe setScore: la canción entera de una vez.
score.duration |
Segundos. |
score.tempo, score.period |
Pulsos por minuto, y segundos por pulso. |
score.beats, score.downbeats |
Tiempos en segundos, ordenados. |
score.onsets.k, .s, .h |
Bombos, cajas y charles: { t, s }, dos arrays de la misma longitud con el tiempo y la fuerza. |
score.env, score.fps |
score.env[band] contiene un byte por fotograma, de 0 a 255, para cada banda de F.bands, a score.fps fotogramas por segundo. |
score.envAt(band, t) |
El valor de una banda en un instante, de 0 a 1. |
score.sections, score.sectionAt(t) |
Las secciones, como F.section. |
score.events, score.nextEvent(type, t, horizon) |
Los eventos, como F.events, y el siguiente de un tipo dentro de horizon segundos. |
score.beatAt(t), score.barAt(t) |
Números de pulso y de compás en un instante. |
score.stopDepth(t) |
Cuánto se ha entrado en un silencio en un instante. |
score.profile |
Como F.profile. |
Las letras
S.lyrics, la línea de tiempo de las letras. Merece la pena leerla cuando S.lyricsOn es verdadero.
lyrics.ready |
La canción tiene letras sincronizadas. |
lyrics.lines |
{ t0, t1, on, end, blank, words }. La línea sale a escena en on, y su última palabra termina en end. blank marca una línea instrumental. |
words |
{ text, s, e }: una palabra, con su inicio y su final. |
lyrics.adlibs |
Los coros, separados de las líneas: { s, e, k, words }. k es un número correlativo, útil para alternar lados. |
lyrics.aligned |
Los tiempos por palabra son exactos. Si no, se estiman a partir de la longitud de la línea. |
lyrics.lineIndex(t) |
La línea en escena en un instante, o -1. |
lyrics.resting(t, index) |
Nadie está cantando esa línea ahora mismo. |
lyrics.breakAt(t, index) |
{ a, b } cuando hay una pausa instrumental en curso; si no, null. |
lyrics.version |
Cambia cada vez que se sustituyen las líneas: una canción nueva, o la llegada de los tiempos exactos. |
Diseños
layout en el manifiesto indica cómo se organiza el reproductor alrededor de tu capa.
stage |
El reproductor tal como está, con su portada, sus controles y su cola. El espectáculo va detrás. |
immersive |
El espectáculo es toda la imagen. La cola se pliega y un botón de la barra la recupera por encima del espectáculo, la canción y sus controles pasan a ser una tarjeta pequeña en la parte inferior, y todo ello se atenúa mientras el puntero está quieto. |
Dar estilo al reproductor
Un entorno cambia el estilo del reproductor a pantalla completa con las hojas de estilo que enumera en styles. Rainy las carga cuando el entorno sale a escena y las retira cuando se va.
Mientras tu entorno está en escena, el reproductor tiene la clase ls-env-<id>. Empieza todas las reglas con ella:
#fullscreen-player.ls-env-my-show .fs-progress-fill {
background-color: rgb(var(--ls-a));
}
Clases de estado
En #fullscreen-player:
| Clase | |
|---|---|
lightshow-on |
El espectáculo está en marcha. |
ls-env-<id> |
Ese entorno está en escena. |
ls-immersive |
El diseño es inmersivo. |
ls-idle |
Solo en inmersivo: el puntero está quieto y el reproductor está atenuado. |
ls-queue-peek |
Solo en inmersivo: el usuario ha abierto la cola por encima del espectáculo. |
ls-lowpower |
El Modo de bajo rendimiento está activado. Quita tus filtros y sombras. |
mode-modern, mode-standard |
El modo de pantalla completa que eligió el usuario. El moderno tiene sus propios controles. El estándar mantiene la barra del reproductor de la aplicación en la parte inferior, así que .fs-player-controls y el botón de volumen están ocultos. |
layout-swapped |
La portada está a la izquierda y la cola a la derecha, que es lo predeterminado. Sin ella están al revés. |
Partes
| Selector | |
|---|---|
.fs-backdrop |
La portada desenfocada que hay detrás de todo. |
.ls-env-root |
Tu capa. |
.fs-brand |
La marca de Rainy, arriba a la izquierda. |
#fs-volume-btn, #fs-lightshow-btn, #fs-close-btn |
Los botones de la parte superior. |
.ls-hud, .ls-hud-btn |
La barra del espectáculo, con el tempo y el género, y sus botones, incluidos los tuyos. |
.fs-content |
La caja que contiene la canción y la cola. |
.fs-current-info |
La canción: portada, título, artista y controles. En un diseño inmersivo es la tarjeta. |
.fs-artwork-container |
La portada del álbum. |
.fs-title, .fs-artist |
El título y el artista de la canción. |
.fs-player-controls |
La barra de progreso y los botones. |
.fs-progress-container, .fs-progress-bar, .fs-progress-fill, .fs-time |
La barra de progreso, su parte rellena y los dos tiempos. |
.fs-buttons, .fs-control-btn, .fs-control-btn.play-pause |
Los botones de reproducción. |
.fs-queue-container |
El panel con la cola y las letras. |
Todo lo que no está en esta tabla es interno y puede cambiar sin aviso.
Variables
| Variable | |
|---|---|
--ls-a, --ls-b, --ls-c |
El color primario, secundario y terciario de la sección que está sonando, cada uno como r g b. Los mismos colores que S.palette. |
--ls-w |
El blanco teñido, como r g b. |
--ls-deep |
El color oscuro de ambiente, como r g b. |
--accent-primary |
El color de acento del usuario. |
--text-primary, --text-secondary, --text-tertiary |
Los colores de texto de Rainy. |
--bg-primary, --bg-secondary, --bg-tertiary, --bg-elevated |
Los colores de superficie de Rainy. |
--border-subtle |
El color de borde de Rainy. |
--radius-sm, --radius-md, --radius-lg, --radius-full |
Radios de esquina. |
--spacing-xs, --spacing-sm, --spacing-md, --spacing-lg, --spacing-xl |
Pasos de espaciado. |
--font-family |
La fuente de la interfaz. |
Usa una variable de la paleta como rgb(var(--ls-a)) o, con transparencia, rgb(var(--ls-a) / 0.5). Las variables de la paleta existen mientras el espectáculo está en marcha, y se deslizan de los colores de una sección a los de la siguiente.
Límites
- Limítate al reproductor a pantalla completa. Tus reglas no deben afectar a nada fuera de
#fullscreen-player.ls-env-<id>. - No ocultes ni tapes
#fs-close-btnni#fs-lightshow-btn, y mantén utilizables los controles de reproducción. - El CSS recibe la paleta, no el pulso. Dibuja en tu capa todo lo que se mueva con la música.
Herramientas
RAINY_DEV=1 RAINY_ENVIRONMENTS_DEV=<carpeta> |
Sirve paquetes sin empaquetar desde una carpeta, sin caché. Cada uno aparece como un entorno con la etiqueta Desarrollo, y ocupa el lugar del paquete instalado con el mismo id. |
python scripts/pack_environment.py <carpeta> [-o <salida>] |
Comprueba una carpeta como un servidor comprueba una subida y escribe <id>-<version>.zip, en dist por defecto. Los mismos archivos dan siempre el mismo zip. |
node --import ./tests/js/sdk-hook.mjs --test <archivos> |
Ejecuta los tests propios de un paquete en Node, con @rainy/lightshow resuelto como lo resuelve el navegador. |