Communitygithub.com

perspective-illusion

Crea un vídeo 3D ilustrado en bucle al estilo de la ilusión de perspectiva japonesa (ej. @garments__) de cualquier lugar, como una calle, cruce, estación, pasillo de tienda, habitación, parque o azotea.

¿Qué es perspective-illusion?

Esta habilidad permite generar vídeos en bucle con ilusiones ópticas de perspectiva, inspirados en el estilo de artistas japoneses como @garments__. El resultado es una escena de línea limpia que, comprimida por un teleobjetivo, parece un dibujo plano; luego, mediante un 'dolly zoom', la lente se abre mientras la cámara avanza, revelando una profundidad tridimensional. La cámara también gira hacia vistas en esquina que inicialmente se leen como planas y luego se convierten en 3D, mientras objetos intercambian su posición en profundidad durante los momentos planos. Soporta escenas diurnas y nocturnas (calles, mercados, cruces), utiliza plantillas HTML con Three.js y se renderiza con scripts Node.js para obtener bucles perfectos. Es ideal para creadores que buscan efectos visuales llamativos tipo 'dolly zoom' o 'plano a 3D'.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/wsxiaolin/perspective-illusion/tree/main

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Ilusión de perspectiva

El estilo, en un párrafo

Una cámara nivelada con un teleobjetivo muy largo (aproximadamente 2° desde 400 m de distancia) aplana una escena profunda hasta que parece un dibujo plano. Luego realiza un dolly zoom: la lente se abre mientras la cámara avanza, de modo que el sujeto mantiene el mismo tamaño pero el espacio detrás se estira y se abre. La cámara también gira hacia vistas en esquina. Cada una comienza plana y se abre en 3D. Mientras la vista es plana, los objetos se deslizan en profundidad donde nadie puede verlo, de modo que cuando la profundidad regresa, una fila se ha convertido en una diagonal. Todo está dibujado como línea de tinta limpia con sombreado plano de dos tonos, sombras proyectadas rayadas y un cielo pintado, y todo el conjunto se repite sin problemas.

Inicio rápido

