VYBE Cinematic 3D
El 3D en un vídeo de HyperFrames es un <canvas> cuyo cada fotograma es una función pura
del tiempo. El adaptador three de HyperFrames publica el tiempo; tú lo renderizas.
Autoridad: /hyperframes-animation → adapters/three.md cuando está instalado.
Contrato (no negociable)
- Importación fija:
import * as THREE from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";(o un importmap que fije la misma versión para addons). - Construye escena, cámara, renderizador y materiales sincrónicamente al cargar; carga cualquier
modelo/textura antes de una búsqueda crítica para el render (el
DefaultLoadingManagerde Three se espera automáticamente). Para configuración pesada de CPU, registrawindow.__hf.buildReady["<nombre>"] = promise. - Renderiza solo a partir del tiempo:
window.addEventListener("hf-seek", e => renderAt(e.detail.time)); renderAt(window.__hfThreeTime || 0); - No hay bucles
requestAnimationFrame, relojes, deltas niMath.random()sin semilla. renderer.setPixelRatio(1); renderer.setSize(W, H, false)con W/H deldata-width/heightde la raíz. La raíz debe tenerdata-duration.- Marca el canvas a sangre completa con
data-layout-allow-overflow.
Esqueleto
<canvas id="gl" width="1920" height="1080" data-layout-allow-overflow></canvas>
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";
const root = document.getElementById("vybe-root");
const W = +root.dataset.width, H = +root.dataset.height, D = +root.dataset.duration;
const css = getComputedStyle(document.documentElement);
const tok = (n, f) => css.getPropertyValue(n).trim() || f; // lee tokens VYBE
const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById("gl"), antialias: true });
renderer.setPixelRatio(1); renderer.setSize(W, H, false);
renderer.setClearColor(new THREE.Color(tok("--vy-bg", "#000")), 1);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(W > H ? 40 : 60, W / H, 0.1, 200); // mayor FOV en vertical
// … construir …
function renderAt(t) { const p = t / D; /* cámara + objetos desde t */ renderer.render(scene, camera); }
window.addEventListener("hf-seek", (e) => renderAt(e.detail.time));
renderAt(window.__hfThreeTime || 0);
</script>
Coloca el canvas en el anfitrión (index.html) cuando el mundo 3D abarque escenas
(arco de cámara a lo largo de la película); colócalo en un archivo de escena solo cuando viva en una escena.
Superpone HTML encima; nunca renderices texto en WebGL cuando el texto del DOM sea suficiente.
Recetas
- Partículas / polvo / estrellas:
THREE.Pointscon un generador de números pseudoaleatorios (PRNG) con semilla para posiciones, colores de vértice desde la paleta, un sprite redondo (CanvasTexturegradiente radial comomap) — los puntos por defecto son cuadrados —AdditiveBlending,depthWrite: false. Mantén cada partícula más allá del z más cercano de la cámara, o se hincha en un sprite gigante cuando la cámara la pasa (un defecto real de VYBE). - Orbe héroe / planeta:
SphereGeometry(r, 96, 64)+MeshStandardMaterial(metalness/roughness) + halo emisivo anilloTorusGeometry; ilumínalo a lo largo del tiempo. - Agujero negro: esfera oscura + disco de acreción =
RingGeometrycon una textura de gradiente de canvas, inclinado 70–80°, rotando; anillo de lente = segundo toro fino mirando a la cámara; estrellas curvándose = escala una capa de puntos de fondo radialmente cerca del centro. - Molécula: esferas en posiciones de átomos (
InstancedMeshpara muchas), cilindros entre ellos (orienta conquaternion.setFromUnitVectors); cámara en órbita. - Giro de producto: GLTF mediante
GLTFLoader(importmap),AnimationMixer.setTime(t)para clips animados; rig de luz de estudio debajo; órbita lenta 20–35° sobre la toma. - Escultura de datos:
InstancedMeshde cajas cuyas alturas provienen de datos, crecidas consmoothstepa lo largo del tiempo. - Terreno/olas procedurales: desplaza un
PlaneGeometryen JS desdet(recalcula posiciones por fotograma para ≤40k vértices) o en unShaderMaterialcon un uniformeuTimeestablecido enrenderAt.
Iluminación
Carga references/lighting.md. Rig mínimo: clave (Point/Directional), contraluz/trasera
en un tono contrastante, y un HemisphereLight de relleno — una malla iluminada con solo
una luz se renderiza como un recorte negro en su lado oscuro. Conduce las intensidades de luz desde
la misma función de tiempo con relaciones fijas.
Cámara
Deriva la posición a partir del progreso normalizado p = t / D con segmentos smoothstep por
acto (ver el renderAt de la plantilla cinematográfica). Para cortes, declara const CUT_B = 23
una vez y úsalo tanto para el selector de toma de cámara como para la visibilidad de objetos; verifica
los fotogramas justo antes y después (snapshot --at 22.9667,23).
Rendimiento (Chrome headless puede ser software GL)
- ≤ 100k triángulos, ≤ 20k partículas, sin pases de postprocesado que necesiten historial de fotogramas. Bloom: simúlalo con sprites/halos aditivos.
- Evita
antialias+ canvas enormes a 4K en máquinas con poca RAM; prueba un render borrador. - Si WebGL falla en el entorno de render, el canvas es negro: el control de calidad lo detecta como fotogramas negros; recurre a un canvas 2D o a una versión CSS-3D de la escena.