mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 16:42:27 +00:00
feat(registry): polish Liquid Glass catalog blocks
This commit is contained in:
+238
-159
@@ -4,10 +4,6 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=1920, height=1080" />
|
||||
<title>Liquid Glass Media Controls</title>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
<script src="lib/liquid-glass.iife.js"></script>
|
||||
@@ -65,41 +61,41 @@
|
||||
--lg-saturation: 0.25;
|
||||
}
|
||||
.search-panel {
|
||||
width: 480px;
|
||||
height: 56px;
|
||||
--lg-corner-radius: 18;
|
||||
width: 640px;
|
||||
height: 72px;
|
||||
--lg-corner-radius: 24;
|
||||
}
|
||||
.toggle-panel {
|
||||
width: 480px;
|
||||
height: 50px;
|
||||
width: 640px;
|
||||
height: 64px;
|
||||
--lg-corner-radius: 44;
|
||||
}
|
||||
.media-panel {
|
||||
width: 480px;
|
||||
height: 88px;
|
||||
width: 640px;
|
||||
height: 116px;
|
||||
--lg-corner-radius: 44;
|
||||
}
|
||||
.slider-panel {
|
||||
width: 480px;
|
||||
height: 58px;
|
||||
--lg-corner-radius: 22;
|
||||
width: 640px;
|
||||
height: 76px;
|
||||
--lg-corner-radius: 28;
|
||||
}
|
||||
|
||||
#glass-search {
|
||||
top: 400px;
|
||||
left: 720px;
|
||||
top: 300px;
|
||||
left: 640px;
|
||||
}
|
||||
#glass-toggle {
|
||||
top: 470px;
|
||||
left: 720px;
|
||||
top: 390px;
|
||||
left: 640px;
|
||||
}
|
||||
#glass-media {
|
||||
top: 534px;
|
||||
left: 720px;
|
||||
top: 476px;
|
||||
left: 640px;
|
||||
}
|
||||
#glass-slider {
|
||||
top: 636px;
|
||||
left: 720px;
|
||||
top: 616px;
|
||||
left: 640px;
|
||||
}
|
||||
|
||||
/* ── Text Overlays ── */
|
||||
@@ -111,85 +107,131 @@
|
||||
|
||||
/* Search bar */
|
||||
.search-text {
|
||||
width: 480px;
|
||||
height: 56px;
|
||||
width: 640px;
|
||||
height: 72px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 0 20px;
|
||||
gap: 16px;
|
||||
padding: 0 28px;
|
||||
background: #02040a;
|
||||
border-radius: 24px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
.search-text svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
stroke: rgba(255, 255, 255, 0.45);
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
stroke: rgba(255, 255, 255, 0.86);
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.search-text span {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
.search-label {
|
||||
font-size: 19px;
|
||||
font-weight: 650;
|
||||
color: #fff;
|
||||
}
|
||||
.search-caret {
|
||||
width: 2px;
|
||||
height: 25px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.82);
|
||||
opacity: 0;
|
||||
}
|
||||
#text-search {
|
||||
top: 400px;
|
||||
left: 720px;
|
||||
top: 300px;
|
||||
left: 640px;
|
||||
}
|
||||
|
||||
/* Toggle row */
|
||||
.toggle-text {
|
||||
width: 480px;
|
||||
height: 50px;
|
||||
width: 640px;
|
||||
height: 64px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0;
|
||||
position: relative;
|
||||
padding: 6px;
|
||||
background: rgba(5, 10, 20, 0.52);
|
||||
border-radius: 44px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.toggle-active-pill {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
z-index: 0;
|
||||
width: 209px;
|
||||
height: 52px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.16);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
.toggle-item {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
line-height: 50px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.96);
|
||||
line-height: 52px;
|
||||
}
|
||||
.toggle-item.active {
|
||||
color: #fff;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 44px;
|
||||
}
|
||||
#text-toggle {
|
||||
top: 470px;
|
||||
left: 720px;
|
||||
top: 390px;
|
||||
left: 640px;
|
||||
}
|
||||
|
||||
/* Media pill */
|
||||
.media-text {
|
||||
width: 480px;
|
||||
height: 88px;
|
||||
width: 640px;
|
||||
height: 116px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 0 16px;
|
||||
gap: 22px;
|
||||
padding: 0 24px;
|
||||
background: rgba(5, 10, 20, 0.56);
|
||||
border-radius: 44px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
.album-art {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(135deg, #6366f1, #ec4899);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 78px;
|
||||
height: 78px;
|
||||
border-radius: 20px;
|
||||
background:
|
||||
radial-gradient(circle at 70% 28%, rgba(255, 255, 255, 0.78), transparent 16%),
|
||||
conic-gradient(from 210deg, #06e3fa, #4fdb5e, #f59e0b, #ec4899, #06e3fa);
|
||||
flex-shrink: 0;
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.28),
|
||||
0 12px 26px rgba(0, 0, 0, 0.24);
|
||||
}
|
||||
.album-sheen {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: -70px;
|
||||
width: 38px;
|
||||
height: 110px;
|
||||
background: rgba(255, 255, 255, 0.34);
|
||||
filter: blur(8px);
|
||||
transform: rotate(24deg);
|
||||
}
|
||||
.media-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
gap: 7px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.media-title {
|
||||
font-size: 15px;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
@@ -197,45 +239,72 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.media-artist {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.84);
|
||||
}
|
||||
.media-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
}
|
||||
.live-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #4ade80;
|
||||
box-shadow: 0 0 14px rgba(74, 222, 128, 0.76);
|
||||
}
|
||||
.sound-wave {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
gap: 3px;
|
||||
height: 16px;
|
||||
}
|
||||
.sound-wave span {
|
||||
width: 3px;
|
||||
height: 7px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.74);
|
||||
}
|
||||
.transport {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
gap: 24px;
|
||||
margin-left: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
.transport svg {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
fill: #fff;
|
||||
stroke: none;
|
||||
}
|
||||
.transport .play-btn svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
#text-media {
|
||||
top: 534px;
|
||||
left: 720px;
|
||||
top: 476px;
|
||||
left: 640px;
|
||||
}
|
||||
|
||||
/* Brightness slider */
|
||||
.slider-text {
|
||||
width: 480px;
|
||||
height: 58px;
|
||||
width: 640px;
|
||||
height: 76px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 0 22px;
|
||||
gap: 18px;
|
||||
padding: 0 28px;
|
||||
background: rgba(5, 10, 20, 0.56);
|
||||
border-radius: 28px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
.slider-text svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
stroke: rgba(255, 255, 255, 0.6);
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
stroke: rgba(255, 255, 255, 0.88);
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
@@ -244,31 +313,32 @@
|
||||
}
|
||||
.slider-track {
|
||||
flex: 1;
|
||||
height: 6px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border-radius: 3px;
|
||||
height: 8px;
|
||||
background: rgba(255, 255, 255, 0.22);
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
}
|
||||
.slider-fill {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 68%;
|
||||
width: 34%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 14px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.slider-pct {
|
||||
font-size: 14px;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-variant-numeric: tabular-nums;
|
||||
width: 36px;
|
||||
width: 42px;
|
||||
text-align: right;
|
||||
}
|
||||
#text-slider {
|
||||
top: 636px;
|
||||
left: 720px;
|
||||
top: 616px;
|
||||
left: 640px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -297,11 +367,13 @@
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
||||
</svg>
|
||||
<span>Search</span>
|
||||
<span id="search-label" class="search-label">Search</span>
|
||||
<span id="search-caret" class="search-caret"></span>
|
||||
</div>
|
||||
|
||||
<!-- Toggle row -->
|
||||
<div id="text-toggle" class="text-overlay toggle-text">
|
||||
<div id="toggle-pill" class="toggle-active-pill"></div>
|
||||
<div class="toggle-item active">All</div>
|
||||
<div class="toggle-item">Favorites</div>
|
||||
<div class="toggle-item">Recent</div>
|
||||
@@ -309,10 +381,16 @@
|
||||
|
||||
<!-- Media pill -->
|
||||
<div id="text-media" class="text-overlay media-text">
|
||||
<div class="album-art"></div>
|
||||
<div class="album-art"><span id="album-sheen" class="album-sheen"></span></div>
|
||||
<div class="media-info">
|
||||
<div class="media-title">Midnight Drive</div>
|
||||
<div class="media-artist">Glass Resonance</div>
|
||||
<div class="media-meta-row">
|
||||
<span id="live-dot" class="live-dot"></span>
|
||||
<div class="media-artist">Glass Resonance</div>
|
||||
<div id="sound-wave" class="sound-wave">
|
||||
<span></span><span></span><span></span><span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transport">
|
||||
<span>
|
||||
@@ -346,8 +424,8 @@
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
||||
</svg>
|
||||
<div class="slider-track"><div class="slider-fill"></div></div>
|
||||
<span class="slider-pct">68%</span>
|
||||
<div class="slider-track"><div id="slider-fill" class="slider-fill"></div></div>
|
||||
<span id="slider-pct" class="slider-pct">34%</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -450,8 +528,10 @@
|
||||
var glassCanvas = document.getElementById("glass-canvas");
|
||||
var ctx = glassCanvas.getContext("2d");
|
||||
var lg = new LiquidGlass.LiquidGlassCanvas(glassCanvas);
|
||||
var lgReady = false;
|
||||
|
||||
function renderGlass(time) {
|
||||
if (!lgReady) return;
|
||||
uniforms.uTime.value = time;
|
||||
renderer.render(scene, camera);
|
||||
ctx.clearRect(0, 0, W, H);
|
||||
@@ -459,6 +539,23 @@
|
||||
lg.renderGlassElements();
|
||||
}
|
||||
|
||||
function requestGlassRender(time) {
|
||||
if (glassCanvas.requestPaint) {
|
||||
glassCanvas.onpaint = function () {
|
||||
renderGlass(time);
|
||||
};
|
||||
glassCanvas.requestPaint();
|
||||
return;
|
||||
}
|
||||
renderGlass(time);
|
||||
}
|
||||
|
||||
lg.waitForInit().then(function (ok) {
|
||||
if (!ok) return;
|
||||
lgReady = true;
|
||||
requestGlassRender(0);
|
||||
});
|
||||
|
||||
/* ── GSAP Timeline ──────────────────────────────────────────────── */
|
||||
window.__timelines = window.__timelines || {};
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
@@ -471,99 +568,81 @@
|
||||
var tt = document.getElementById("text-toggle");
|
||||
var tm = document.getElementById("text-media");
|
||||
var tsl = document.getElementById("text-slider");
|
||||
var searchLabel = document.getElementById("search-label");
|
||||
var sliderPct = document.getElementById("slider-pct");
|
||||
var sliderValue = { value: 34 };
|
||||
|
||||
/* All panels start stacked at center */
|
||||
var cx = 720,
|
||||
cy = 496;
|
||||
gsap.set([gs, ts, gt, tt, gm, tm, gsl, tsl], { top: 1160, opacity: 1 });
|
||||
gsap.set("#sound-wave span", { height: 7 });
|
||||
|
||||
/* Search: drifts upper-left */
|
||||
tl.fromTo(
|
||||
[gs, ts],
|
||||
{ left: cx, top: cy },
|
||||
{ left: 180, top: 180, duration: 3, ease: "power2.out" },
|
||||
0,
|
||||
tl.to([gs, ts], { top: 300, duration: 0.48, ease: "power3.out" }, 0.12);
|
||||
tl.to([gt, tt], { top: 390, duration: 0.44, ease: "power3.out" }, 0.22);
|
||||
tl.to([gm, tm], { top: 476, duration: 0.44, ease: "power3.out" }, 0.32);
|
||||
tl.to([gsl, tsl], { top: 616, duration: 0.46, ease: "power3.out" }, 0.42);
|
||||
|
||||
tl.call(
|
||||
function () {
|
||||
searchLabel.textContent = "Search Music";
|
||||
},
|
||||
null,
|
||||
0.9,
|
||||
);
|
||||
tl.to(
|
||||
[gs, ts],
|
||||
{ left: 320, top: 260, duration: 5, ease: "sine.inOut", yoyo: true, repeat: 1 },
|
||||
3,
|
||||
"#search-caret",
|
||||
{ opacity: 1, duration: 0.1, yoyo: true, repeat: 5, ease: "none" },
|
||||
0.94,
|
||||
);
|
||||
tl.fromTo(
|
||||
[gs, ts],
|
||||
{ top: "+=0" },
|
||||
{ top: "+=50", duration: 2.2, ease: "sine.inOut", yoyo: true, repeat: 2 },
|
||||
1,
|
||||
tl.call(
|
||||
function () {
|
||||
searchLabel.textContent = "Midnight Drive";
|
||||
},
|
||||
null,
|
||||
1.55,
|
||||
);
|
||||
|
||||
/* Toggle: drifts upper-right */
|
||||
tl.fromTo(
|
||||
[gt, tt],
|
||||
{ left: cx, top: cy },
|
||||
{ left: 1340, top: 220, duration: 3.2, ease: "back.out(1.2)" },
|
||||
0,
|
||||
tl.to("#toggle-pill", { left: 215, duration: 0.24, ease: "power2.out" }, 1.82);
|
||||
tl.to(
|
||||
".play-btn",
|
||||
{ scale: 0.86, duration: 0.12, ease: "power2.out", yoyo: true, repeat: 1 },
|
||||
2.18,
|
||||
);
|
||||
tl.to("#album-sheen", { left: 112, duration: 0.75, ease: "power2.out" }, 2.2);
|
||||
tl.to(
|
||||
"#sound-wave span",
|
||||
{ height: 15, duration: 0.22, ease: "power2.inOut", stagger: 0.05, yoyo: true, repeat: 12 },
|
||||
2.2,
|
||||
);
|
||||
tl.to(
|
||||
[gt, tt],
|
||||
{ left: 1200, top: 300, duration: 4.8, ease: "sine.inOut", yoyo: true, repeat: 1 },
|
||||
3.2,
|
||||
);
|
||||
tl.fromTo(
|
||||
[gt, tt],
|
||||
{ top: "+=0" },
|
||||
{ top: "+=40", duration: 1.9, ease: "sine.inOut", yoyo: true, repeat: 3 },
|
||||
0.5,
|
||||
);
|
||||
|
||||
/* Media: drifts lower-left */
|
||||
tl.fromTo(
|
||||
[gm, tm],
|
||||
{ left: cx, top: cy },
|
||||
{ left: 200, top: 740, duration: 2.8, ease: "expo.out" },
|
||||
0,
|
||||
sliderValue,
|
||||
{
|
||||
value: 82,
|
||||
duration: 4.4,
|
||||
ease: "none",
|
||||
onUpdate: function () {
|
||||
sliderPct.textContent = Math.round(sliderValue.value) + "%";
|
||||
},
|
||||
},
|
||||
1.2,
|
||||
);
|
||||
tl.to("#slider-fill", { width: "82%", duration: 4.4, ease: "none" }, 1.2);
|
||||
tl.to(
|
||||
[gm, tm],
|
||||
{ left: 400, top: 680, duration: 5.2, ease: "sine.inOut", yoyo: true, repeat: 1 },
|
||||
2.8,
|
||||
);
|
||||
tl.fromTo(
|
||||
[gm, tm],
|
||||
{ top: "+=0" },
|
||||
{ top: "+=55", duration: 2.5, ease: "sine.inOut", yoyo: true, repeat: 2 },
|
||||
0.8,
|
||||
"#live-dot",
|
||||
{ scale: 1.45, duration: 0.24, ease: "power2.out", yoyo: true, repeat: 4 },
|
||||
2.6,
|
||||
);
|
||||
tl.to("#toggle-pill", { left: 425, duration: 0.24, ease: "power2.out" }, 4.15);
|
||||
|
||||
/* Slider: drifts lower-right */
|
||||
tl.fromTo(
|
||||
[gsl, tsl],
|
||||
{ left: cx, top: cy },
|
||||
{ left: 1280, top: 800, duration: 3.5, ease: "circ.out" },
|
||||
0,
|
||||
);
|
||||
tl.to(
|
||||
[gsl, tsl],
|
||||
{ left: 1100, top: 720, duration: 4.5, ease: "sine.inOut", yoyo: true, repeat: 1 },
|
||||
3.5,
|
||||
);
|
||||
tl.fromTo(
|
||||
[gsl, tsl],
|
||||
{ top: "+=0" },
|
||||
{ top: "+=45", duration: 2.0, ease: "sine.inOut", yoyo: true, repeat: 2 },
|
||||
0.3,
|
||||
);
|
||||
var stack = [gs, ts, gt, tt, gm, tm, gsl, tsl];
|
||||
tl.to(stack, { top: "-=8", duration: 0.22, ease: "power2.out", yoyo: true, repeat: 1 }, 5.55);
|
||||
tl.to(stack, { top: "+=760", duration: 0.42, ease: "power2.in" }, 6.72);
|
||||
|
||||
/* Duration driver */
|
||||
tl.to({ v: 0 }, { v: 1, duration: DURATION, ease: "none" }, 0);
|
||||
|
||||
tl.eventCallback("onUpdate", function () {
|
||||
renderGlass(tl.time());
|
||||
requestGlassRender(tl.time());
|
||||
});
|
||||
|
||||
window.__timelines["liquid-glass-media-controls"] = tl;
|
||||
|
||||
setTimeout(function () {
|
||||
renderGlass(0);
|
||||
}, 0);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"height": 1080
|
||||
},
|
||||
"duration": 8,
|
||||
"tags": ["liquid-glass-html-in-canvas", "webgpu"],
|
||||
"tags": ["html-in-canvas", "liquid-glass-html-in-canvas", "webgpu"],
|
||||
"files": [
|
||||
{
|
||||
"path": "liquid-glass-media-controls.html",
|
||||
|
||||
Reference in New Issue
Block a user