Todas las páginas Referencia de la API de entornos

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:

  • update o render lanzan 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-btn ni #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.

Relacionado