mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
feat(registry): seed transition blocks — 14 shader + 14 CSS showcase (#270)
## What Add 28 transition blocks from the Hyperframe Template Structure catalog, bringing the registry to 53 total items. ### Shader transitions (14 blocks, WebGL, 4s each) `domain-warp-dissolve`, `ridged-burn`, `whip-pan`, `sdf-iris`, `ripple-waves`, `gravitational-lens`, `cinematic-zoom`, `chromatic-radial-split`, `glitch`, `swirl-vortex`, `thermal-distortion`, `flash-through-white`, `cross-warp-morph`, `light-leak` ### CSS transition showcases (14 blocks, various durations) `transitions-3d`, `transitions-blur`, `transitions-cover`, `transitions-destruction`, `transitions-dissolve`, `transitions-distortion`, `transitions-grid`, `transitions-light`, `transitions-mechanical`, `transitions-other`, `transitions-push`, `transitions-radial`, `transitions-scale`, `transitions-shader` ## Why Phase D content accumulation. Transitions are the most-requested category for the catalog. ## How - Shader transitions extracted from `shader-showcase.zip`, each a standalone HTML with WebGL shaders - CSS transitions extracted from `showcase-bundle.zip`, each a standalone showcase page - All tagged with `transition` + `shader` or `showcase` for catalog grouping - Preview thumbnails generated for all 28 blocks - Catalog pages + index regenerated ## Test plan - [x] All 28 blocks produce preview thumbnails - [x] `registry-item.json` validates for all blocks - [x] Catalog pages generated (45 total items in catalog-index.json) - [x] `oxfmt --check` passes
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<style>
|
||||
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Bebas+Neue&family=JetBrains+Mono:wght@400;700&family=Lato:wght@400;700&display=block");
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="root"
|
||||
data-composition-id="main"
|
||||
data-start="0"
|
||||
data-duration="4"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
>
|
||||
<style>
|
||||
[data-composition-id="main"] {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #10002b;
|
||||
}
|
||||
|
||||
/* Blueprint grid */
|
||||
.bp-grid {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image:
|
||||
linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
.bp-left {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 1200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.bp-right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 720px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 60px 60px 60px 40px;
|
||||
}
|
||||
.bp-divider {
|
||||
position: absolute;
|
||||
left: 1200px;
|
||||
top: 60px;
|
||||
bottom: 60px;
|
||||
width: 1px;
|
||||
background: #f20089;
|
||||
opacity: 0.15;
|
||||
}
|
||||
.bp-number {
|
||||
font-family: "Space Mono", monospace;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.4em;
|
||||
text-transform: uppercase;
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 60px;
|
||||
color: #f20089;
|
||||
}
|
||||
|
||||
/* Right panel typography */
|
||||
.bp-name {
|
||||
font-family: "Bebas Neue", sans-serif;
|
||||
font-size: 38px;
|
||||
letter-spacing: 0.08em;
|
||||
margin-bottom: 20px;
|
||||
color: #f20089;
|
||||
}
|
||||
.bp-plabel {
|
||||
font-family: "Space Mono", monospace;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.3em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 10px;
|
||||
color: #f20089;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.bp-prompt {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 20px;
|
||||
line-height: 1.6;
|
||||
padding: 16px 20px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
color: #f20089;
|
||||
background: rgba(242, 0, 137, 0.06);
|
||||
border: 1px solid rgba(242, 0, 137, 0.12);
|
||||
}
|
||||
.bp-desc {
|
||||
font-family: "Lato", sans-serif;
|
||||
font-size: 17px;
|
||||
line-height: 1.6;
|
||||
color: #a080a0;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
/* GL scenes (hidden, just for texture capture) */
|
||||
.scene {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1200px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.scene-label {
|
||||
font-family: "Bebas Neue", sans-serif;
|
||||
font-size: 140px;
|
||||
letter-spacing: 0.06em;
|
||||
opacity: 0.12;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bp-grid"></div>
|
||||
<div class="bp-divider"></div>
|
||||
<div class="bp-number">06 / 14</div>
|
||||
|
||||
<!-- GL demo scenes (captured as textures, then hidden) -->
|
||||
<div id="s1" class="scene" style="background: #10002b">
|
||||
<div class="scene-label" style="color: #f20089">SCENE A</div>
|
||||
</div>
|
||||
<div id="s2" class="scene" style="background: #f20089; opacity: 0">
|
||||
<div class="scene-label" style="color: #10002b">SCENE B</div>
|
||||
</div>
|
||||
|
||||
<!-- GL canvas (left panel only) -->
|
||||
<canvas
|
||||
id="gl-canvas"
|
||||
width="1200"
|
||||
height="1080"
|
||||
style="
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1200px;
|
||||
height: 1080px;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
display: none;
|
||||
"
|
||||
>
|
||||
</canvas>
|
||||
|
||||
<!-- Right panel metadata -->
|
||||
<div class="bp-right">
|
||||
<div class="bp-name">Gravitational Lens</div>
|
||||
<div class="bp-plabel">Prompt</div>
|
||||
<div class="bp-prompt">"use gravitational lens shader transition"</div>
|
||||
<div class="bp-desc">
|
||||
Content warps toward a gravity well with chromatic aberration and event horizon darkening.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="driver"
|
||||
data-start="0"
|
||||
data-duration="4"
|
||||
data-track-index="0"
|
||||
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
var glCanvas = document.getElementById("gl-canvas");
|
||||
var gl = glCanvas.getContext("webgl", { preserveDrawingBuffer: true });
|
||||
if (!gl) {
|
||||
console.warn("WebGL not available");
|
||||
window.__timelines["main"] = gsap.timeline({ paused: true });
|
||||
} else {
|
||||
gl.viewport(0, 0, 1200, 1080);
|
||||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
||||
var sceneTextures = {};
|
||||
|
||||
function captureScene(sceneId) {
|
||||
var scene = document.getElementById(sceneId);
|
||||
var origOpacity = scene.style.opacity;
|
||||
var origZ = scene.style.zIndex;
|
||||
scene.style.opacity = "1";
|
||||
scene.style.zIndex = "999";
|
||||
scene.offsetHeight;
|
||||
var c = document.createElement("canvas");
|
||||
c.width = 1200;
|
||||
c.height = 1080;
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.fillStyle = window.getComputedStyle(scene).backgroundColor;
|
||||
ctx.fillRect(0, 0, 1200, 1080);
|
||||
var sr = scene.getBoundingClientRect();
|
||||
var els = scene.querySelectorAll("*");
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
var el = els[i],
|
||||
cs = window.getComputedStyle(el);
|
||||
if (cs.display === "none" || cs.visibility === "hidden") continue;
|
||||
var r = el.getBoundingClientRect();
|
||||
if (r.width < 1 || r.height < 1) continue;
|
||||
var x = r.left - sr.left,
|
||||
y = r.top - sr.top,
|
||||
w = r.width,
|
||||
h = r.height;
|
||||
ctx.save();
|
||||
ctx.globalAlpha = parseFloat(cs.opacity) || 1;
|
||||
var bg = cs.backgroundColor;
|
||||
if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
|
||||
ctx.fillStyle = bg;
|
||||
ctx.fillRect(x, y, w, h);
|
||||
}
|
||||
var hasChildEls = el.querySelector("div,span,img,video");
|
||||
var text = "";
|
||||
for (var j = 0; j < el.childNodes.length; j++)
|
||||
if (el.childNodes[j].nodeType === 3) text += el.childNodes[j].textContent;
|
||||
text = text.trim();
|
||||
if (text && !hasChildEls) {
|
||||
ctx.font = cs.fontWeight + " " + cs.fontSize + " " + cs.fontFamily;
|
||||
ctx.fillStyle = cs.color;
|
||||
if (cs.letterSpacing && cs.letterSpacing !== "normal")
|
||||
ctx.letterSpacing = cs.letterSpacing;
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(text, x + w / 2, y + h / 2);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
scene.style.opacity = origOpacity;
|
||||
scene.style.zIndex = origZ;
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
|
||||
sceneTextures[sceneId] = tex;
|
||||
}
|
||||
|
||||
var vertSrc =
|
||||
"attribute vec2 a_pos; varying vec2 v_uv; void main(){" +
|
||||
"v_uv=a_pos*0.5+0.5; v_uv.y=1.0-v_uv.y; gl_Position=vec4(a_pos,0,1);}";
|
||||
var quadBuf = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
|
||||
gl.bufferData(
|
||||
gl.ARRAY_BUFFER,
|
||||
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
|
||||
gl.STATIC_DRAW,
|
||||
);
|
||||
function compileShader(src, type) {
|
||||
var s = gl.createShader(type);
|
||||
gl.shaderSource(s, src);
|
||||
gl.compileShader(s);
|
||||
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
|
||||
console.error("Shader:", gl.getShaderInfoLog(s));
|
||||
return s;
|
||||
}
|
||||
function mkProg(fragSrc) {
|
||||
var p = gl.createProgram();
|
||||
gl.attachShader(p, compileShader(vertSrc, gl.VERTEX_SHADER));
|
||||
gl.attachShader(p, compileShader(fragSrc, gl.FRAGMENT_SHADER));
|
||||
gl.linkProgram(p);
|
||||
if (!gl.getProgramParameter(p, gl.LINK_STATUS))
|
||||
console.error("Link:", gl.getProgramInfoLog(p));
|
||||
return p;
|
||||
}
|
||||
|
||||
var H =
|
||||
"precision mediump float;" +
|
||||
"varying vec2 v_uv;" +
|
||||
"uniform sampler2D u_from, u_to;" +
|
||||
"uniform float u_progress;" +
|
||||
"uniform vec2 u_resolution;\n";
|
||||
|
||||
var progPass = mkProg(H + "void main(){gl_FragColor=texture2D(u_from,v_uv);}");
|
||||
var progTrans = mkProg(
|
||||
H +
|
||||
"void main(){vec4 B=texture2D(u_to,v_uv);vec2 uv=v_uv-.5;float dist=length(uv);float pull=u_progress*2.;float warpStr=pull*.3/(dist+.1);vec2 warped=clamp(v_uv-uv*warpStr,0.,1.);vec4 A=texture2D(u_from,warped);float horizon=smoothstep(0.,.3,dist/(1.-u_progress*.85+.001));float shift=pull*.02/(dist+.2);float r=texture2D(u_from,clamp(v_uv-uv*(warpStr+shift),0.,1.)).r;float b=texture2D(u_from,clamp(v_uv-uv*(warpStr-shift),0.,1.)).b;vec3 lensed=vec3(r,A.g,b)*horizon;gl_FragColor=vec4(mix(lensed,B.rgb,smoothstep(.3,.9,u_progress)),1.);}",
|
||||
);
|
||||
|
||||
function renderShader(prog, texFrom, texTo, progress) {
|
||||
gl.useProgram(prog);
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texFrom);
|
||||
gl.uniform1i(gl.getUniformLocation(prog, "u_from"), 0);
|
||||
gl.activeTexture(gl.TEXTURE1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texTo);
|
||||
gl.uniform1i(gl.getUniformLocation(prog, "u_to"), 1);
|
||||
gl.uniform1f(gl.getUniformLocation(prog, "u_progress"), progress);
|
||||
gl.uniform2f(gl.getUniformLocation(prog, "u_resolution"), 1200, 1080);
|
||||
var pos = gl.getAttribLocation(prog, "a_pos");
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
|
||||
gl.enableVertexAttribArray(pos);
|
||||
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
function easeInOut(p) {
|
||||
return p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
|
||||
}
|
||||
|
||||
captureScene("s1");
|
||||
captureScene("s2");
|
||||
glCanvas.style.display = "block";
|
||||
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
|
||||
document.querySelectorAll(".scene").forEach(function (s) {
|
||||
s.style.opacity = "0";
|
||||
});
|
||||
|
||||
var tl = gsap.timeline({
|
||||
paused: true,
|
||||
onUpdate: function () {
|
||||
var t = tl.time();
|
||||
if (t >= 1.0 && t < 3.0) {
|
||||
renderShader(
|
||||
progTrans,
|
||||
sceneTextures["s1"],
|
||||
sceneTextures["s2"],
|
||||
easeInOut((t - 1.0) / 2.0),
|
||||
);
|
||||
} else if (t >= 3.0) {
|
||||
renderShader(progPass, sceneTextures["s2"], sceneTextures["s2"], 0);
|
||||
} else {
|
||||
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
|
||||
}
|
||||
},
|
||||
});
|
||||
tl.to({ v: 0 }, { v: 1, duration: 4, ease: "none" }, 0);
|
||||
window.__timelines["main"] = tl;
|
||||
} // end if (gl)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
|
||||
"name": "gravitational-lens",
|
||||
"type": "hyperframes:block",
|
||||
"title": "Gravitational Lens",
|
||||
"description": "Shader transition with gravitational lensing distortion",
|
||||
"tags": ["transition", "shader"],
|
||||
"dimensions": {
|
||||
"width": 1920,
|
||||
"height": 1080
|
||||
},
|
||||
"duration": 4,
|
||||
"files": [
|
||||
{
|
||||
"path": "gravitational-lens.html",
|
||||
"target": "compositions/gravitational-lens.html",
|
||||
"type": "hyperframes:composition"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user