Exportación de archivos
Paquete: @tiendana/utils/logomark
Archivos del logomark para quien no puede leer tokens CSS: stickers animados y fragmentos de vídeo como APNG, WebP animado o GIF, cada fotograma como PNG en un zip, cualquier still como PNG o WebP, y las expresiones de p18 como SVG. Los fotogramas los pinta paintMark a partir de ClipPlayer, así que un archivo es exactamente lo que reproduce el elemento.
Para descargar los archivos ya hechos, en cualquier formato y tamaño, usa Descargas del logomark: genera con estas mismas funciones, en el navegador, también los videos para CapCut.
Características
✅ APNG - Un archivo, con alfa y sin pérdida; ffmpeg lo lee para vídeo
✅ WebP animado - Lo que reproduce Android de forma nativa y aceptan las apps de chat
✅ GIF - Lo reproduce cualquier app; transparencia de 1 bit
✅ Secuencia PNG - Todos los fotogramas numerados en un zip, para editores y ffmpeg
✅ Stills - Cualquier still, con sus acentos, como PNG o WebP sin pérdida
✅ SVG - Las cuatro expresiones de p18 desde los paths originales
✅ Encuadre común o ajustado - Todo un set a la misma escala, o cada archivo lleno con su expresión
✅ Progreso y cancelación - onProgress y un AbortSignal
Los exportadores dibujan en un OffscreenCanvas, así que se ejecutan en el navegador o en un worker. Para generar archivos desde Node, el repositorio incluye desde 0.5.0 un script de stickers que pinta con Skia.
Opciones: ClipExport
Los exportadores animados reciben el mismo objeto:
| Campo | Tipo | Descripción |
|---|---|---|
name | ClipName | El clip a exportar |
fps | number | Fotogramas por segundo; el GIF admite hasta 50 |
size | number | Lado del fotograma, en px |
tones | LogomarkTones | Los tonos con que se pinta; ver Colourways |
style | 'flat' | 'sticker' | flat por defecto; sticker añade el contorno troquelado y necesita tones.keyline |
framing | 'shared' | 'tight' | shared por defecto; ver El encuadre |
loop | boolean | En un bucle se descarta el último fotograma, que repite el primero; salvo en un clip que holds, cuyo último fotograma es su expresión |
plays | number | Veces que se reproduce el archivo; 0, por defecto, para siempre. Un clip que holds (como form-error) se lee mejor una sola vez, terminando en su expresión |
onProgress | (done, total) => void | Se llama a medida que avanzan los fotogramas |
signal | AbortSignal | Detiene la exportación entre dos fotogramas; la promesa se rechaza con el motivo de la señal |
import { clipApng, readLogomarkTones } from '@tiendana/utils/logomark';
const el = document.querySelector('tdn-logomark')!; // con las propiedades --logomark-* fijadas por la página
const tones = readLogomarkTones(el);
const blob = await clipApng({ name: 'hello', fps: 30, size: 512, tones, style: 'sticker', loop: true });
readLogomarkTones(el) solo lee las propiedades --logomark-* que la página fija (con el mixin de Colourways o con CSS); el atributo colourway no las fija. Sin esas propiedades, pasa LOGOMARK_COLOURWAYS.primary (desde 0.5.0) o tonos literales, por ejemplo primary: { face: '#00D47E', body: '#1B434C', track: '#DBE1E2', error: '#F54F4F', keyline: '#FFFFFF', sun: '#FF7834', sunLight: '#FFDECC' }. Sin sun y sunLight, halloween, christmas y warning pierden sus tonos sol (ver Colourways). Ver readLogomarkTones.
Opciones: StillExport
stillImage recibe name (StillName), size, tones, style y framing como arriba, y type: 'image/png' por defecto o 'image/webp' (sin pérdida).
Funciones
| Función | Devuelve | Descripción |
|---|---|---|
clipApng(options) | Promise<Blob> (image/apng) | El clip como PNG animado, a fps |
clipWebp(options) | Promise<Blob> (image/webp) | El clip como WebP animado sin pérdida, a fps |
clipGif(options) | Promise<Blob> (image/gif) | El clip como GIF, a fps (hasta 50) |
clipPngSequence(options) | Promise<Blob> (application/zip) | Cada fotograma como PNG numerado (<clip>-000.png...) en un zip sin compresión |
stillImage(options) | Promise<Blob> | Un still, con sus acentos, como PNG o WebP |
clipFramePng(player, t, size, tones, style?, type?) | Promise<Blob> | Un fotograma del clip en t segundos, en el cuadro común, con alfa: PNG, o WebP sin pérdida si type es 'image/webp' |
expressionSvg(expression, tones) | string | Una de las cuatro expresiones de p18 como SVG, desde los paths originales |
clipFrameCount(name, fps) | number | Fotogramas de un clip a fps, con ambos extremos incluidos: el primero y el último son SMILE |
import { clipFrameCount, clipGif, clipPngSequence, clipWebp, stillImage } from '@tiendana/utils/logomark';
clipFrameCount('hello', 30); // 46: Math.round(1.5 * 30) + 1
const webp = await clipWebp({ name: 'hello', fps: 30, size: 512, tones, loop: true });
const gif = await clipGif({ name: 'celebrate', fps: 25, size: 256, tones, style: 'sticker', framing: 'tight', loop: true });
const once = await clipGif({ name: 'form-error', fps: 25, size: 256, tones, plays: 1 });
const zip = await clipPngSequence({ name: 'congrat', fps: 24, size: 512, tones });
const png = await stillImage({ name: 'love', size: 1024, tones, style: 'sticker', framing: 'tight' });
Progreso y cancelación
const controller = new AbortController();
const webp = await clipWebp({
name: 'christmas', fps: 30, size: 1024, tones, loop: true,
onProgress: (done, total) => (bar.value = done / total),
signal: controller.signal,
});
cancelButton.onclick = () => controller.abort();
GIF
El GIF usa una paleta para todos los fotogramas: los 255 colores más pintados, que son los tonos del colourway, y el resto del antialiasing en su color más cercano. Su transparencia es de 1 bit: cada píxel se pinta o no, así que el borde del troquelado se ve escalonado sobre fondos oscuros. GIF mide el tiempo en centésimas de segundo y los navegadores ralentizan los fotogramas de menos de dos, así que fps admite hasta 50; 25 fps es exacto.
Navegadores
- PNG y APNG se codifican en la librería, no con el canvas: Chrome codifica el PNG de un canvas solo en tiempo libre, que una pestaña en segundo plano recibe una vez por segundo.
- WebP usa el codificador sin pérdida del canvas. Safari no codifica WebP:
clipWebp, ystillImageyclipFramePngcon'image/webp', lanzanthis browser cannot encode image/webp.
Stills en SVG
expressionSvg(expression, tones) acepta 'smile', 'congrat', 'play' o 'error' (el tipo ExportExpression) y devuelve el SVG como texto. En ERROR la sonrisa y la X usan tones.error, o el tono de la cara si no hay.
import { expressionSvg } from '@tiendana/utils/logomark';
const svg = expressionSvg('congrat', tones);
El encuadre
framing decide dónde queda la marca en el cuadrado del archivo:
framing | La marca | Úsalo para |
|---|---|---|
'shared' (por defecto) | Siempre al mismo tamaño, más o menos la mitad del archivo | Un set de stickers que se ven juntos, como el pack de WhatsApp |
'tight' | Lo más grande que cabe: el cuadrado rodea lo que pinta ese clip o still, con el contorno y un 4 % de aire | Un archivo suelto: una publicación, un video, un icono pequeño |
El cuadro común
Todo export shared usa el mismo cuadrado, para que un conjunto de stickers dibuje la marca al mismo tamaño.
| Función | Descripción |
|---|---|
exportFrame() | Devuelve { span, focus }: el lado del cuadrado y su centro, en las unidades de la marca |
measureExportFrame() | Recalcula ese cuadrado reproduciendo todos los clips; es lo que exportFrame() debe igualar |
exportFrame() es la unión de lo que pinta cada clip (la marca por su rig, los pops y los disfraces incluidos, y cada accent a su máximo), ampliada por el contorno del sticker y con un margen del 4 % del cuadro en cada lado. Se guarda como constante para que el primer logomark de una página no tenga que reproducir todos los clips; el test del repositorio falla si measureExportFrame() deja de coincidir. measureExportFrame() es costosa y está pensada para ese test, no para uso en producción.
Colocar la marca
| Función | Descripción |
|---|---|
exportPlacement(size) | La marca en un cuadrado de size px, en el cuadro común |
clipPlacement(name, size, framing?) | La marca en el export del clip name; con 'tight' mide el clip una vez y lo recuerda |
stillPlacement(name, size, framing?) | La marca en el export del still name |
clipBounds(name) / stillBounds(name) | Lo que pinta un clip a lo largo de toda su duración, o un still, en unidades de la marca |
Úsalas para previsualizar un archivo antes de generarlo, pintando con paintMark en la misma colocación.
Ver También
- Descargas del logomark - todos los archivos, sin código
- Canvas propio -
ClipPlayerypaintMark - Stickers - packs de WhatsApp y GIFs, generados desde Node
- Colourways - los tonos