mkdir -p ~/Movies/edits/<fecha>-<nombre>/stills && cd $_
printf '{"type":"module"}' > package.json && npm i [email protected] [email protected]
cp -r ~/simcraft/skills/video/perspective-illusion/templates/* .
cp scramble_night.html scene.html                                # o la plantilla más cercana (ver abajo), luego editar
node render.mjs scene.html x --stills=0.3,1.5,3,6,8.5           # fotogramas de cada toma, en stills/
node render_fast.mjs scene.html preview.mp4 --preview            # bucle completo, mitad de tamaño, aproximadamente 1.5 min
node render_fast.mjs scene.html final.mp4                        # calidad completa, aproximadamente 30 min para 10 s
python3 ~/simcraft/skills/video/vox-explainer/scripts/motion_check.py final.mp4
python3 ~/simcraft/skills/video/perspective-illusion/scripts/blink_map.py ffmpeg final.mp4 blink.png

Corrige problemas en los fotogramas y las previsualizaciones. Renderiza en calidad completa solo una vez que la previsualización esté aprobada. Configura $FFMPEG si ffmpeg no está en el PATH.

Plantillas

Comienza desde la plantilla más cercana a la nueva escena. Mantén su rig de cámara, línea de tiempo, pase de postprocesado y hooks de renderizado, y reemplaza solo la sección de la escena (todo entre // ---------- kit y // ---------- cameras).

PlantillaEscenaRenderizador
street.html, street_plus.htmlCalle diurna con postes, conos, un cruce y un cielo rojo. street_plus añade detalle y vistas en esquina.render_smooth.mjs
market.html, market_real.htmlPasillo de supermercado, dibujado y realista.render_smooth.mjs (market.html: render.mjs)
scramble_night.htmlUn gran cruce nocturno bajo la lluvia, con multitud caminando, reflejos mojados y pantallas publicitarias. Tiene todas las optimizaciones de velocidad.render_fast.mjs

Para una escena nueva, scramble_night.html es la mejor base para el motor, porque es la única con los hooks del renderizador rápido. Elimina sus extras nocturnos (consulta reference.md) para un aspecto diurno.

Paso 1: Construir una escena que pueda engañar al ojo

Cualquier lugar funciona si tiene estos elementos:

  • Un eje largo. Coloca la escena a lo largo de -z (una calle, un pasillo, un andén, un corredor), con la cámara mirando a lo largo de él. La profundidad a lo largo de este eje es lo que oculta el teleobjetivo.
  • Cosas repetidas a diferentes profundidades. Postes, lámparas, estantes, columnas, carteles, árboles, personas. Con un teleobjetivo se apilan en un solo plano. Los postes alineados se fusionan en uno, y las pilas de carteles en fachadas lejanas se acumulan en una pared.
  • Objetos intercambiables. De 3 a 6 objetos similares (conos, personas, contenedores, sillas, cajas) cuya disposición cambia entre una fila y una diagonal. También pueden dibujarse más grandes en la vista plana (cs), para que la escala se lea correctamente al aplanarse.
  • Escala del mundo real en metros. Los lentes y los planos de enfoque solo tienen sentido a escala real: un cono de 0.75 m, personas de 1.7 m, una planta de 3.2 m.
  • Detalle donde miran las vistas en esquina. Cada vista en esquina revela los lados de los edificios, las partes traseras de los objetos y el suelo. Llánalos: ventanas laterales, desagües, cables, bordillos, la sombra de contacto debajo de un coche. Las vistas planas ocultan el descuido y las vistas en esquina lo exponen.
  • Haz que cada detalle sea parte de una superficie (texturas, mangas apiladas), o mantén las superficies separadas al menos 0.4 m de distancia. Desde 400 m de distancia, las superficies separadas por unos centímetros parpadean.

Paso 2: Coreografiar la cámara

La cámara nunca está inclinada. Permanece nivelada para que las verticales se mantengan verticales, como en un dibujo de arquitecto. Cada toma es un objeto simple:

{ x, y, zf, W, fov, H, el, yaw, lay, cs }

ClaveSignificado
x, yPosición lateral y altura de la cámara (m)
zf, WEl plano de enfoque y el ancho enmarcado allí (m). Mantener W mientras se cambia fov es el dolly zoom.
fovÁngulo horizontal del lente. Aproximadamente 2° es plano, de 25 a 90° es profundo.
HDesplazamiento del lente: dónde se sitúa el horizonte (-1 abajo, 0 medio, 1 arriba).
elMirar hacia abajo elevando la cámara y desplazando el lente, nunca inclinando.
yawGirar alrededor del punto de enfoque para vistas en esquina.
lay, csDisposición de objetos intercambiables (0 fila, 1 diagonal) y su escala en vista plana.

Vocabulario de tomas que funciona:

TomaConfiguración
Planafov aproximadamente 2, H 0. Toda la escena se lee como un alzado.
Ojo de gusanoAltura de rodilla, fov 90, horizonte bajo (H aproximadamente -0.7).
AltaCámara arriba con un lente medio, horizonte por encima del encuadre.
Vista en esquinayaw ±18 a 35°, el 9 a 50°. Viene en par: primero una versión con teleobjetivo (fov 4), luego la misma vista con angular (fov 25 a 45).
Diagonal y bajaLentes medios que muestran los objetos intercambiables en profundidad.

Estructura del bucle. Plana, luego una vista profunda, luego una vista en esquina (plana y luego 3D), de vuelta a plana (intercambiar los objetos aquí), una diagonal alta, la otra vista en esquina, una toma baja, y luego plana de nuevo. El bucle termina en la misma toma en que comienza.

Temporización. Todos los parámetros se ejecutan a través de una curva cúbica monótona (Fritsch-Carlson) sobre los tiempos clave, por lo que la velocidad nunca salta. Interpola W y fov en espacio logarítmico. Añade pequeñas tomas de "deriva" (W × 0.96) para que las pausas respiren en lugar de congelarse. 10 s se siente suave, mientras que 7 s se siente apresurado. Para cambiar la duración, escala los tiempos clave en lugar de reescribirlos.

Truco mientras está plano. Cambia lay solo durante las pausas planas. Si la cámara se mueve en profundidad mientras los objetos se mueven, el truco se nota.

La primera vista en esquina debe ir hacia el lado que el objeto héroe (un coche, un cartel) no cubre. De esa manera, la revelación muestra algo nuevo.

Paso 3: El aspecto

La página renderiza cuatro pases: color, normales con profundidad, color plano (sin iluminación) y una máscara de sombra solo solar. Un sombreador final los combina.

  • Líneas de tinta donde cambian la profundidad (segunda diferencia), las normales o el color plano. Haz las líneas más pesadas de cerca. Las marcas en el suelo reciben líneas grises finas. Atenúa las líneas de color donde un píxel cubre muchos metros, o las texturas lejanas se convierten en ruido.
  • Sombreado de dos tonos. Luz versus sombra, sin degradados. Configura la luz de la máscara a 2*PI, porque three.js divide Lambert por pi, y sin eso todo se convierte en sombra.
  • Rayado solo en sombras proyectadas, con el rayado anclado en el espacio del mundo (nunca en el espacio de pantalla) y atenuado por fwidth.
  • Pinta el cielo por dirección de visión, no por posición de pantalla, para que las nubes se mantengan fijas mientras la cámara se mueve. Mantén los bordes de las nubes suaves.
  • Paleta. De 6 a 10 colores planos más un acento (un cielo rojo, un cartel amarillo). Para coincidir con una referencia, toma los colores de sus fotogramas con k-means.
  • Luz. Un sol bajo y duro colocado de modo que los sujetos principales permanezcan iluminados y proyecten sombras largas en el suelo. Un sol desde el lado alto entierra la escena en una gran sombra.

Para una variante nocturna (luz de luna, ventanas iluminadas, reflejos mojados, brillo, lluvia, gradación), una multitud de caminantes, o pantallas publicitarias y carteles, consulta reference.md.

Para obtener un aspecto diurno de scramble_night.html:

  • Cambia la luna por un sol cálido y eleva la luz ambiental.
  • Elimina el bucle de luz puntual.
  • Retira el bloque de suelo mojado, la línea de bruma y la gradación nocturna del sombreador de postprocesado.
  • Elimina la lluvia y establece emissiveIntensity en las ventanas a 0.
  • Pinta un skyAt diurno.

Paso 4: Pasos de detalle (lo que lo hace genial)

Las primeras versiones siempre se ven vacías. Las versiones geniales provienen de pasos deliberados, cada uno verificado en fotogramas antes de que comience el siguiente.

  1. Formas. Masas principales a escala real, el eje largo, los objetos intercambiables y la línea de tiempo de la cámara. Verifica que la toma plana realmente se lea plana y que cada movimiento revele algo.
  2. Estructura. Todo lo que tiene un lugar real, construido con lógica del mundo real. Para una calle, eso significa bordillos, desagües, tapas de alcantarilla, postes con sus brazos y cajas, carteles en ambas caras, vallas, contenedores, máquinas expendedoras, soportes para bicicletas, cables aéreos, y marcos de ventanas con alféizares y unidades de aire acondicionado. Mira fotos del tipo de lugar real y enumera lo que hay antes de construir.
  3. Desgaste e historia. Pequeñas cosas que lo hacen habitado: pegatinas, cinta adhesiva, carteles con texto dibujado con código, manchas de charcos, una bicicleta apoyada, ropa tendida, un gato, una taza de café. Apunta a 3 o más por superficie en la que la cámara se detiene.
  4. Auditoría de vistas en esquina. Para cada vista en esquina, renderiza el fotograma amplio y llena lo que se ve desnudo allí. Generalmente son los lados de los edificios, las partes traseras de los carteles, los techos (tanques, barandillas, antenas) y el suelo entre objetos.
  5. Luz y sombra. Asegúrate de que cada objeto proyecte una sombra legible, añade sombras de contacto debajo de las cosas estacionadas y lleva el lado sombreado de cada forma principal al paso de dos tonos. Las sombras que solo aparecen en una vista son una recompensa para el movimiento de la cámara.
  6. Vida (opcional). Caminantes, un tren o coches moviéndose a velocidad constante, pantallas, pájaros, banderas. Todo se repite un número entero de veces.
  7. Pulido. Armonía de la paleta, grosor de línea, cielo, viñeta y gradación. Luego la verificación de parpadeo en el resultado final.

Regla de densidad: desde el fotograma plano con teleobjetivo, el encuadre debe sentirse lleno de borde a borde, como una ilustración densa, sin grandes áreas vacías de pared o suelo a menos que sea un descanso deliberado para el ojo.

El estándar de calidad

Antes de cualquier renderizado completo, verifica los fotogramas en cada tiempo clave (y a medio camino entre movimientos) contra esta lista. Corrige cualquier cosa que falle, luego verifica de nuevo.

  • La toma plana se lee como un dibujo plano. Nada revela la profundidad.
  • Cada movimiento termina en una revelación: una diagonal oculta, una calle lateral, objetos que estaban lejos.
  • Las vistas en esquina comienzan planas y se abren, y la primera se aleja del objeto héroe.
  • Las líneas son nítidas y uniformes, sin líneas dobles, sin tinta en caras brillantes y sin ruido en texturas lejanas.
  • El sombreado de dos tonos es claro en cada forma principal, y el rayado aparece solo en sombras proyectadas.
  • Nada se lee como un primitivo desnudo. Cada caja tiene moldura, costuras, una base o una etiqueta.
  • El texto es legible y está escrito correctamente, en fuentes reales, con marcas inventadas.
  • El cielo coincide con la dirección de la luz y el color de la escena.
  • La paleta es limitada y armoniosa, con un acento claro.
  • La costura del bucle es invisible (el fotograma 0 es igual al último fotograma) y nada aparece de repente.
  • La previsualización no tiene tartamudeos. En el resultado final, el recuento de blink_map es bajo, y lo que parpadea es movimiento intencionado (lluvia, pantallas).

Al revisar fotogramas, míralos como un ilustrador: nombra las tres áreas más débiles de cada fotograma, corrígelas y repite. No te detengas en "funciona".

Paso 5: Renderizar y verificar

  • render_fast.mjs renderiza cada fotograma en la GPU como un promedio de sub-renderizados con jitter: 4 para antialiasing, y hasta 32 en movimientos rápidos para un desenfoque de movimiento continuo, dimensionados por cuánto se mueven los puntos de window.probe en pantalla. Usa --preview para la mitad de tamaño a 30 fps. --from, --to y --fps también están disponibles.
  • render_smooth.mjs ofrece la misma calidad para páginas sin renderMany, pero promedia en ffmpeg, por lo que es varias veces más lento.
  • Fusiona mallas estáticas por material al cargar (BufferGeometryUtils.mergeGeometries). Una escena pasó de 7,654 llamadas de dibujo a 530, aproximadamente 7 veces más rápida. Mantén cualquier cosa que se mueva fuera de la fusión.
  • Verifica el resultado final con motion_check.py (nada se congela) y blink_map.py, que cuenta los píxeles que parpadean en fotogramas casi estáticos. Compara el recuento antes y después de un cambio. Las previsualizaciones brillan por diseño, así que juzga el parpadeo solo en el resultado final.

El contrato de la página

Cualquier página de escena funciona con los renderizadores si proporciona:

HookQué hace
#frameEl lienzo que se captura.
window.READYSe establece una vez que los assets y las fuentes están cargados.
window.render(ms)Dibuja el fotograma en el tiempo ms.
window.probe(ms)Devuelve posiciones de pantalla de algunos puntos del mundo, utilizadas para dimensionar el desenfoque de movimiento.
window.setJitter(x, y)Desplazamiento del lente de subpíxel en píxeles, establecido a través de projectionMatrix.elements[8] y [9].
window.renderMany([[ms, jx, jy], ...])Promedia varios renderizados en una sola llamada (necesario para render_fast).
?scale=.5Renderiza a la mitad de tamaño.

Todo lo animado debe ser una función pura de ms, periódica en la duración del bucle. Usa números enteros de ciclos por bucle para pasos, arrastres y lluvia.

Parpadeo y fallos

CausaSolución
Cualquier cosa en espacio de pantalla (bamboleo, rayado, ruido, bruma por distancia de cámara)Anclarlo al mundo o a la dirección de visión.
Superficies separadas unos pocos cmFusionarlas en una superficie, o mantenerlas separadas 0.4 m o más.
Planos coplanares superpuestos (marcas viales, piezas de suelo)Pintar las marcas en un solo plano, y hacer que las piezas se encuentren borde a borde.
Detalle de subpíxel (rieles, rejillas, cables, lluvia)Jitter de antialiasing en cada fotograma, y atenuar líneas densas por metros por píxel.
Un renderizado por fotogramaNunca hacer esto en resultados finales.
Bordes duros en nubes o reflejosSuavizarlos y atenuar los efectos en los bordes de la pantalla.
Cosas en movimiento que se envuelven o aparecenEnvolverlas durante el movimiento de cámara más rápido del bucle, encontrado con window.probe.

Errores comunes

  • Un comentario // añadido a una línea de código se traga el resto de la línea (un scene.add, una luz). Usa /* */.
  • Los helpers que añaden a la raíz de la escena (como plane()) ignoran el grupo actual y pueden aterrizar encima de cosas. Construye dentro de grupos.
  • Mantén las caras emisivas (pantallas, paneles de carteles) fuera de los pases de color plano y sombra, o cada glifo se entintará y oscurecerá.
  • ffmpeg -stream_loop ... -c copy hace bucles que algunos reproductores detienen antes de tiempo. Vuelve a codificar en su lugar.
  • Para X, las imágenes lado a lado a 32:9 son demasiado anchas para subir. Apílalas verticalmente.
  • Usa solo personajes originales y marcas inventadas. Copia la técnica de una referencia, nunca su obra.

Skills relacionados