Canal de video promocional de Velxio
Tres fases, todo en este repositorio (velxio_docs; /home/dave/velxio_docs en la caja de desarrollo):
- Grabar —
scripts/promo-record.mjsmaneja el producto real en staging de extremo a extremo (proyecto en blanco -> seleccionar ESP32 -> añadir 220R + LED -> rotar resistencia -> cablear por clics en pines -> escribir sketch -> Ejecutar -> LED parpadea), con un cursor visible inyectado + ondas de clic. Cada evento registra{t, x, y, label}enscripts/promo-events.json; el video en bruto se guarda enscripts/promo-raw.webm. - Cuadrícula de beats —
scripts/detect-beats.py(librosa) convierte la banda sonora enpromo/src/beats.json(BPM, beats, kicks, snares). - Post —
promo/es un proyecto de Remotion.prepare.mjscopia la toma, recorta el arranque pre-modal, elimina la espera de compilación y generasrc/data.json.src/Promo.tsxrenderiza la cámara (zooms centrados en cada beat, cada golpe SNAP al beat musical más cercano dentro de 0.34 s), píldoras de subtítulos, una tarjeta de introducción SÓLIDA, el cierre de velxio.dev y la pista de música con fundidos.
Comandos
cd /home/dave/velxio_docs
VELXIO_SHOTS_EMAIL='[email protected]' VELXIO_SHOTS_PASSWORD='<see memory vstaging-test-user>' \
node scripts/promo-record.mjs # toma (~2-4 min incl. compilación)
python3 scripts/detect-beats.py promo/public/soundtrack.mp3 --fps 30 \
--out promo/src/beats.json # solo cuando cambia la pista
cd promo && node prepare.mjs
CHROME=$(ls -d $HOME/.cache/ms-playwright/chromium-*/chrome-linux*/chrome | sort | tail -1)
npx remotion render src/index.ts promo out/velxio-demo.mp4 --codec h264 --browser-executable "$CHROME"
Copia publicada para visualización en GitHub: media/velxio-demo.mp4 (commiteada; sobrescribir + hacer push para actualizar la misma URL). promo/out/ está en gitignore.
Procedimiento de revisión (NO omitir)
Tomar muestras de fotogramas EN LOS TIEMPOS DE BEAT desde promo/src/data.json (campo ct), no en tiempos adivinados — los beats se mueven entre tomas:
ffmpeg -y -ss <ct> -i out/velxio-demo.mp4 -vframes 1 /tmp/beat.png
Verificar: introducción legible, cada zoom muestra su sujeto sin recortar, los subtítulos coinciden con lo que está en pantalla, el cursor no cubre lo importante, el LED final encendido.
Videos demo de galería (modo básico)
Un video corto por ejemplo de galería — abrirlo, ejecutarlo, filmarlo funcionando — con una tarjeta de introducción dividida (logotipo + título + placa a la izquierda, el circuito completo a la derecha), un tercio inferior, el cierre y la banda sonora.
node scripts/gallery-scan.mjs # refrescar el índice de 406 ejemplos
node scripts/gallery-record.mjs [slug ...] # tomas 1080p (salta las ya hechas)
node scripts/gallery-bbox.mjs [slug ...] # medir dónde se asienta el circuito
node scripts/gallery-render.mjs [slug ...] # un mp4 por toma
- El conjunto de demos seleccionado está en
GALLERYal inicio degallery-record.mjs; los slugs provienen descripts/gallery-index.json(nombre de miniatura = slug). - Las imágenes fijas se capturan con
deviceScaleFactor: 2y se recortan al bbox del circuito: lo suficientemente nítidas para llenar la mitad de un fotograma 1080p. NO hacer zoom en la aplicación para ampliar un circuito pequeño — el ancla del zoom se centra en su centro y desplaza el circuito fuera de la pantalla; restablecer la vista en su lugar. - El pase de bbox necesita un CONTEXTO NUEVO por ejemplo: una segunda carga del editor desde el cliente deja el lienzo vacío y no mide nada.
- Los ejemplos sin placa (categorías Digital / Analógico) nunca compilan: Ejecutar permanece deshabilitado y el motor SPICE los maneja desde el inicio.
- Las placas Backend-QEMU (STM32, Raspberry Pi) no emiten ninguna línea de consola "en el navegador". STM32 además no se ejecuta en staging (libqemu-arm es un activo opcional que no está desplegado allí) — compila en 3 s, nunca inicia.
- Las tomas en bruto (
promo/public/gallery/*.webm, ~3 MB cada una) están en gitignore; las imágenes fijas del circuito y el JSON por toma están commiteados para que un re-renderizado solo necesite las tomas de vuelta.
Música
promo/public/soundtrack.mp3 = Mixkit "House Vibez" por Lily J (assets.mixkit.co/music/745/745.mp3), Mixkit Stock Music Free License — libre para uso comercial, sin atribución requerida. 123 BPM. Cambiar el archivo y re-ejecutar detect-beats.py para cambiar de pista; mantener la nota de licencia actualizada en promo/public/ATTRIBUTION.md.
La pista abre con ~8 s de introducción: AUDIO_START en Promo.tsx es el primer beat detectado, por lo que el audio comienza desde ahí y la composición t=0 cae en un tiempo fuerte. El volumen se mantiene en 0.55 con un fundido de entrada de 0.9 s y un fundido de salida de 2.2 s sobre el cierre.
Reglas de estilo (de la revisión de David — mantenerlas)
- El video comienza EN el editor con el modal de plantilla de placa ya abierto y el chat de IA ya minimizado. Sin página de inicio, sin carga, sin clic de minimización visible (el grabador lo hace programáticamente antes de iniciar; prepare.mjs recorta hasta la marca
start). - Título de introducción sobre una tarjeta oscura SÓLIDA — nunca translúcido sobre la interfaz.
- Los zooms deben CENTRAR su sujeto: translate+scale con sujeciones de borde (
Promo.tsx), nunca transformOrigin-at-point (deja el sujeto en un borde y lo corta, por ejemplo la tarjeta ESP32). - Los beats de añadir piezas usan una sujeción CORTA (~0.5 s) para que el zoom se libere a tiempo para VER dónde cayó la pieza.
- El beat de código centra todo el PANEL del editor (fx/fy override 357,280) — nunca un editor recortado mientras se escribe código.
- Después de hacer clic en Ejecutar, ESTACIONAR el cursor lejos (el grabador se mueve a 700,620) para que el spinner del botón sea visible; el beat de Ejecutar hace zoom en el grupo de compilación/ejecución a escala moderada (1.8).
- Rotar la resistencia horizontal después de colocarla (el valor predeterminado vertical superpone sus propios cables en cámara).
- El puntero es una FLECHA estilo macOS, no un punto. Matemáticas del hotspot (del skill saas-product-demo): la punta está en (4,3) en un viewBox de 24x24, por lo que al ancho de renderizado W el elemento se desplaza en (-4W/24, -3W/24) — sin esto cada clic se lee ~6-8 px fuera del objetivo.
- Los golpes de zoom caen en beats musicales (ver Música arriba); nunca dejar que un golpe se desvíe más de ~0.3 s de su clic solo para acertar un beat.
- Los beats cuyo MODAL SE CIERRA al hacer clic (choose-blank, add-*) necesitan
lead: 0.45: el pico debe caer ANTES del clic para que el fotograma muestre la tarjeta aún abierta, y la liberación luego revela dónde cayó la pieza. Pico en el clic mismo deja el zoom estacionado en un diálogo ya cerrado.
Trampas (cada una costó una toma rota — todas manejadas en los scripts)
/es la página de aterrizaje de marketing incluso cuando se ha iniciado sesión; el editor está en/editor. Iniciar sesión mediante fetch POST/api/auth/loginen la página primero.- En un
/editornuevo, la superposición "Iniciar un nuevo proyecto" se abre automáticamente (.new-project-overlay) e intercepta cada clic de puntero externo. Interactuar con ella primero, o enviar clics programáticos. - El campo de búsqueda del selector CONSERVA la consulta anterior — limpiar con Ctrl+A + Retroceso antes de escribir o se buscará "esp32led".
- Tarjetas del selector: coincidir el título exacto con
.component-picker-modal .card-name(los motores de texto genéricos golpean tokens de Monaco detrás del modal). Los resultados están debounced — esperar hasta 5 s. Los nombres de las tarjetas son exactos ("Resistor 220 Ω" con carácter estilo U+2126, no "Resistor"; verificar/components-metadata.json). - Las placas NO se arrastran desde su cuerpo — dejar la placa donde la deja el selector (cerca del borde derecho del lienzo) y colocar piezas pequeñas RELATIVAS a su boundingBox en vivo, a su IZQUIERDA donde hay espacio.
- Clics en pines: usar los propios
[data-pin-overlay="true"][title=<pin>]divs de la aplicación, eligiendo el candidato más cercano al elemento anfitrión (los títulos chocan: pin "2" de placa vs resistor "2"). Calcular desde los offsets depinInfose rompe en piezas rotadas. Los pines ESP32 se llaman '2','4','GND' (no D2). - Verificar que cada cable cayó contando
path[stroke="#1a1a1a"](el trazo del contorno de cada cable; los cables no tienen clase/atributos data). Reintentar una vez mediante Escape + re-clic. - El verificador de circuitos BLOQUEA Ejecutar para un LED sin resistencia en serie (error de 3.9e12 A). La demo debe cablear GPIO2 -> 220R -> LED A, GND -> LED C. Nunca enviar una toma que necesitó "Ejecutar de todos modos".
- La plantilla en blanco incluye un sketch predeterminado — Ctrl+A antes de escribir el comentario en cámara, luego establecer el sketch completo mediante
monaco.editor.getModels()[0].setValue(...)(la escritura literal lucha con los corchetes de cierre automático de Monaco). - El toast "¿Disfrutando Velxio? / Star en GitHub" fotobomba tomas de más de ~5 min — el limpiador inyectado lo elimina cada segundo.
- Playwright no graba el cursor del SO: el
#vx-cursordiv inyectado + la onda de mousedown (context.addInitScript) es el puntero visible. - La espera de compilación es real (30 s en caliente - 5 min en frío): el grabador registra
runysim-started; prepare.mjs elimina ese intervalo. El inicio de la simulación se detecta mediante una línea de consola "en el navegador"; "guest crashed" = abortar. - Remotion renderiza con el chromium de Playwright mediante
--browser-executable(sin descarga de navegador empaquetado en esta máquina).
Repositorios de referencia (examinados 2026-08-15)
Dos skills de Claude-Code para el mismo género, enfoque diferente: ellos COMPONEN películas a partir de capturas de pantalla/interfaces esquemáticas con un cursor sintético — el nuestro GRABA el producto real. Clonarlos al mejorar:
github.com/noamdorr/saas-product-demo-video— películas de marketing sincronizadas con beats de 20-45 s en Remotion. Robar: SINCRONIZACIÓN CON BEATS de banda sonora (librosadetect-beats.py: cortes de escena en snares, eventos intraescena en kicks — nuestro video es silencioso, añadir música + alinear beats de zoom es la mejora más grande disponible), matemáticas del hotspot del cursor (la punta de la flecha SVG está en 4,3 de un 24-box — importa si cambiamos nuestro cursor de punto por una flecha), verificación de presupuesto de escritura, libro de jugadas de iteración.github.com/Vincentwei1021/video-shotcraft— 152 tarjetas de recetas de planos con fuentes de demo + galería (vincentwei1021.github.io/video-shotcraft), una plantilla aprobada (Ink Press), movimientos de cámara 2.5D, diseño de sonido y tres modos de operación (plantilla / autónomo / co-creado). Robar: el vocabulario de planos de dirección y su lista de verificación de revisión final; también se instala como plugin si alguna vez se desea una película cinematográfica completa.
Relacionados
- Canal de capturas de pantalla:
scripts/shots.mjs(mismo repositorio) — escenas con el panel de IA minimizado a menos que sea el sujeto. - GIFs: grabar un segmento (Playwright recordVideo) y convertir con ffmpeg de dos pasos con paleta; ver
scripts/weather-media.mjspara el patrón de zoom+recorte (región de recorte desde el boundingBox del elemento). - Usuario de prueba de staging: memory
vstaging-test-user(s3-tester, pro). - Proyecto de showcase roto (estación meteorológica) se rastrea en
project/docs-portal-2026-08/STATUS.mden velxio-prod.