Sistema de diseño de empaquetado para locución Remotion (v1 hub)
Objetivo de estilo: replicar el empaquetado HUD del vídeo de referencia (las imágenes de referencia están en el directorio refs/ del proyecto). Este archivo es el hub de restricciones duras: reglas de hierro + semántica de tokens + referencia rápida de componentes + colección de errores; los detalles de cada sección se encuentran en references/ (depósito de las conclusiones de la comparación en profundidad de 77 diferencias del 2026-07-16). Cualquier decisión visual que no esté escrita en el sistema debe completarse primero en el archivo de la sección correspondiente antes de escribir código.
Tabla de rutas de secciones (qué archivo leer para qué)
| Sección | Archivo | Qué abarca |
|---|---|---|
| Tabla de especificaciones (consulta antes de escribir) | references/specs.md | Fuente de verdad de valores medidos del vídeo de referencia: ancho de tarjeta, tamaño de fuente, posición, duración de fotogramas de animación. Consúltala antes de ensamblar. Si no está en la tabla, mide y rellena. Prohibido estimar a ojo |
| Composición del diseño | references/layout.md | Tres zonas, mecanismo takeover (A-level sin PiP, atenuar cámara lenta ya rechazado), un centro de gravedad por pantalla, plantillas de agrupación, puntos de encaje |
| Tipografía | references/typography.md | Única fuente más grande, obligación h1, sándwich hero, variante SideLabel title |
| Color y textura | references/texture.md | Bloques tipo gelatina/glow, variantes claras/oscuras de SURFACE, única línea de especificación de sello, ≤2 gamas de color por pantalla, regla detallada de "sin texto desnudo en fondo claro" |
| Animación | references/motion.md | useEnter/useExit, subdivisión de tiempo, build-up, intervalo de servicio, Breathe, pantalla limpia |
| Diseño de información | references/infographic.md | Selección de gráficos, metáforas visuales, waffle, tres capas de números grandes, vocabulario de micrográficos |
| Narrativa/Ritmo/Subtítulos/Material/Sonido | remotion-assembly references/ | narrative / rhythm / subtitle / broll / audio |
| Colección de errores (síntoma → índice de solución) | Skill independiente remotion-gotchas-index | Aquí se consulta la ubicación de la solución de cada "Error #NN" en el texto completo; errores de renderizado o imágenes incorrectas: consulta aquí primero |
Lista de sustrato de ingeniería (substrate — comprobar que está presente antes de arrancar un nuevo proyecto)
Este sistema de diseño es un sustrato compartido en todo el repositorio, no se reconstruye en cada vídeo. Los siguientes archivos son el requisito previo para todo el flujo (assembly «revisión de entrada → generación de fotogramas → tres compuertas» + compuerta motion §12); un nuevo proyecto reutiliza estos archivos por defecto, solo añade su propio composition + subtítulos + Scene, y no reconstruye el sustrato. Los lectores que empiezan desde cero (prohibido leer src/) suelen fallar aquí: primero comprueba según esta tabla que los archivos estén presentes. Para valores concretos, abre el archivo correspondiente y léelo, no esperes que el skill te los copie.
| Archivo de sustrato | Qué contiene | Cómo usarlo al empezar desde cero |
|---|---|---|
src/design/tokens.ts | Única fuente de verdad de valores: COLOR (cuatro semánticas + hex de colores base), SURFACE, FONT, GRADIENT, escalera SIZE (kicker…mega), GRID, RADIUS, SAFE, fotogramas MOTION | Para valores concretos como SIZE.mega, hex de color semántico, etc., lee directamente este archivo — el skill no los copia a propósito (para evitar desviación entre la instantánea y el código, ver §1). Si el archivo no existe, falta el sustrato; créalo primero |
src/design/*.tsx | Librería de componentes (tabla completa §3: SideLabel/HeroText/Chip…) + FontGuard.tsx (guardia de fuentes, error #01) + qc.tsx (Sonda QC QcProbe: lee fotograma a fotograma las cajas [data-qc] para detectar solapamientos, error #29) | Antes de escribir elementos de empaquetado, consulta la tabla de componentes §3 para localizar el archivo |
src/design/motion.ts | Hooks base useEnter/useExit/usePop + constantes MOTION | Los hooks referenciados en las reglas de motion.md están aquí |
src/design/fonts.ts | Registro de fuentes locales @fontsource (error #01: las fuentes web por red fallan silenciosamente a Songti) | package.json debe incluir sideEffects que lo contenga |
src/koubo/scenes/shared.tsx | Cuatro piezas de compuerta de la capa de ensamblaje Enter/DimAfter/Exit/ClearOut (motion §12) + Place caja de posicionamiento + qcAllow lista blanca de encaje QC (assembly §2.5 compuerta ①) | Al ensamblar un Scene, envuelve directamente con estos envoltorios, no uses opacidad manual |
src/Root.tsx | Registro de compositions (existente <Composition id="Koubo-0715-01" fps={30} …/>) | Para un nuevo vídeo, añade una línea <Composition> aquí, id a elección; el script de renderizado por lotes debe coincidir con este id (ver assembly §6 render-service cambiar id) |
src/koubo/ | Específico de cada vídeo: subtitles-<nombre>.ts / SubtitleTrack.tsx / <Componente principal del vídeo>.tsx / scenes/SceneNN.tsx | Un nuevo vídeo solo añade archivos en esta capa (estructura ver assembly §4) |
Arranque real desde cero (src/ completamente vacío): Si el sustrato no está presente, el flujo de assembly no puede comenzar (no se puede obtener ningún token, generar el primer fotograma, ni aplicar las tres compuertas). El orden es: primero construir el sustrato, luego ensamblar: ① tokens.ts establecer la fuente de verdad de valores → ② fonts.ts + FontGuard.tsx (error #01) → ③ motion.ts tres hooks → ④ Librería de componentes §3 → ⑤ src/koubo/scenes/shared.tsx cuatro piezas de compuerta + Place/qcAllow → ⑥ src/design/qc.tsx Sonda QC → ⑦ src/Root.tsx registrar composition. Usa src/design de este repositorio como referencia de implementación; después de la migración, los valores todavía se leen de tokens.ts, no se rellenan en el skill.
0. Seis reglas de hierro
- El área de información por defecto está a la izquierda, la persona a la derecha: El área de información está por defecto a la izquierda (autor predeterminado por el usuario), el HUD se ancla en el lado izquierdo y crece verticalmente, el área de la persona está prohibida; pero para cada vídeo, primero pregunta al usuario sobre la composición, no te adelantes. Las coordenadas de las tres zonas y el mecanismo de excepción takeover se encuentran en references/layout.md regla 1.
- Todo el texto tiene estructura de dos capas: Inglés MAYÚSCULAS con espaciado ancho kicker (pequeño) + chino negrita gruesa (grande). Los componentes con solo una capa de texto se consideran incompletos.
- Solo se resalta una palabra por frase: En los títulos en chino, como máximo un cambio de color/palabra enfatizada. El color debe ser del sistema de cuatro colores semánticos.
- El material real es el sujeto, Remotion es un sintetizador, no una mesa de dibujo (actualización de decisión del 2026-07-16 seg01): Las escenas de "experiencia de producto" (escritura/generación/interfaz/demostración) deben ser siempre material real editado — grabación de pantalla propia > video oficial > captura de pantalla de página web > tarjeta de simulación de UI; el dibujo a mano solo para la capa HUD (etiquetas laterales/subtítulos/gráficos/sellos/metáforas visuales). Usar CSS para imitar el trabajo de un equipo profesional de motion graphics siempre fracasa. "Ajustar y aun así no queda bien/dista mucho" tiene su raíz en usar una mesa de dibujo para hacer el trabajo de un sintetizador. La tubería de captura y edición se encuentra en assembly references/broll.md.
- Sin texto desnudo en fondo claro (decisión de la comparación en profundidad del 2026-07-16, regla transversal entre 6 secciones): En fondos claros (pizarra blanca/pared blanca/fondo takeover claro) está prohibido el texto sin fondo. Todo el texto debe estar sobre un fondo oscuro (SURFACE.darkPlate), un cuerpo de tarjeta o una variante de superficie clara.
textShadowno es una solución. Los detalles se encuentran en references/texture.md. - Un centro dominante por pantalla: Cada pantalla de información tiene una y solo una "fuente/elemento más grande". Fuera del área principal, como máximo 2 elementos pequeños tipo chip. Los detalles se encuentran en references/typography.md y layout.md.
1. Design Tokens
Única fuente de verdad = src/design/tokens.ts. Todos los componentes solo deben importar valores de ahí. Esta sección solo escribe semántica y reglas de uso, no copia valores — antes hubo una desviación entre la instantánea y el código (2026-07-16 se encontraron varias discrepancias como kicker/h1 etc.), el código es la referencia.
- Cuatro semánticas de color (únicos colores de énfasis permitidos): blue = definición/método/avance neutral; green = positivo/bajo umbral/ya activo; yellow = oportunidad/advertencia/controversia/giro; red = negativo/trampa/crisis. Los colores base también incluyen white/grey/greyDim/cardBg/cardStroke.
- Fuentes (dos capas, no mezclar): Capa de empaquetado MG —
FONT.zh= Noto Sans SC (única fuente para chino en la capa de empaquetado, los títulos siempre usanFONT.zhHeavy);FONT.en= Inter (kicker/cuerpo/números);FONT.enTitle= Archivo Black (títulos en inglés y conclusiones de gran tamaño, supernegra estrecha, weight siempre 400 — Inter no da la talla para letras grandes, conclusión de comparación de formas de letras 2026-07). Capa de subtítulos inferior —FONT.subZh= PingFang SC 400 /FONT.subEn= Inter 300 (decisión del usuario tras comparación de cinco muestras el 2026-07-26): los subtítulos son una capa de seguimiento, no de empaquetado; solo la fuente ligera tiene la textura de los subtítulos de Apple, y se diferencia de la negrita gruesa del MG, sin robar atención. La versión anterior con Noto 700 en toda la línea parecía una pegatina. PingFang SC es una fuente del sistema macOS, no se empaqueta con@fontsource— la renderización local es correcta, en entornos Windows/Linux se degradará a la fuente empaquetada Noto Sans SC 400 (ya importada en fonts.ts, apariencia similar pero no idéntica). Antes de renderizar en otra máquina, renderiza un fotograma para verificar la apariencia de los subtítulos. Las líneas en inglés de los subtítulos deben usar una fuente proporcional occidental, ver error #42. - Las conclusiones de gran tamaño siempre usan color semántico puro +
textShadow. ProhibidobackgroundClip: textcon texto degradado (error #06);GRADIENTsolo para bloques de color/trazos. - Tamaños de fuente solo se permite la escalera
SIZE(kicker / subSmall / chip / subZh / subEn / card / h2 / h1 / mega). Prohibido usar tamaños fuera de la escalera. Base 1080p, para salida 4K multiplicar por 2. - Espaciado siempre múltiplos de
GRID(8px); esquinas redondeadas conRADIUS; zona de seguridad conSAFE(anclaje de etiqueta lateral, borde izquierdo de pila, distancia de subtítulos al borde inferior; las tarjetas permanentes no superan x55%, las coordenadas de la zona prohibida para la persona/zona derecha están en layout.md; zona prohibida de subtítulos y>82%, el borde inferior de los elementos de la zona izquierda ≤y840 es una línea dura más estricta que y82%).
2. Etiqueta lateral de sección SideLabel (permanente en todo el vídeo, componente de máxima prioridad)
- Estructura:
│(línea vertical de 4px, color semántico) +KICKER EN INGLÉS · frase en chino(primera línea, inglés con especificación kicker + color semántico, chino blanco 34px) + segunda línea gris 24px explicación adicional. - Posición: fija
SAFE.sideLabel. Al cambiar, la etiqueta antigua se desvanece en 12 fotogramas, la nueva se desliza desde la izquierda en 15 fotogramas. - Sistema de numeración con nombre:
SCENE 01,PATH 1/2/3, contraposición (DISSOLVED·01..vsIMMUNE·01..). - Color = semántica emocional del segmento, ver comentarios de tokens. Referencia:
refs/01-Diseño y etiquetas laterales/.
3. Referencia rápida de especificaciones de componentes (las especificaciones detalladas se completan con la implementación, primero mira las imágenes de referencia antes de escribir)
| Componente | Especificaciones clave | Referencia |
|---|---|---|
| BilingualSub | Chino 52 blanco + sombra negra / Inglés 28 blanco puro, centrado en la parte inferior, siempre en la capa superior | Cualquier refs |
| HeroText | kicker + h1/h2 chino, palabra resaltada en color semántico; variantes: tachado rojo para corrección, subrayado amarillo tipo pincel, sello inclinado | refs/02 |
| Chip | Tarjeta negra RADIUS.chip + icono en color + texto 34px, puede tener una palabra de color cambiado | refs/03 |
| Checklist | Chip apilados verticalmente, aparecen uno a uno; chips inactivos opacidad 0.35 | refs/03 |
| InfoCard | Icono + kicker + título 44px + palabra resaltada en azul | refs/01 |
| StepList | Números ①②③ en círculo + chino + inglés pequeño kicker, se iluminan gradualmente | refs/04 |
| FlowChain | Tarjeta negra + → flechas en serie, aparecen nodo por nodo | refs/04 |
| CompareCard | logo + nombre + chip rojo ✗ debilidad + chip verde ✓ fortaleza, apilados verticalmente | refs/04 |
| Formula | Letra grande A símbolo B (>, », ⇄, =), símbolo en color semántico | refs/05 |
| BigNumber | Número grande Inter + unidad pequeña + kicker; contador con desplazamiento spring | refs/05 |
| BarChart | Barras de datos con esquinas de 8px; barra destacada en amarillo + chip de corona en la parte superior; el resto en gris | refs/05 |
| CurveOverlay | Curva amarilla de 2–3px superpuesta directamente sobre B-roll, etiqueta en el extremo derecho | refs/05 |
| Timeline | Tipo de intervalo entre dos puntos / tipo de evento con chip de resultado rojo/verde | refs/05 |
| ScoreBoard | Marcador de gran número verde:rojo | refs/05 |
| PhoneMockup | Marco de iPhone + trazo degradado brillante + captura de pantalla larga incrustada con desplazamiento | refs/06 |
| WindowCard | Semáforos de Mac + icono de app + chip de funcionalidad, contenido dinámico | refs/04 |
| QuoteDoc | Tarjeta de captura de pantalla con fondo blanco + resaltado amarillo fluorescente + capa flotante de traducción al chino con fondo negro | refs/07 |
| TweetCard | Avatar + kicker de identidad + conclusión de gran tamaño en rojo + chip de vistas | refs/07 |
| PersonCard | Avatar redondo + nombre + texto pequeño de identidad + chip de institución | refs/07 |
| Stamp | Sello inclinado -8°~-6° con trazo (rojo/verde), animación de sello = scale 1.3→1 + ligera vibración | refs/08 |
| MatrixIcon | Iconos de matriz cuadrada: rojo = facción que será disuelta / verde = facción inmune | refs/08 |
| CardWall | Tarjetas blancas pequeñas de 3 a 20, se extienden una a una, simulando una explosión de demanda | refs/06 |
| BeforeAfter | Dos tarjetas con icono + flecha azul + chip de conclusión debajo | refs/04 |
| Breathe | Envoltorio de microanimación idle: respiración scale ±0.6% + flotación ±3px, phase para desfasar fases y evitar sincronía; envuelve el elemento principal | src/design/Breathe.tsx |
| BrickWall | Pared de ladrillos dorados con juntas desplazadas, se construyen bloque a bloque + etiqueta central, metáfora de "construir muro/barrera dura" | src/design/BrickWall.tsx |
| UnitMatrix | N grupos de matrices cuadradas se iluminan una a una; modo waffle fillRatio (campo de datos 73%) | src/design/UnitMatrix.tsx |
| CloneCascade | Tarjeta de icono original + imitaciones aparecen una a una + chip de advertencia, metáfora de "ser copiado/destilado" | src/design/CloneCascade.tsx |
Componentes en línea de escena de producción por lotes (añadidos en la producción por lotes del 2026-07-17, aún no promovidos a componente compartido)
Los siguientes componentes actualmente solo viven en una sola Scene. Marcados como "En línea de Scene, cuando se reutilice por segunda vez, promover a componente compartido en src/design y añadir línea de especificación en specs" — cuando un nuevo vídeo se encuentre con una necesidad similar, primero consulta aquí, no reinventes:
| Componente en línea | Ubicación | Qué hace | Condición de promoción |
|---|---|---|---|
| DissolveGrid | scenes/Scene08.tsx | Cuadrícula de disolución: los bloques de la facción que será disuelta se disgregan uno a uno, el fondo ⚡ se desvanece dejando el contorno blanco suspendido | Cuando se reutilice la metáfora de "disolución de facción" por segunda vez |
| VerdictBox (caja de veredicto) | scenes/Scene17.tsx | Caja de veredicto espejo rojo/verde: ≈400×170 marco vacío con trazo se levanta primero + encabezado dentro + 3 chips en fila horizontal entran por lotes (rojo se llena primero, verde después, creando suspensión de "¿de qué lado estás?") | Cuando se eleve el "veredicto VS" por segunda vez |
| NamePlate + CtaBadge (insignia CTA) | scenes/Scene19.tsx | Una fila horizontal en la parte inferior del CTA final: la placa de nombre se coloca primero como ancla → cuatro insignias de acción entran una a una (la insignia de comentario es la más ancha = énfasis) | Cuando se cierre el CTA final por segunda vez |
Especificaciones de iconos
- Los iconos siempre usan iconos SVG lineales de lucide-react, color con color semántico (
COLOR[accent]),strokeWidth 2.5aproximadamente; prohibido usar emojis (los bloques de color redondeados chocan con el estilo lineal monocromático del vídeo de referencia, lección de la tercera ronda de revisión de 2026-07). - Los props
iconde Chip / Checklist / SideLabel aceptan ReactNode:icon={<Lock size={26} strokeWidth={2.5} />}.
Especificaciones de textura → references/texture.md
Degradados de bloques tipo gelatina, glow del mismo color, viñeta, logotipo real, variantes claras/oscuras de SURFACE, línea única de especificación de sello, todo en texture.md (desde 2026-07-16 es la única fuente de verdad para textura, el texto antiguo de esta sección se ha movido).
4. Reglas de animación → references/motion.md
useEnter/useExit, entrada con subdivisión de tiempo, intervalo de servicio, Breathe, pantalla limpia entre capítulos, elementos prohibidos, todo en motion.md (desde 2026-07-16 es la única fuente de verdad para animación, el texto antiguo de esta sección se ha movido; nota: la regla antigua "la información anterior permanece con opacidad reducida" ha sido reemplazada por "intervalo de servicio + disciplina de salida").
5. Autocomprobación antes de exportar (ejecutar antes de cada renderizado)
- grep para comprobar si hay componentes con valores de color/tamaño/fuente fuera de tokens.
- Comprobar si todas las tarjetas permanentes invaden faceZone / subtitleZone.
- Comprobar si cada palabra resaltada en los títulos es ≤ 1 lugar; si los kicker en inglés están en mayúsculas con espaciado.
- Tomar 3–5 fotogramas clave y compararlos lado a lado con las imágenes de referencia en refs/. Si no se parecen, indica qué token está fallando; corrige el token, no modifiques el componente.
6. Colección de errores
#01 El chino se degrada silenciosamente a Songti (2026-07-15 · Primer día del sistema de diseño)
- Síntoma: En renderizados/capturas, el chino se convierte en Songti, el inglés funciona; a veces el mismo componente funciona y a veces no (depende de la suerte).
- Causa: Tres capas, la última es la verdadera culpable. ①
@remotion/google-fontsobtiene la fuente de gstatic en tiempo de ejecución, la red doméstica no puede alcanzarla, falla silenciosamente a la fuente de respaldo; ② las fuentes web chinas se empaquetan por unicode-range, la carga y la captura tienen condiciones de carrera; ③ Tree-shaking:sideEffects: ["*.css"]enpackage.jsonhace quefonts.ts, que solo se importa por efectos secundarios, sea eliminado por completo en el paquete de producción, la CSS de la fuente no está en el bundle de renderizado (document.fonts.size === 0) — el modo de desarrollo de Studio no hace tree-shaking, por lo que "Studio funciona, renderizado falla". - Solución: ① Usar paquete local
@fontsourcepara las fuentes (src/design/fonts.ts); ②sideEffectsenpackage.jsondebe incluir"src/design/fonts.ts"; ③ En cualquier composición que contenga texto, montar<FontGuard/>: verificación en bucle load→check, y también debe comprobardocument.fonts.size > 0(fonts.check()devuelve true vacío cuando no hay fuentes registradas), si hay tiempo de espera, llamar acancelRendery reportar el error, nunca renderizar silenciosamente un fotograma con Songti. - Lección: "Studio funciona, exportación falla": sospechar primero de diferencias en el paquete de producción (tree-shaking/compresión), no de condiciones de carrera místicas. La verificación de fuentes debe hacerse con el umbral duro de FontGuard, el ojo humano no es fiable con las miniaturas.
#02 remotion still genera «○» = reutiliza imagen antigua
- Síntoma: Después de cambiar el código y volver a renderizar, el archivo de salida parece sin cambios; la línea de comandos muestra
○en lugar de+. - Solución: Antes de verificar el renderizado, elimina la salida antigua (o renderiza con un nombre de archivo nuevo); si es necesario, añade
--bundle-cache=false.+= renderizado real,○= sospechoso. - Lección: La verificación comparativa debe basarse en productos de renderizado confirmadamente frescos, de lo contrario se puede diagnosticar erróneamente que "la reparación no funciona" (esta vez se perdieron dos rondas por esto).
#03 Las miniaturas de comparación engañan
- Síntoma: En la comparación lado a lado de imágenes pequeñas, el chino parece Songti, pero la imagen original es normal.
- Solución: Para juzgar detalles de fuente/trazo, recortar la resolución original y ampliar localmente, no usar la miniatura de todo el fotograma para concluir.
#04 Las cadenas de atributos JSX no interpretan escapes \uXXXX
- Síntoma:
<Chip icon="\u2705" />muestra el literal\u2705en la pantalla en lugar de ✅. - Causa: Los literales de cadena en los atributos JSX son texto tipo HTML, no pasan por la interpretación de escapes de JS; solo las cadenas en expresiones JS (
icon={'\u2705'}) interpretan los escapes. Es fácil caer en esto al escribir TSX por lotes con scripts. - Solución: En los atributos JSX, escribir directamente el carácter real para emojis/caracteres especiales (
icon="✅"); si se necesita escape, escribirlo comoicon={'\u2705'}.
#06 El texto degradado con backgroundClip: text se renderiza oscuro
- Síntoma: Los títulos grandes con backgroundImage degradado + WebkitBackgroundClip:'text' + WebkitTextFillColor:'transparent' se ven aceptables en Studio, pero en el renderizado el color de la imagen sale oscuro y apagado (rojo brillante se vuelve rojo ladrillo), el usuario lo rechaza de plano.
- Solución: Las conclusiones de gran tamaño siempre usan color semántico puro
COLOR[semantic]+ textShadow; para sensación de capas, usar sombra y peso de fuente, no relleno degradado. tokens.GRADIENT solo para bloques de color/trazos.
#08 En el producto final, los bordes del texto MG tienen halos y aspecto de mancha («añadir MG empeora la calidad de imagen») (2026-07-16 · 0715-01 v3)
- Síntoma: El usuario dice que la calidad de imagen es mala; al ampliar, los bordes del texto MG tienen ruido JPEG/halos, cuanto más nítido es el elemento, más evidente. El material en sí es limpio a 15 Mbps HEVC.
- Causa: La tubería predeterminada de Remotion tiene doble compresión: cada fotograma se captura como JPEG con calidad 80, luego se comprime con CRF 18 a H264. El texto MG grande/las líneas finas son señales de alta frecuencia, las primeras en mostrar artefactos de compresión. Antes de añadir MG, los artefactos estaban ocultos en la textura de la imagen real y no eran obvios, por lo que se diagnosticó erróneamente como "MG empeora la calidad".
- Solución: En
remotion.config.ts, fijarConfig.setJpegQuality(100)+Config.setCrf(15)(ya establecido en este proyecto, no revertir). El tamaño aumenta aproximadamente un 20%, el renderizado es un poco más lento, pero vale la pena. - Método de diagnóstico: Tomar una captura del mismo fotograma del material/antiguo producto final/prueba con nuevos parámetros, recortar la misma área de texto MG y ampliarla lado a lado; primero renderizar un segmento de prueba de 5 segundos para verificar los parámetros antes de renderizar todo el vídeo.
#09 Renderizado largo desaparece a mitad de camino, mp4 queda como archivo corrupto (2026-07-16 · 0715-01 v3)
- Síntoma: Después de que el renderizado ha estado ejecutándose mucho tiempo, «el proceso sigue ahí» pero el archivo de salida no crece durante mucho tiempo; o el renderizado desaparece silenciosamente, dejando un mp4 que no se puede abrir.
- Causa: ① El renderizado está colgado en un subproceso de la sesión de AI, si la sesión se reinicia/se cierra, mata el renderizado (esta vez fue matado al 90%); ② Al detectar el proceso con
pgrep -f "remotion render", coincide con el propio script de detección (la línea de comandos contiene la misma cadena), dando la ilusión de que «el proceso sigue vivo». - Solución: ① Los renderizados de más de unos minutos siempre deben ejecutarse con
nohup npx remotion render … > /tmp/xx.log 2>&1 & disownpara separarse de la sesión; ② El criterio de finalización debe ser la línea+ nombre de archivo de salidaen el registro (+= renderizado realmente exitoso), no la existencia del proceso; ③ Al detectar procesos, excluir la autocoincidencia (mirar el uso de CPU o usar PID exacto); ④ Antes de volver a renderizar, eliminar el archivo corrupto. - Lección: Un mp4 corrupto (duración/tamaño no coinciden) nunca debe entregarse; primero verificar la duración y las pistas de audio con
ffprobeantes de mostrarlo al usuario.