Skip to content

Commit babf9dc

Browse files
feat(registry): add parallax-zoom and parallax-unzoom components
Two companion components inspired by the eBay Playbook hero transition: - parallax-zoom: center card scales up to fill the frame while siblings parallax outward. Single CSS variable (--pz-progress 0→1), fully seekable and deterministic. - parallax-unzoom: the reverse — focus card starts at full-frame scale and shrinks back into its grid position while siblings parallax inward. Uses --pu-progress with the pu prefix to avoid variable collisions when both components live in the same composition. Designed to chain: zoom INTO a card in scene 1, unzoom OUT of it in scene 2 to reveal a fresh grid underneath. Includes demo compositions, registry manifests, and catalog pages. Preview assets rendered and uploaded to CDN. Co-authored-by: Kanyini <onebenson@gmail.com>
1 parent 154359d commit babf9dc

9 files changed

Lines changed: 978 additions & 0 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: "Parallax Unzoom"
3+
description: "Reveal transition — focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)"
4+
---
5+
6+
# Parallax Unzoom
7+
8+
Reveal transition — focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)
9+
10+
`transition` `reveal` `unzoom` `parallax` `grid` `hero`
11+
12+
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-unzoom.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-unzoom.png" autoPlay muted loop playsInline />
13+
14+
## Install
15+
16+
<CodeGroup>
17+
18+
```bash Terminal
19+
npx hyperframes add parallax-unzoom
20+
```
21+
22+
</CodeGroup>
23+
24+
## Details
25+
26+
| Property | Value |
27+
| --- | --- |
28+
| Type | Component |
29+
30+
## Files
31+
32+
| File | Target | Type |
33+
| --- | --- | --- |
34+
| `parallax-unzoom.html` | `compositions/components/parallax-unzoom.html` | hyperframes:snippet |
35+
36+
## Usage
37+
38+
Open `compositions/components/parallax-unzoom.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: "Parallax Zoom"
3+
description: "Center card scales up to fill the frame while siblings parallax outward — inspired by the eBay Playbook hero transition"
4+
---
5+
6+
# Parallax Zoom
7+
8+
Center card scales up to fill the frame while siblings parallax outward — inspired by the eBay Playbook hero transition
9+
10+
`transition` `zoom` `parallax` `grid` `hero`
11+
12+
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-zoom.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-zoom.png" autoPlay muted loop playsInline />
13+
14+
## Install
15+
16+
<CodeGroup>
17+
18+
```bash Terminal
19+
npx hyperframes add parallax-zoom
20+
```
21+
22+
</CodeGroup>
23+
24+
## Details
25+
26+
| Property | Value |
27+
| --- | --- |
28+
| Type | Component |
29+
30+
## Files
31+
32+
| File | Target | Type |
33+
| --- | --- | --- |
34+
| `parallax-zoom.html` | `compositions/components/parallax-zoom.html` | hyperframes:snippet |
35+
36+
## Usage
37+
38+
Open `compositions/components/parallax-zoom.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=1920, height=1080" />
6+
<title>Parallax Unzoom — Demo</title>
7+
<link rel="preconnect" href="https://fonts.googleapis.com" />
8+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9+
<link
10+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800;900&display=swap"
11+
rel="stylesheet"
12+
/>
13+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
14+
<style>
15+
* {
16+
margin: 0;
17+
padding: 0;
18+
box-sizing: border-box;
19+
}
20+
21+
html,
22+
body {
23+
width: 1920px;
24+
height: 1080px;
25+
overflow: hidden;
26+
background: #f6f6f4;
27+
font-family: "Inter", system-ui, sans-serif;
28+
}
29+
30+
.demo-canvas {
31+
width: 1920px;
32+
height: 1080px;
33+
position: relative;
34+
overflow: hidden;
35+
display: flex;
36+
align-items: center;
37+
justify-content: center;
38+
}
39+
40+
.parallax-unzoom-grid {
41+
display: grid;
42+
grid-template-columns: repeat(5, 240px);
43+
grid-template-rows: repeat(3, 320px);
44+
gap: 40px;
45+
}
46+
47+
.parallax-unzoom-card {
48+
border-radius: 22px;
49+
overflow: hidden;
50+
position: relative;
51+
box-shadow: 0 12px 36px rgba(20, 20, 30, 0.08);
52+
display: flex;
53+
align-items: center;
54+
justify-content: center;
55+
}
56+
57+
.card-glyph {
58+
font-size: 92px;
59+
font-weight: 800;
60+
color: rgba(255, 255, 255, 0.92);
61+
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
62+
letter-spacing: -0.04em;
63+
line-height: 1;
64+
}
65+
66+
.pu-c0 {
67+
background: linear-gradient(135deg, #3a8b6f, #1d4d3d);
68+
}
69+
.pu-c1 {
70+
background: linear-gradient(135deg, #8b4a3a, #4a2418);
71+
}
72+
.pu-c2 {
73+
background: linear-gradient(135deg, #c89868, #8a6038);
74+
}
75+
.pu-c3 {
76+
background: linear-gradient(135deg, #3a6088, #1a2f4a);
77+
}
78+
.pu-c4 {
79+
background: linear-gradient(135deg, #b03838, #6a1818);
80+
}
81+
.pu-c5 {
82+
background: linear-gradient(135deg, #bcbcbc, #6e6e6e);
83+
}
84+
.pu-c6 {
85+
background: linear-gradient(135deg, #8a5fa0, #4a2860);
86+
}
87+
.pu-c7-focus {
88+
background: linear-gradient(135deg, #f5c93f, #d99a18);
89+
}
90+
.pu-c8 {
91+
background: linear-gradient(135deg, #d8d8d8, #9a9a9a);
92+
}
93+
.pu-c9 {
94+
background: linear-gradient(135deg, #5fa37e, #2a6a4a);
95+
}
96+
.pu-c10 {
97+
background: linear-gradient(135deg, #d1b66a, #8a7028);
98+
}
99+
.pu-c11 {
100+
background: linear-gradient(135deg, #4f7fc0, #1f3f80);
101+
}
102+
.pu-c12 {
103+
background: linear-gradient(135deg, #5a3a8f, #2a1858);
104+
}
105+
.pu-c13 {
106+
background: linear-gradient(135deg, #b85a3a, #6a2818);
107+
}
108+
.pu-c14 {
109+
background: linear-gradient(135deg, #f0f0e8, #c8c8be);
110+
}
111+
112+
.parallax-unzoom-card[data-pu-focus="true"] {
113+
grid-column: 3;
114+
grid-row: 2;
115+
}
116+
117+
.focus-label {
118+
font-weight: 900;
119+
font-size: 56px;
120+
letter-spacing: -0.04em;
121+
color: #1a1208;
122+
text-align: center;
123+
line-height: 1;
124+
opacity: 0;
125+
}
126+
127+
.focus-label small {
128+
display: block;
129+
font-size: 18px;
130+
font-weight: 600;
131+
letter-spacing: 0.18em;
132+
margin-bottom: 14px;
133+
color: rgba(26, 18, 8, 0.7);
134+
}
135+
136+
.hero-headline {
137+
position: absolute;
138+
top: 80px;
139+
left: 0;
140+
width: 100%;
141+
text-align: center;
142+
font-size: 68px;
143+
font-weight: 800;
144+
letter-spacing: -0.03em;
145+
color: #1a1a1a;
146+
opacity: 1;
147+
}
148+
149+
.parallax-unzoom-grid {
150+
--pu-progress: 0;
151+
--pu-focus-scale: 8;
152+
--pu-sibling-push: 900px;
153+
--pu-sibling-fade: 1;
154+
position: relative;
155+
transform-style: preserve-3d;
156+
}
157+
158+
.parallax-unzoom-card {
159+
transform-origin: center center;
160+
will-change: transform, opacity;
161+
transform: translate3d(
162+
calc(var(--pu-dx, 0px) * (1 - var(--pu-progress))),
163+
calc(var(--pu-dy, 0px) * (1 - var(--pu-progress))),
164+
0
165+
)
166+
scale(calc(0.7 + 0.3 * var(--pu-progress)));
167+
opacity: calc(var(--pu-progress) * var(--pu-sibling-fade));
168+
}
169+
170+
.parallax-unzoom-card[data-pu-focus="true"] {
171+
z-index: 10;
172+
transform: translate3d(0, 0, 0)
173+
scale(calc(var(--pu-focus-scale) - (var(--pu-focus-scale) - 1) * var(--pu-progress)));
174+
opacity: 1;
175+
}
176+
</style>
177+
</head>
178+
<body>
179+
<div
180+
id="demo"
181+
data-composition-id="parallax-unzoom-demo"
182+
data-width="1920"
183+
data-height="1080"
184+
data-duration="6"
185+
data-start="0"
186+
>
187+
<div class="demo-canvas">
188+
<div class="hero-headline">Inspired by how people discover.</div>
189+
190+
<div class="parallax-unzoom-grid">
191+
<div class="parallax-unzoom-card pu-c0" data-pu-row="0" data-pu-col="0">
192+
<span class="card-glyph"></span>
193+
</div>
194+
<div class="parallax-unzoom-card pu-c1" data-pu-row="0" data-pu-col="1">
195+
<span class="card-glyph"></span>
196+
</div>
197+
<div class="parallax-unzoom-card pu-c2" data-pu-row="0" data-pu-col="2">
198+
<span class="card-glyph"></span>
199+
</div>
200+
<div class="parallax-unzoom-card pu-c3" data-pu-row="0" data-pu-col="3">
201+
<span class="card-glyph"></span>
202+
</div>
203+
<div class="parallax-unzoom-card pu-c4" data-pu-row="0" data-pu-col="4">
204+
<span class="card-glyph"></span>
205+
</div>
206+
207+
<div class="parallax-unzoom-card pu-c5" data-pu-row="1" data-pu-col="0">
208+
<span class="card-glyph"></span>
209+
</div>
210+
<div class="parallax-unzoom-card pu-c6" data-pu-row="1" data-pu-col="1">
211+
<span class="card-glyph"></span>
212+
</div>
213+
<div
214+
class="parallax-unzoom-card pu-c7-focus"
215+
data-pu-row="1"
216+
data-pu-col="2"
217+
data-pu-focus="true"
218+
>
219+
<div class="focus-label">
220+
<small>EBAY PLAYBOOK</small>
221+
DISCOVER
222+
</div>
223+
</div>
224+
<div class="parallax-unzoom-card pu-c8" data-pu-row="1" data-pu-col="3">
225+
<span class="card-glyph"></span>
226+
</div>
227+
<div class="parallax-unzoom-card pu-c9" data-pu-row="1" data-pu-col="4">
228+
<span class="card-glyph"></span>
229+
</div>
230+
231+
<div class="parallax-unzoom-card pu-c10" data-pu-row="2" data-pu-col="0">
232+
<span class="card-glyph"></span>
233+
</div>
234+
<div class="parallax-unzoom-card pu-c11" data-pu-row="2" data-pu-col="1">
235+
<span class="card-glyph"></span>
236+
</div>
237+
<div class="parallax-unzoom-card pu-c12" data-pu-row="2" data-pu-col="2">
238+
<span class="card-glyph"></span>
239+
</div>
240+
<div class="parallax-unzoom-card pu-c13" data-pu-row="2" data-pu-col="3">
241+
<span class="card-glyph"></span>
242+
</div>
243+
<div class="parallax-unzoom-card pu-c14" data-pu-row="2" data-pu-col="4">
244+
<span class="card-glyph" style="color: rgba(40, 40, 40, 0.7)"></span>
245+
</div>
246+
</div>
247+
</div>
248+
249+
<script>
250+
(function () {
251+
const grids = document.querySelectorAll(".parallax-unzoom-grid");
252+
grids.forEach((grid) => {
253+
const cards = Array.from(grid.querySelectorAll(".parallax-unzoom-card"));
254+
if (cards.length === 0) return;
255+
let focal = cards.find((c) => c.dataset.puFocus === "true");
256+
if (!focal) {
257+
focal = cards[Math.floor(cards.length / 2)];
258+
focal.dataset.puFocus = "true";
259+
}
260+
const focusRow = Number(focal.dataset.puRow ?? 0);
261+
const focusCol = Number(focal.dataset.puCol ?? 0);
262+
const push =
263+
parseFloat(getComputedStyle(grid).getPropertyValue("--pu-sibling-push")) || 900;
264+
cards.forEach((card) => {
265+
if (card === focal) return;
266+
const row = Number(card.dataset.puRow ?? 0);
267+
const col = Number(card.dataset.puCol ?? 0);
268+
const dCol = col - focusCol;
269+
const dRow = row - focusRow;
270+
const mag = Math.hypot(dCol, dRow) || 1;
271+
const nx = (dCol / mag) * push * mag;
272+
const ny = (dRow / mag) * push * mag;
273+
card.style.setProperty("--pu-dx", `${nx}px`);
274+
card.style.setProperty("--pu-dy", `${ny}px`);
275+
});
276+
});
277+
278+
const tl = gsap.timeline({ paused: true });
279+
280+
tl.to(
281+
".hero-headline",
282+
{
283+
opacity: 0,
284+
duration: 0.5,
285+
ease: "power2.in",
286+
},
287+
0.3,
288+
);
289+
290+
tl.fromTo(
291+
".parallax-unzoom-grid",
292+
{ "--pu-progress": 0 },
293+
{
294+
"--pu-progress": 1,
295+
duration: 3.0,
296+
ease: "power2.inOut",
297+
},
298+
0.5,
299+
);
300+
301+
tl.to(
302+
".focus-label",
303+
{
304+
opacity: 1,
305+
duration: 1.0,
306+
ease: "power2.out",
307+
},
308+
2.5,
309+
);
310+
311+
window.__timelines = window.__timelines || {};
312+
window.__timelines["parallax-unzoom-demo"] = tl;
313+
})();
314+
</script>
315+
</div>
316+
</body>
317+
</html>

0 commit comments

Comments
 (0)