Cinética Tipográfica — KINETIC
Un lenguaje visual + renderizador cuadro a cuadro sin dependencias. Cada fotograma es una función pura del tiempo: imagen, subtítulos, efectos de sonido y música comparten una misma línea de tiempo, sin necesidad de fotogramas clave manuales.
Fue destilado a partir de dos piezas virales (desglose en references/viral-laws.md) y ya se ha completado una pieza completa en tasks/opus-kinetic-20261001/ (examples/opus-kinetic/).
Cinco Leyes (Revisa cada plano contra ellas)
- Una frase, un objeto: Dale a cada pulso semántico un objeto visual que el espectador reconozca al instante —cajas de selección, ondas sonoras, fotogramas clave, líneas de tiempo, barras de renderizado, bocas, cuadros de indicaciones. El movimiento también tiene sentido: "no" se tacha; "derribar" se derriba; "esconder detrás" se esconde realmente detrás del personaje.
- Sincronización: Las palabras grandes caen exactamente en la sílaba dicha (
at('palabra')); los cortes de planos puramente visuales caen en los beats musicales (beat(k)); cada acción visible tiene un efecto de sonido que solo responde a esa acción. - Una línea desde el principio hasta el fin: Una sola luz recorre todo el video —al principio es una línea de exploración encendida, en medio se transforma en línea de selección, línea base de onda sonora, efecto que atraviesa la escena, y al final converge en un punto que se apaga mientras aparece el crédito final. Se deforma antes que cortar.
- Ritmo: Después de una sección densa debe haber un respiro (un beat completamente silencioso, un texto pequeño sobre fondo blanco hueso); un número que cambia constantemente genera suspenso (en esta pieza: "fotogramas clave hechos a mano: 0").
- Calidad: Estrictamente cuatro colores, desenfoque de movimiento subfotograma, resplandor, pulsos de dispersión cromática, partículas en racimo; pequeñas anotaciones con traza de herramienta que invitan a detenerse.
Especificaciones de Idioma
| Elemento | Especificación |
|---|---|
| Paleta | Noche #0A0A0D · Hueso #F1EDE4 · Naranja señal #FF5A1F · Azul cobalto #3448FF (solo para "máquina/datos") · Gris #8B8983 · Grafito #26262C |
| Fuentes | Noto Sans SC (chino, peso 900 para impacto / 500 cuerpo) · Archivo VF (latín y números display) · JetBrains Mono (anotaciones) · Songti solo para respiros |
| Tamaño mínimo (1920×1080) | Anotación ≥28px · explicación ≥36px · palabra grande ≥76px; debe ser legible incluso al escalar a 390 px de ancho |
| Ocho acciones → sonido | Encender click · tirar línea zip · escanear scan · seleccionar blip/select · golpear impact/hit · decodificar tick · aspirar suck · onda de choque drop |
| Estado del personaje | Plano completo (W 1.0 / M ~1.2 / C ~1.4 con cortes y zooms) · Arrastrar selección para crear ventana · Ventana pequeña en esquina (inferior derecha) · Recorte para insertar personaje en escena (texto detrás) |
| Subtítulos | Una tarjeta por frase natural, sin puntuación, números de versión pegados (Opus5.5); fondo sólido noche con esquinas redondeadas 8px y texto 46px; color no leído gris → leído hueso con barrido continuo, borde anterior con luz naranja señal |
| Seguridad | Cualquier texto/gráfico delante del personaje debe mantener ≥30px de distancia del marco de la cabeza real (incluyendo sombrero); el texto detrás del personaje (bajo la capa de recorte) no tiene restricción. Verificar con qa_face.py, no a ojo |
Flujo de trabajo (comandos detallados en references/pipeline.md)
- Guión → tabla de beats: Escribe primero la locución natural, luego elige un objeto para cada pulso semántico (references/devices.md). No cambies la locución solo por el efecto.
- Locución y personaje: Genera según el flujo del proyecto (Fish Audio → HeyGen, etc.). Para grabación real, usa el metraje original directamente.
- Alineación:
tools/align_script.py— el guión es la referencia, ASR solo da tiempos; alineación global CJK + interpolación con detección de silencios (ASR tiende a arrastrar la primera palabra de una frase al silencio anterior, y trata el punto de5.5como un punto final). - Edición:
tools/build_edit.py— velocidad variable (sincroniza imagen y sonido sin afectar la boca), comprime respiraciones largas en cortes, inserta planos puramente visuales, y genera el únicotimeline.json(referencia para todos los pasos posteriores). - Material del personaje: Extraer fotogramas →
tools/vision_analyze.swift(máscara de retrato Vision + marco de cara/boca) →tools/prep_media.py mattes|faces|thumbs|barcode. - Escribir la pieza: Un módulo
film.js(consulta el ejemplo). Cada elemento se ancla conat('palabra')obeat(k); usa el vocabulario deengine/devices.js;ev(t, 'sfx')registra el efecto de sonido y el pulso posterior en el mismo lugar. - Verificación:
render.mjs --mode stillsextrae fotogramas para revisión →--mode qa+qa_face.py(0 infracciones para continuar). - Sonido:
render_dialog.py(ajusta el volumen entre fuentes) →--mode cues→sfx.py→mix.py(corta la música en los beats, baja la voz cuando hay música, sube cuando no, silencia los beats, ganancia estática + limitación de pico real para alcanzar la sonoridad objetivo). - Pieza final:
render.mjs --mode framesrenderiza en bloques sin pérdida → codificación H.264 única → verificación mecánica del proyecto.
Cómo usar para grabación real
Misma metodología: recorta al personaje, deja que las palabras grandes crucen por detrás, convierte los números de la locución en contadores/indicadores de progreso/anillos visibles, haz zooms en los cortes, ajusta el volumen general del audio original. El ejemplo de 10 segundos es una pieza real de locución en 4K (references/pipeline.md).
Portada (3:4 / 4:3)
Mismo motor genera fotogramas estáticos con el mismo estilo que la pieza final (comandos en references/pipeline.md, ejemplo en examples/opus-kinetic/cover.js):
- Personaje: Elige un fotograma del metraje original del avatar digital —rostro frontal, ojos abiertos, sonrisa natural. Primero filtra con
faces.jsonlusando la relación de aspecto del marco de boca y la frontalidad, luego decide visualmente. Extrae fotograma sin pérdida →vision_analyze … 1.0(máscara de resolución completa) →prep_media.py cutout(separa el color de la pared del borde del cabello y del sombrero para que no aparezca un borde blanco sobre fondo oscuro). - Diseño: Título ≥150 px (calculado sobre 1080 px de ancho), debe ser legible incluso al escalar a 180 px de ancho; el logotipo de la pieza final se esconde detrás del personaje (en 3:4 usar estilo cabecera de revista, con la parte superior del sombrero presionando el borde inferior del título); la última palabra del título termina con un punto de luz. Además, como máximo 2–3 objetos pequeños de la pieza final (asas de selección, etiquetas de capa, un REC tachado, una línea de estadísticas). No dejes que el texto y el sombrero se toquen: o se superponen claramente, o guardan ≥40 px de distancia.
- Seguridad y plataforma:
--mode qa+qa_face.pydebe tener 0 infracciones; el 10% inferior de la imagen está reservado para los indicadores de reproducción y duración de la plataforma. - La primera línea del módulo llama a
setSize(w, h); los números del diseño se colocan en función del centro del rostro; al cambiar de fotograma no es necesario modificar el código.
Errores ya cometidos (no los repitas)
- ASR omite las primeras palabras del clip: añade 1 segundo de silencio antes de enviarlo a ASR y luego recórtalo.
- El punto en los números de versión (
5.5) no es un punto final: tanto la alineación como los subtítulos deben tratarlo como un separador decimal. ffmpeg -ss … -c copyretrocede al fotograma clave anterior, haciendo que el inicio del clip sea impreciso; para puntos de inicio exactos, decodifica y extrae fotogramas/audio y verifica con correlación cruzada.- La memoria caché de fotogramas recicla ImageBitmap: las imágenes de uso prolongado (miniaturas, fuentes de nubes de puntos) deben mantenerse con
loadImagepor separado. - El pico de la voz TTS es muy agudo (PLR puede alcanzar 24 dB); subir el volumen directamente provocará recorte; primero normaliza el volumen dinámico con
loudnorm(con límite de pico real) y luego mezcla. - zsh no divide variables por espacios: usa scripts bash para el renderizado por bloques.
- El
loudnormdinámico hace que el equilibrio entre voz y música "respire"; la masterización final solo usa ganancia estática + limitación. - Después de cambiar la música a WAV completo, el contenido por encima de 19 kHz (más el generado por el limitador) puede hacer que el pico real después de codificar AAC sea aproximadamente 1 dB más alto que la masterización:
loudness.lowpass: 19000enmix.jsondebe estar al final de la cadena de masterización para mantener el límite después de la codificación. - Antes de reemplazar la versión de vista previa por la completa, verifica la alineación con correlación cruzada (Epidemic previsualiza y WAV alineados muestra por muestra) y luego ajusta
fullDbsegún la diferencia de sonoridad entre ambas, para que la proporción entre voz y música sea consistente con la versión aprobada.