VYBE 시네마틱 3D
HyperFrames 비디오의 3D는 모든 프레임이 시간의 순수 함수인 <canvas>입니다. HyperFrames의 three 어댑터가 시간을 게시하고, 여러분이 렌더링합니다. 권위: /hyperframes-animation → adapters/three.md (설치된 경우).
계약 (협상 불가)
- 고정 임포트:
import * as THREE from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";(또는 애드온에 대해 동일한 버전을 고정하는 importmap). - 씬, 카메라, 렌더러, 재료를 로드 시 동기적으로 빌드합니다. 렌더링에 중요한 시크 전에 모든 모델/텍스처를 로드합니다(Three의
DefaultLoadingManager가 자동으로 대기됨). 과중한 CPU 설정의 경우window.__hf.buildReady["<이름>"] = promise를 등록합니다. - 시간으로만 렌더링:
window.addEventListener("hf-seek", e => renderAt(e.detail.time)); renderAt(window.__hfThreeTime || 0); requestAnimationFrame루프, 시계, 델타 또는 시드되지 않은Math.random()을 사용하지 마십시오.renderer.setPixelRatio(1); renderer.setSize(W, H, false)(W/H는 루트의data-width/height에서 가져옴). 루트에는data-duration이 있어야 합니다.- 전체 너비 캔버스에
data-layout-allow-overflow를 표시합니다.
스켈레톤
<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; // 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); // 세로 모드에서 더 넓은 시야각
// … 빌드 …
function renderAt(t) { const p = t / D; /* 시간에 따른 카메라 + 객체 */ renderer.render(scene, camera); }
window.addEventListener("hf-seek", (e) => renderAt(e.detail.time));
renderAt(window.__hfThreeTime || 0);
</script>
3D 세계가 여러 씬에 걸쳐 있을 때(영화 전반에 걸친 카메라 아크)는 캔버스를 호스트(index.html)에 배치하고, 한 씬에만 존재할 때는 씬 파일에 배치합니다. 그 위에 HTML 유형을 오버레이하고, DOM 텍스트로 충분할 때는 WebGL에서 텍스트를 렌더링하지 마십시오.
레시피
- 입자 / 먼지 / 별: 위치에 시드된 PRNG, 팔레트의 정점 색상, 둥근 스프라이트(
CanvasTexture방사형 그래디언트를map으로 사용 — 기본 포인트는 사각형임),AdditiveBlending,depthWrite: false를 사용하는THREE.Points. 모든 입자를 카메라의 가장 가까운 z 너머에 유지하십시오. 그렇지 않으면 카메라가 통과할 때 거대한 스프라이트로 부풀어 오릅니다(실제 VYBE 결함). - 히어로 구체 / 행성:
SphereGeometry(r, 96, 64)+MeshStandardMaterial(메탈릭/러프니스) + 방사형 헤일로TorusGeometry링; 시간이 지남에 따라 조명을 켭니다. - 블랙홀: 어두운 구체 + 강착 원반 = 캔버스 그래디언트 텍스처가 있는
RingGeometry, 70–80° 기울여 회전; 렌즈 링 = 카메라를 향한 두 번째 얇은 토러스; 별 왜곡 = 배경 포인트 레이어를 중심 근처에서 방사형으로 스케일 조정. - 분자: 원자 위치에 구체(많은 경우
InstancedMesh사용), 그 사이에 실린더(quaternion.setFromUnitVectors로 방향 지정); 카메라 궤도. - 제품 턴테이블:
GLTFLoader(importmap)를 통한 GLTF, 제작된 클립에 대한AnimationMixer.setTime(t), 아래의 스튜디오 라이트 리그, 샷에 걸쳐 20–35° 느린 궤도. - 데이터 조각: 데이터에서 높이가 나오는
InstancedMesh상자, 시간이 지남에 따라smoothstep으로 성장. - 절차적 지형/파도: JS에서
t로PlaneGeometry를 변위(≤40k 정점의 경우 프레임당 위치 재계산)하거나renderAt에서 설정된uTime유니폼을 사용하는ShaderMaterial에서.
조명
references/lighting.md를 로드하십시오. 최소 리그: 키(Point/Directional), 대비되는 색조의 림/백 라이트, 그리고 HemisphereLight 필 — 하나의 조명만 있는 메시는 어두운 면이 검은색 컷아웃으로 렌더링됩니다. 고정된 비율로 동일한 시간 함수에서 조명 강도를 구동합니다.
카메라
정규화된 진행 p = t / D로 위치를 도출하고, 막(행동)별로 smoothstep 세그먼트를 사용합니다(시네마틱 템플릿의 renderAt 참조). 컷의 경우 const CUT_B = 23을 한 번 선언하고 이를 카메라 샷 선택기와 객체 가시성 모두에 사용합니다. 컷 직전과 직후의 프레임을 확인합니다(snapshot --at 22.9667,23).
성능 (헤드리스 Chrome은 소프트웨어 GL일 수 있음)
- ≤ 100k 삼각형, ≤ 20k 입자, 프레임 기록이 필요한 후처리 패스 없음. 블룸: 가산 스프라이트/헤일로로 가짜 구현.
- 저RAM 시스템에서
antialias+ 거대한 캔버스를 4K로 사용하지 마십시오. 드래프트 렌더링을 테스트하십시오. - 렌더 환경에서 WebGL이 실패하면 캔버스가 검은색입니다: QC에서 검은색 프레임으로 포착됨; 씬의 2D 캔버스 또는 CSS-3D 버전으로 폴백합니다.