mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
Merge pull request #1036 from heygen-com/feat/registry-parallax-zoom-unzoom
feat(registry): add parallax-zoom and parallax-unzoom components
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
---
|
||||
title: "Spain Map"
|
||||
description: "Animated Spain choropleth by autonomous community with staggered reveals and gradient legend"
|
||||
description: "Animated Spain choropleth by autonomous community with staggered reveals and gradient legend — D3 conic conformal projection"
|
||||
---
|
||||
|
||||
# Spain Map
|
||||
|
||||
Animated Spain choropleth by autonomous community with staggered reveals and gradient legend — D3 conic conformal projection with GSAP timeline. GDP per capita data with warm red-to-amber color scale.
|
||||
Animated Spain choropleth by autonomous community with staggered reveals and gradient legend — D3 conic conformal projection
|
||||
|
||||
`data` `map` `geography` `spain` `europe` `choropleth`
|
||||
|
||||
<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/blocks/spain-map.mp4?v=1779081476" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/spain-map.png" autoPlay muted loop playsInline />
|
||||
<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/blocks/spain-map.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/spain-map.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
title: "US Bubble Map"
|
||||
description: "Animated US bubble map with proportional city markers, value callouts, and connection lines"
|
||||
description: "Animated US bubble map with proportional city markers, value callouts, and connection lines — composable with us-map"
|
||||
---
|
||||
|
||||
# US Bubble Map
|
||||
|
||||
Animated US bubble map with proportional city markers, value callouts, and connection lines — composable with `us-map` for layered data visualizations.
|
||||
Animated US bubble map with proportional city markers, value callouts, and connection lines — composable with us-map
|
||||
|
||||
`data` `map` `geography` `usa` `bubble` `cities`
|
||||
|
||||
<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/blocks/us-map-bubble.mp4?v=1779081476" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map-bubble.png" autoPlay muted loop playsInline />
|
||||
<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/blocks/us-map-bubble.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map-bubble.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ description: "Animated connection arcs between US cities over a base map — com
|
||||
|
||||
# US Flow Map
|
||||
|
||||
Animated connection arcs between US cities over a base map — composable origin-destination flow visualization with traveling particles and GSAP-drawn Bezier arcs.
|
||||
Animated connection arcs between US cities over a base map — composable origin-destination flow visualization
|
||||
|
||||
`data` `map` `geography` `usa` `flow` `connections` `arcs`
|
||||
|
||||
<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/blocks/us-map-flow.mp4?v=1779081476" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map-flow.png" autoPlay muted loop playsInline />
|
||||
<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/blocks/us-map-flow.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map-flow.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ description: "Animated hexagonal tile grid map — each state as an equal-weight
|
||||
|
||||
# US Hex Grid Map
|
||||
|
||||
Animated hexagonal tile grid map — each state as an equal-weight hex with data fill and abbreviation label. No external dependencies beyond GSAP.
|
||||
Animated hexagonal tile grid map — each state as an equal-weight hex with data fill and abbreviation label
|
||||
|
||||
`data` `map` `geography` `usa` `hexgrid` `tilegrid`
|
||||
|
||||
<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/blocks/us-map-hex.mp4?v=1779081476" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map-hex.png" autoPlay muted loop playsInline />
|
||||
<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/blocks/us-map-hex.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map-hex.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
title: "US Map"
|
||||
description: "Animated US choropleth map with staggered state reveals, value labels, and gradient legend"
|
||||
description: "Animated US choropleth map with staggered state reveals, value labels, and gradient legend — pure inline SVG with GSAP"
|
||||
---
|
||||
|
||||
# US Map
|
||||
|
||||
Animated US choropleth map with staggered state reveals, value labels, and gradient legend — D3 geoAlbersUsa projection with GSAP timeline.
|
||||
Animated US choropleth map with staggered state reveals, value labels, and gradient legend — pure inline SVG with GSAP
|
||||
|
||||
`data` `map` `geography` `usa` `choropleth`
|
||||
|
||||
<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/blocks/us-map-v1779081660.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map.png" autoPlay muted loop playsInline />
|
||||
<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/blocks/us-map.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/us-map.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
@@ -42,12 +42,3 @@ After installing, add the block to your host composition:
|
||||
```html
|
||||
<div data-composition-id="us-map" data-composition-src="compositions/us-map.html" data-start="0" data-duration="12" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
|
||||
## Composability
|
||||
|
||||
Layer `us-map-bubble` or `us-map-flow` on top of this block as a higher track index to combine choropleth + bubble or flow visualizations:
|
||||
|
||||
```html
|
||||
<div data-composition-id="us-map" data-composition-src="compositions/us-map.html" data-start="0" data-duration="12" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
<div data-composition-id="us-map-bubble" data-composition-src="compositions/us-map-bubble.html" data-start="0" data-duration="12" data-track-index="2" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
title: "World Map"
|
||||
description: "Animated world choropleth with country-by-country reveal — D3 Natural Earth projection"
|
||||
description: "Animated world choropleth with country-by-country reveal, tooltip labels, and rotating globe inset — D3 Natural Earth projection"
|
||||
---
|
||||
|
||||
# World Map
|
||||
|
||||
Animated world choropleth with country-by-country reveal, gradient legend, and highlight pulses on top GDP countries — D3 Natural Earth projection with GSAP timeline.
|
||||
Animated world choropleth with country-by-country reveal, tooltip labels, and rotating globe inset — D3 Natural Earth projection
|
||||
|
||||
`data` `map` `geography` `world` `choropleth`
|
||||
|
||||
<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/blocks/world-map.mp4?v=1779081476" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/world-map.png" autoPlay muted loop playsInline />
|
||||
<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/blocks/world-map.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/world-map.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
---
|
||||
title: "Blend Difference"
|
||||
description: "Auto-inverting captions using mix-blend-mode: difference — text flips between white and black per-pixel against the background"
|
||||
description: "Auto-inverting text using mix-blend-mode: difference — flips between white and black per-pixel against the background"
|
||||
---
|
||||
|
||||
# Blend Difference
|
||||
|
||||
Auto-inverting captions using mix-blend-mode: difference — text flips between white and black per-pixel against the background
|
||||
Auto-inverting text using mix-blend-mode: difference — flips between white and black per-pixel against the background
|
||||
|
||||
`text` `effect` `blend-mode` `contrast` `inversion`
|
||||
|
||||
<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/caption-blend-difference.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-blend-difference.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
@@ -19,49 +21,6 @@ npx hyperframes add caption-blend-difference
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## How It Works
|
||||
|
||||
White text with `mix-blend-mode: difference` inverts per-pixel against whatever is behind it:
|
||||
|
||||
- **Dark background** → text stays white
|
||||
- **Light background** → text flips to black
|
||||
- **Color background** → text becomes the complement (blue → orange, red → cyan)
|
||||
|
||||
The composition root needs `isolation: isolate` so the blend operates against sibling content (video, images) rather than the page background.
|
||||
|
||||
## Variants
|
||||
|
||||
| Class | Blend Mode | Effect |
|
||||
| --- | --- | --- |
|
||||
| `.blend-difference` | `difference` | Hard per-pixel inversion — maximum contrast |
|
||||
| `.blend-difference-soft` | `exclusion` | Softer inversion — less harsh on midtones |
|
||||
| `.blend-difference-screen` | `screen` | Text glows on dark areas, fades on light |
|
||||
|
||||
## Example
|
||||
|
||||
```html
|
||||
<div data-composition-id="root" style="isolation: isolate;">
|
||||
<video src="video.mp4" muted playsinline
|
||||
data-start="0" data-duration="30" data-track-index="0" />
|
||||
|
||||
<div class="clip blend-difference"
|
||||
data-start="0" data-duration="5" data-track-index="1"
|
||||
style="position: absolute; inset: 0; z-index: 10;
|
||||
display: flex; align-items: center; justify-content: center;">
|
||||
<span style="font-size: 120px; font-weight: 800;">
|
||||
YOUR CAPTION
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
| Property | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `--blend-caption-color` | `white` | Base text color before blending |
|
||||
| `--blend-mode` | `difference` | Override blend mode on `.blend-difference` |
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
|
||||
@@ -9,7 +9,7 @@ Left-to-right clip-path wipe reveal per word
|
||||
|
||||
`captions` `caption-style` `wipe` `clip-path` `reveal`
|
||||
|
||||
<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/caption-clip-wipe-v2.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-clip-wipe.png" autoPlay muted loop playsInline />
|
||||
<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/caption-clip-wipe.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-clip-wipe.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ RGB chromatic aberration with CRT scanline overlay
|
||||
|
||||
`captions` `caption-style` `glitch` `cyber` `tech`
|
||||
|
||||
<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/caption-glitch-rgb-v2.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-glitch-rgb.png" autoPlay muted loop playsInline />
|
||||
<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/caption-glitch-rgb.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-glitch-rgb.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Gradient-clipped text with elastic bounce entrance
|
||||
|
||||
`captions` `caption-style` `gradient` `colorful`
|
||||
|
||||
<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/caption-gradient-fill-v3.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-gradient-fill.png" autoPlay muted loop playsInline />
|
||||
<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/caption-gradient-fill.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-gradient-fill.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Red background sweep behind each active word, TikTok-style
|
||||
|
||||
`captions` `caption-style` `highlight` `social` `tiktok`
|
||||
|
||||
<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/caption-highlight-v2.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-highlight.png" autoPlay muted loop playsInline />
|
||||
<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/caption-highlight.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-highlight.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Character scramble animation before text reveal
|
||||
|
||||
`captions` `caption-style` `matrix` `scramble` `decode`
|
||||
|
||||
<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/caption-matrix-decode-v2.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-matrix-decode.png" autoPlay muted loop playsInline />
|
||||
<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/caption-matrix-decode.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-matrix-decode.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
title: "Texture Lava"
|
||||
description: "Flowing lava texture mask over large uppercase text"
|
||||
---
|
||||
|
||||
# Texture Lava
|
||||
|
||||
Flowing lava texture mask over large uppercase text
|
||||
|
||||
`captions` `caption-style` `texture` `lava` `mask`
|
||||
|
||||
<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/caption-texture-lava.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-texture-lava.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add caption-texture-lava
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `caption-texture-lava.html` | `compositions/components/caption-texture-lava.html` | hyperframes:snippet |
|
||||
| `lava.png` | `compositions/components/lava.png` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/caption-texture-lava.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Texture"
|
||||
description: "Flowing texture mask over large uppercase text — ships with 6 textures (lava, marble, metal, wood, concrete, rock), configurable via the texture variable"
|
||||
---
|
||||
|
||||
# Texture
|
||||
|
||||
Flowing texture mask over large uppercase text — ships with 6 textures (lava, marble, metal, wood, concrete, rock), configurable via the texture variable
|
||||
|
||||
`captions` `caption-style` `texture` `mask`
|
||||
|
||||
<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/caption-texture.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-texture.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add caption-texture
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `caption-texture.html` | `compositions/components/caption-texture.html` | hyperframes:snippet |
|
||||
| `lava.png` | `compositions/components/lava.png` | hyperframes:asset |
|
||||
| `marble-012.png` | `compositions/components/marble-012.png` | hyperframes:asset |
|
||||
| `metal-046-b.png` | `compositions/components/metal-046-b.png` | hyperframes:asset |
|
||||
| `wood-066.png` | `compositions/components/wood-066.png` | hyperframes:asset |
|
||||
| `concrete-042-a.png` | `compositions/components/concrete-042-a.png` | hyperframes:asset |
|
||||
| `rock-058.png` | `compositions/components/rock-058.png` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/caption-texture.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
@@ -9,7 +9,7 @@ Elegant font-weight transition between caption lines
|
||||
|
||||
`captions` `caption-style` `minimal` `typography`
|
||||
|
||||
<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/caption-weight-shift-v2.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-weight-shift.png" autoPlay muted loop playsInline />
|
||||
<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/caption-weight-shift.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-weight-shift.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: "Parallax Unzoom"
|
||||
description: "Reveal transition — focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)"
|
||||
---
|
||||
|
||||
# Parallax Unzoom
|
||||
|
||||
Reveal transition — focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)
|
||||
|
||||
`transition` `reveal` `unzoom` `parallax` `grid` `hero`
|
||||
|
||||
<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 />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add parallax-unzoom
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `parallax-unzoom.html` | `compositions/components/parallax-unzoom.html` | hyperframes:snippet |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/parallax-unzoom.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: "Parallax Zoom"
|
||||
description: "Center card scales up to fill the frame while siblings parallax outward — inspired by the eBay Playbook hero transition"
|
||||
---
|
||||
|
||||
# Parallax Zoom
|
||||
|
||||
Center card scales up to fill the frame while siblings parallax outward — inspired by the eBay Playbook hero transition
|
||||
|
||||
`transition` `zoom` `parallax` `grid` `hero`
|
||||
|
||||
<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 />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add parallax-zoom
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `parallax-zoom.html` | `compositions/components/parallax-zoom.html` | hyperframes:snippet |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/parallax-zoom.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
+10
-13
@@ -122,7 +122,7 @@
|
||||
"catalog/components/caption-parallax-layers",
|
||||
"catalog/components/caption-particle-burst",
|
||||
"catalog/components/caption-pill-karaoke",
|
||||
"catalog/components/caption-texture-lava",
|
||||
"catalog/components/caption-texture",
|
||||
"catalog/components/caption-weight-shift"
|
||||
]
|
||||
},
|
||||
@@ -199,21 +199,16 @@
|
||||
"catalog/blocks/vpn-youtube-spot"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Maps",
|
||||
"pages": [
|
||||
"catalog/blocks/us-map",
|
||||
"catalog/blocks/us-map-bubble",
|
||||
"catalog/blocks/us-map-hex",
|
||||
"catalog/blocks/us-map-flow",
|
||||
"catalog/blocks/world-map",
|
||||
"catalog/blocks/spain-map"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Data",
|
||||
"pages": [
|
||||
"catalog/blocks/data-chart"
|
||||
"catalog/blocks/data-chart",
|
||||
"catalog/blocks/spain-map",
|
||||
"catalog/blocks/us-map",
|
||||
"catalog/blocks/us-map-bubble",
|
||||
"catalog/blocks/us-map-flow",
|
||||
"catalog/blocks/us-map-hex",
|
||||
"catalog/blocks/world-map"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -222,6 +217,8 @@
|
||||
"catalog/components/caption-blend-difference",
|
||||
"catalog/components/grain-overlay",
|
||||
"catalog/components/grid-pixelate-wipe",
|
||||
"catalog/components/parallax-unzoom",
|
||||
"catalog/components/parallax-zoom",
|
||||
"catalog/components/shimmer-sweep",
|
||||
"catalog/components/texture-mask-text",
|
||||
"catalog/components/vignette"
|
||||
|
||||
@@ -41,6 +41,21 @@
|
||||
"href": "/catalog/blocks/blue-sweater-intro-video",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/blue-sweater-intro-video.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-blend-difference",
|
||||
"type": "component",
|
||||
"title": "Blend Difference",
|
||||
"description": "Auto-inverting text using mix-blend-mode: difference — flips between white and black per-pixel against the background",
|
||||
"tags": [
|
||||
"text",
|
||||
"effect",
|
||||
"blend-mode",
|
||||
"contrast",
|
||||
"inversion"
|
||||
],
|
||||
"href": "/catalog/components/caption-blend-difference",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-blend-difference.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-clip-wipe",
|
||||
"type": "component",
|
||||
@@ -234,19 +249,18 @@
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-pill-karaoke.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-texture-lava",
|
||||
"name": "caption-texture",
|
||||
"type": "component",
|
||||
"title": "Texture Lava",
|
||||
"description": "Flowing lava texture mask over large uppercase text",
|
||||
"title": "Texture",
|
||||
"description": "Flowing texture mask over large uppercase text — ships with 6 textures (lava, marble, metal, wood, concrete, rock), configurable via the texture variable",
|
||||
"tags": [
|
||||
"captions",
|
||||
"caption-style",
|
||||
"texture",
|
||||
"lava",
|
||||
"mask"
|
||||
],
|
||||
"href": "/catalog/components/caption-texture-lava",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-texture-lava.png"
|
||||
"href": "/catalog/components/caption-texture",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-texture.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-weight-shift",
|
||||
@@ -481,6 +495,37 @@
|
||||
"href": "/catalog/blocks/nyc-paris-flight",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/nyc-paris-flight.png"
|
||||
},
|
||||
{
|
||||
"name": "parallax-unzoom",
|
||||
"type": "component",
|
||||
"title": "Parallax Unzoom",
|
||||
"description": "Reveal transition — focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)",
|
||||
"tags": [
|
||||
"transition",
|
||||
"reveal",
|
||||
"unzoom",
|
||||
"parallax",
|
||||
"grid",
|
||||
"hero"
|
||||
],
|
||||
"href": "/catalog/components/parallax-unzoom",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-unzoom.png"
|
||||
},
|
||||
{
|
||||
"name": "parallax-zoom",
|
||||
"type": "component",
|
||||
"title": "Parallax Zoom",
|
||||
"description": "Center card scales up to fill the frame while siblings parallax outward — inspired by the eBay Playbook hero transition",
|
||||
"tags": [
|
||||
"transition",
|
||||
"zoom",
|
||||
"parallax",
|
||||
"grid",
|
||||
"hero"
|
||||
],
|
||||
"href": "/catalog/components/parallax-zoom",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-zoom.png"
|
||||
},
|
||||
{
|
||||
"name": "reddit-post",
|
||||
"type": "block",
|
||||
|
||||
+325
@@ -0,0 +1,325 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1920, height=1080" />
|
||||
<title>Parallax Unzoom — Demo</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800;900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background: #1a1a20;
|
||||
font-family: "Inter", system-ui, sans-serif;
|
||||
}
|
||||
|
||||
.demo-canvas {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.parallax-unzoom-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 360px);
|
||||
grid-template-rows: repeat(3, 341px);
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.parallax-unzoom-card {
|
||||
border-radius: 22px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-shadow: 0 12px 36px rgba(20, 20, 30, 0.08);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-glyph {
|
||||
font-size: 92px;
|
||||
font-weight: 800;
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
|
||||
letter-spacing: -0.04em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pu-c0 {
|
||||
background: linear-gradient(135deg, #3a8b6f, #1d4d3d);
|
||||
}
|
||||
.pu-c1 {
|
||||
background: linear-gradient(135deg, #8b4a3a, #4a2418);
|
||||
}
|
||||
.pu-c2 {
|
||||
background: linear-gradient(135deg, #c89868, #8a6038);
|
||||
}
|
||||
.pu-c3 {
|
||||
background: linear-gradient(135deg, #3a6088, #1a2f4a);
|
||||
}
|
||||
.pu-c4 {
|
||||
background: linear-gradient(135deg, #b03838, #6a1818);
|
||||
}
|
||||
.pu-c5 {
|
||||
background: linear-gradient(135deg, #bcbcbc, #6e6e6e);
|
||||
}
|
||||
.pu-c6 {
|
||||
background: linear-gradient(135deg, #8a5fa0, #4a2860);
|
||||
}
|
||||
.pu-c7-focus {
|
||||
background: linear-gradient(135deg, #f5c93f, #d99a18);
|
||||
}
|
||||
.pu-c8 {
|
||||
background: linear-gradient(135deg, #d8d8d8, #9a9a9a);
|
||||
}
|
||||
.pu-c9 {
|
||||
background: linear-gradient(135deg, #5fa37e, #2a6a4a);
|
||||
}
|
||||
.pu-c10 {
|
||||
background: linear-gradient(135deg, #d1b66a, #8a7028);
|
||||
}
|
||||
.pu-c11 {
|
||||
background: linear-gradient(135deg, #4f7fc0, #1f3f80);
|
||||
}
|
||||
.pu-c12 {
|
||||
background: linear-gradient(135deg, #5a3a8f, #2a1858);
|
||||
}
|
||||
.pu-c13 {
|
||||
background: linear-gradient(135deg, #b85a3a, #6a2818);
|
||||
}
|
||||
.pu-c14 {
|
||||
background: linear-gradient(135deg, #f0f0e8, #c8c8be);
|
||||
}
|
||||
|
||||
.parallax-unzoom-card[data-pu-focus="true"] {
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.focus-label {
|
||||
font-weight: 900;
|
||||
font-size: 56px;
|
||||
letter-spacing: -0.04em;
|
||||
color: #1a1208;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.focus-label small {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.18em;
|
||||
margin-bottom: 14px;
|
||||
color: rgba(26, 18, 8, 0.7);
|
||||
}
|
||||
|
||||
.hero-headline {
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 68px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
color: #1a1a1a;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.parallax-unzoom-grid {
|
||||
--pu-progress: 0;
|
||||
--pu-focus-scale: 6;
|
||||
--pu-sibling-push: 900px;
|
||||
--pu-sibling-fade: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.parallax-unzoom-card {
|
||||
transform-origin: center center;
|
||||
will-change: transform, opacity;
|
||||
transform: translate3d(
|
||||
calc(var(--pu-dx, 0px) * (1 - var(--pu-progress))),
|
||||
calc(var(--pu-dy, 0px) * (1 - var(--pu-progress))),
|
||||
0
|
||||
)
|
||||
scale(calc(0.7 + 0.3 * var(--pu-progress)));
|
||||
opacity: calc(var(--pu-progress) * var(--pu-sibling-fade));
|
||||
}
|
||||
|
||||
.parallax-unzoom-card[data-pu-focus="true"] {
|
||||
z-index: 10;
|
||||
transform: translate3d(0, 0, 0)
|
||||
scale(calc(var(--pu-focus-scale) - (var(--pu-focus-scale) - 1) * var(--pu-progress)));
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="demo"
|
||||
data-composition-id="parallax-unzoom-demo"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
data-duration="6"
|
||||
data-start="0"
|
||||
>
|
||||
<div class="demo-canvas">
|
||||
<div class="hero-headline">Inspired by how people discover.</div>
|
||||
|
||||
<div class="parallax-unzoom-grid">
|
||||
<div class="parallax-unzoom-card pu-c0" data-pu-row="0" data-pu-col="0">
|
||||
<span class="card-glyph">◇</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c1" data-pu-row="0" data-pu-col="1">
|
||||
<span class="card-glyph">◐</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c2" data-pu-row="0" data-pu-col="2">
|
||||
<span class="card-glyph">◯</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c3" data-pu-row="0" data-pu-col="3">
|
||||
<span class="card-glyph">◑</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c4" data-pu-row="0" data-pu-col="4">
|
||||
<span class="card-glyph">▲</span>
|
||||
</div>
|
||||
|
||||
<div class="parallax-unzoom-card pu-c5" data-pu-row="1" data-pu-col="0">
|
||||
<span class="card-glyph">✦</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c6" data-pu-row="1" data-pu-col="1">
|
||||
<span class="card-glyph">❖</span>
|
||||
</div>
|
||||
<div
|
||||
class="parallax-unzoom-card pu-c7-focus"
|
||||
data-pu-row="1"
|
||||
data-pu-col="2"
|
||||
data-pu-focus="true"
|
||||
>
|
||||
<div class="focus-label">
|
||||
<small>EBAY PLAYBOOK</small>
|
||||
DISCOVER
|
||||
</div>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c8" data-pu-row="1" data-pu-col="3">
|
||||
<span class="card-glyph">✧</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c9" data-pu-row="1" data-pu-col="4">
|
||||
<span class="card-glyph">◈</span>
|
||||
</div>
|
||||
|
||||
<div class="parallax-unzoom-card pu-c10" data-pu-row="2" data-pu-col="0">
|
||||
<span class="card-glyph">▼</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c11" data-pu-row="2" data-pu-col="1">
|
||||
<span class="card-glyph">◆</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c12" data-pu-row="2" data-pu-col="2">
|
||||
<span class="card-glyph">●</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c13" data-pu-row="2" data-pu-col="3">
|
||||
<span class="card-glyph">◭</span>
|
||||
</div>
|
||||
<div class="parallax-unzoom-card pu-c14" data-pu-row="2" data-pu-col="4">
|
||||
<span class="card-glyph" style="color: rgba(40, 40, 40, 0.7)">◇</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const grids = document.querySelectorAll(".parallax-unzoom-grid");
|
||||
grids.forEach((grid) => {
|
||||
const cards = Array.from(grid.querySelectorAll(".parallax-unzoom-card"));
|
||||
if (cards.length === 0) return;
|
||||
let focal = cards.find((c) => c.dataset.puFocus === "true");
|
||||
if (!focal) {
|
||||
focal = cards[Math.floor(cards.length / 2)];
|
||||
focal.dataset.puFocus = "true";
|
||||
}
|
||||
const focusRow = Number(focal.dataset.puRow ?? 0);
|
||||
const focusCol = Number(focal.dataset.puCol ?? 0);
|
||||
const push =
|
||||
parseFloat(getComputedStyle(grid).getPropertyValue("--pu-sibling-push")) || 900;
|
||||
cards.forEach((card) => {
|
||||
if (card === focal) return;
|
||||
const row = Number(card.dataset.puRow ?? 0);
|
||||
const col = Number(card.dataset.puCol ?? 0);
|
||||
const dCol = col - focusCol;
|
||||
const dRow = row - focusRow;
|
||||
const mag = Math.hypot(dCol, dRow) || 1;
|
||||
const nx = (dCol / mag) * push * mag;
|
||||
const ny = (dRow / mag) * push * mag;
|
||||
card.style.setProperty("--pu-dx", `${nx}px`);
|
||||
card.style.setProperty("--pu-dy", `${ny}px`);
|
||||
});
|
||||
});
|
||||
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
tl.to(
|
||||
".hero-headline",
|
||||
{
|
||||
opacity: 0,
|
||||
duration: 0.5,
|
||||
ease: "power2.in",
|
||||
},
|
||||
0.3,
|
||||
);
|
||||
|
||||
tl.fromTo(
|
||||
".parallax-unzoom-grid",
|
||||
{ "--pu-progress": 0 },
|
||||
{
|
||||
"--pu-progress": 1,
|
||||
duration: 3.0,
|
||||
ease: "power2.inOut",
|
||||
},
|
||||
0.5,
|
||||
);
|
||||
|
||||
tl.fromTo(
|
||||
".parallax-unzoom-card:not([data-pu-focus='true'])",
|
||||
{ opacity: 0 },
|
||||
{
|
||||
opacity: 1,
|
||||
duration: 1.5,
|
||||
ease: "power2.out",
|
||||
stagger: { each: 0.02, from: "center" },
|
||||
},
|
||||
2.0,
|
||||
);
|
||||
|
||||
tl.to(
|
||||
".focus-label",
|
||||
{
|
||||
opacity: 1,
|
||||
duration: 1.0,
|
||||
ease: "power2.out",
|
||||
},
|
||||
2.5,
|
||||
);
|
||||
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["parallax-unzoom-demo"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,103 @@
|
||||
<!--
|
||||
Parallax Unzoom — focus card scales down from full frame while siblings
|
||||
parallax IN to form a grid. The reverse of parallax-zoom.
|
||||
|
||||
Pairs naturally with parallax-zoom: zoom INTO a card in scene 1, then
|
||||
unzoom OUT of it in scene 2 to reveal a fresh grid underneath.
|
||||
|
||||
Usage:
|
||||
1. Wrap your card grid with class="parallax-unzoom-grid".
|
||||
2. Mark each card with class="parallax-unzoom-card".
|
||||
3. Add data-pu-row="0|1|2|..." and data-pu-col="0|1|2|..." per card.
|
||||
4. Mark the card that starts at full size with data-pu-focus="true".
|
||||
5. Drive --pu-progress 0 → 1 on the .parallax-unzoom-grid from your
|
||||
composition's paused GSAP timeline (see example at bottom).
|
||||
|
||||
Tunable CSS variables on .parallax-unzoom-grid:
|
||||
- --pu-focus-scale (default 6) starting scale of the focus card
|
||||
- --pu-sibling-push (default 900px) outward distance siblings start at
|
||||
- --pu-sibling-fade (default 1) sibling opacity falloff (0–1)
|
||||
-->
|
||||
|
||||
<style>
|
||||
.parallax-unzoom-grid {
|
||||
--pu-progress: 0;
|
||||
--pu-focus-scale: 6;
|
||||
--pu-sibling-push: 900px;
|
||||
--pu-sibling-fade: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.parallax-unzoom-card {
|
||||
transform-origin: center center;
|
||||
will-change: transform, opacity;
|
||||
transform: translate3d(
|
||||
calc(var(--pu-dx, 0px) * (1 - var(--pu-progress))),
|
||||
calc(var(--pu-dy, 0px) * (1 - var(--pu-progress))),
|
||||
0
|
||||
)
|
||||
scale(calc(0.7 + 0.3 * var(--pu-progress)));
|
||||
opacity: calc(var(--pu-progress) * var(--pu-sibling-fade));
|
||||
}
|
||||
|
||||
.parallax-unzoom-card[data-pu-focus="true"] {
|
||||
z-index: 10;
|
||||
transform: translate3d(0, 0, 0)
|
||||
scale(calc(var(--pu-focus-scale) - (var(--pu-focus-scale) - 1) * var(--pu-progress)));
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const grids = document.querySelectorAll(".parallax-unzoom-grid");
|
||||
|
||||
grids.forEach((grid) => {
|
||||
const cards = Array.from(grid.querySelectorAll(".parallax-unzoom-card"));
|
||||
if (cards.length === 0) return;
|
||||
|
||||
let focal = cards.find((c) => c.dataset.puFocus === "true");
|
||||
if (!focal) {
|
||||
focal = cards[Math.floor(cards.length / 2)];
|
||||
focal.dataset.puFocus = "true";
|
||||
}
|
||||
|
||||
const focusRow = Number(focal.dataset.puRow ?? 0);
|
||||
const focusCol = Number(focal.dataset.puCol ?? 0);
|
||||
const push = parseFloat(getComputedStyle(grid).getPropertyValue("--pu-sibling-push")) || 900;
|
||||
|
||||
cards.forEach((card) => {
|
||||
if (card === focal) return;
|
||||
const row = Number(card.dataset.puRow ?? 0);
|
||||
const col = Number(card.dataset.puCol ?? 0);
|
||||
const dCol = col - focusCol;
|
||||
const dRow = row - focusRow;
|
||||
const mag = Math.hypot(dCol, dRow) || 1;
|
||||
const nx = (dCol / mag) * push * mag;
|
||||
const ny = (dRow / mag) * push * mag;
|
||||
card.style.setProperty("--pu-dx", `${nx}px`);
|
||||
card.style.setProperty("--pu-dy", `${ny}px`);
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!--
|
||||
Timeline integration example (paste into your composition's GSAP timeline):
|
||||
|
||||
tl.fromTo(
|
||||
".parallax-unzoom-grid",
|
||||
{ "--pu-progress": 0 },
|
||||
{
|
||||
"--pu-progress": 1,
|
||||
duration: 2.4,
|
||||
ease: "power2.inOut",
|
||||
},
|
||||
startTime, // start time in seconds
|
||||
);
|
||||
|
||||
Chaining with parallax-zoom example:
|
||||
// Scene 1 (0-3s): zoom IN to the focal card via parallax-zoom
|
||||
// Scene 2 (3-6s): unzoom OUT of a NEW grid via parallax-unzoom,
|
||||
// with the focal card pre-positioned to match scene 1
|
||||
-->
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
|
||||
"name": "parallax-unzoom",
|
||||
"type": "hyperframes:component",
|
||||
"title": "Parallax Unzoom",
|
||||
"description": "Reveal transition — focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)",
|
||||
"tags": ["transition", "reveal", "unzoom", "parallax", "grid", "hero"],
|
||||
"files": [
|
||||
{
|
||||
"path": "parallax-unzoom.html",
|
||||
"target": "compositions/components/parallax-unzoom.html",
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": {
|
||||
"poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-unzoom.png"
|
||||
}
|
||||
}
|
||||
+342
@@ -0,0 +1,342 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1920, height=1080" />
|
||||
<title>Parallax Zoom — Demo</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800;900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background: #1a1a20;
|
||||
font-family: "Inter", system-ui, sans-serif;
|
||||
}
|
||||
|
||||
.demo-canvas {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.parallax-zoom-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 360px);
|
||||
grid-template-rows: repeat(3, 341px);
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.parallax-zoom-card {
|
||||
border-radius: 22px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-shadow: 0 12px 36px rgba(20, 20, 30, 0.08);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.card-glyph {
|
||||
font-size: 92px;
|
||||
font-weight: 800;
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
|
||||
letter-spacing: -0.04em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pz-c0 {
|
||||
background: linear-gradient(135deg, #3a8b6f, #1d4d3d);
|
||||
}
|
||||
.pz-c1 {
|
||||
background: linear-gradient(135deg, #8b4a3a, #4a2418);
|
||||
}
|
||||
.pz-c2 {
|
||||
background: linear-gradient(135deg, #c89868, #8a6038);
|
||||
}
|
||||
.pz-c3 {
|
||||
background: linear-gradient(135deg, #3a6088, #1a2f4a);
|
||||
}
|
||||
.pz-c4 {
|
||||
background: linear-gradient(135deg, #b03838, #6a1818);
|
||||
}
|
||||
.pz-c5 {
|
||||
background: linear-gradient(135deg, #bcbcbc, #6e6e6e);
|
||||
}
|
||||
.pz-c6 {
|
||||
background: linear-gradient(135deg, #8a5fa0, #4a2860);
|
||||
}
|
||||
.pz-c7-focus {
|
||||
background: linear-gradient(135deg, #f5c93f, #d99a18);
|
||||
}
|
||||
.pz-c8 {
|
||||
background: linear-gradient(135deg, #d8d8d8, #9a9a9a);
|
||||
}
|
||||
.pz-c9 {
|
||||
background: linear-gradient(135deg, #5fa37e, #2a6a4a);
|
||||
}
|
||||
.pz-c10 {
|
||||
background: linear-gradient(135deg, #d1b66a, #8a7028);
|
||||
}
|
||||
.pz-c11 {
|
||||
background: linear-gradient(135deg, #4f7fc0, #1f3f80);
|
||||
}
|
||||
.pz-c12 {
|
||||
background: linear-gradient(135deg, #5a3a8f, #2a1858);
|
||||
}
|
||||
.pz-c13 {
|
||||
background: linear-gradient(135deg, #b85a3a, #6a2818);
|
||||
}
|
||||
.pz-c14 {
|
||||
background: linear-gradient(135deg, #f0f0e8, #c8c8be);
|
||||
}
|
||||
|
||||
.parallax-zoom-card[data-pz-focus="true"] {
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.focus-label {
|
||||
font-weight: 900;
|
||||
font-size: 56px;
|
||||
letter-spacing: -0.04em;
|
||||
color: #1a1208;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.focus-label small {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.18em;
|
||||
margin-bottom: 14px;
|
||||
color: rgba(26, 18, 8, 0.7);
|
||||
}
|
||||
|
||||
.zoom-backdrop {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(135deg, #f5c93f, #d99a18);
|
||||
opacity: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.hero-headline {
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 68px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
color: #1a1a1a;
|
||||
opacity: 0;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.parallax-zoom-grid {
|
||||
--pz-progress: 0;
|
||||
--pz-focus-scale: 6;
|
||||
--pz-sibling-push: 900px;
|
||||
--pz-sibling-fade: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.parallax-zoom-card {
|
||||
transform-origin: center center;
|
||||
will-change: transform, opacity;
|
||||
transform: translate3d(
|
||||
calc(var(--pz-dx, 0px) * var(--pz-progress)),
|
||||
calc(var(--pz-dy, 0px) * var(--pz-progress)),
|
||||
0
|
||||
)
|
||||
scale(calc(1 - var(--pz-progress) * 0.4));
|
||||
}
|
||||
|
||||
.parallax-zoom-card[data-pz-focus="true"] {
|
||||
z-index: 10;
|
||||
transform: translate3d(0, 0, 0)
|
||||
scale(calc(1 + var(--pz-progress) * (var(--pz-focus-scale) - 1)));
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="demo"
|
||||
data-composition-id="parallax-zoom-demo"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
data-duration="6"
|
||||
data-start="0"
|
||||
>
|
||||
<div class="demo-canvas">
|
||||
<div class="zoom-backdrop"></div>
|
||||
<div class="hero-headline">Inspired by how people discover.</div>
|
||||
|
||||
<div class="parallax-zoom-grid">
|
||||
<div class="parallax-zoom-card pz-c0" data-pz-row="0" data-pz-col="0">
|
||||
<span class="card-glyph">◇</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c1" data-pz-row="0" data-pz-col="1">
|
||||
<span class="card-glyph">◐</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c2" data-pz-row="0" data-pz-col="2">
|
||||
<span class="card-glyph">◯</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c3" data-pz-row="0" data-pz-col="3">
|
||||
<span class="card-glyph">◑</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c4" data-pz-row="0" data-pz-col="4">
|
||||
<span class="card-glyph">▲</span>
|
||||
</div>
|
||||
|
||||
<div class="parallax-zoom-card pz-c5" data-pz-row="1" data-pz-col="0">
|
||||
<span class="card-glyph">✦</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c6" data-pz-row="1" data-pz-col="1">
|
||||
<span class="card-glyph">❖</span>
|
||||
</div>
|
||||
<div
|
||||
class="parallax-zoom-card pz-c7-focus"
|
||||
data-pz-row="1"
|
||||
data-pz-col="2"
|
||||
data-pz-focus="true"
|
||||
>
|
||||
<div class="focus-label">
|
||||
<small>EBAY PLAYBOOK</small>
|
||||
DISCOVER
|
||||
</div>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c8" data-pz-row="1" data-pz-col="3">
|
||||
<span class="card-glyph">✧</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c9" data-pz-row="1" data-pz-col="4">
|
||||
<span class="card-glyph">◈</span>
|
||||
</div>
|
||||
|
||||
<div class="parallax-zoom-card pz-c10" data-pz-row="2" data-pz-col="0">
|
||||
<span class="card-glyph">▼</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c11" data-pz-row="2" data-pz-col="1">
|
||||
<span class="card-glyph">◆</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c12" data-pz-row="2" data-pz-col="2">
|
||||
<span class="card-glyph">●</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c13" data-pz-row="2" data-pz-col="3">
|
||||
<span class="card-glyph">◭</span>
|
||||
</div>
|
||||
<div class="parallax-zoom-card pz-c14" data-pz-row="2" data-pz-col="4">
|
||||
<span class="card-glyph" style="color: rgba(40, 40, 40, 0.7)">◇</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const grids = document.querySelectorAll(".parallax-zoom-grid");
|
||||
grids.forEach((grid) => {
|
||||
const cards = Array.from(grid.querySelectorAll(".parallax-zoom-card"));
|
||||
if (cards.length === 0) return;
|
||||
let focal = cards.find((c) => c.dataset.pzFocus === "true");
|
||||
if (!focal) {
|
||||
focal = cards[Math.floor(cards.length / 2)];
|
||||
focal.dataset.pzFocus = "true";
|
||||
}
|
||||
const focusRow = Number(focal.dataset.pzRow ?? 0);
|
||||
const focusCol = Number(focal.dataset.pzCol ?? 0);
|
||||
const push =
|
||||
parseFloat(getComputedStyle(grid).getPropertyValue("--pz-sibling-push")) || 900;
|
||||
cards.forEach((card) => {
|
||||
if (card === focal) return;
|
||||
const row = Number(card.dataset.pzRow ?? 0);
|
||||
const col = Number(card.dataset.pzCol ?? 0);
|
||||
const dCol = col - focusCol;
|
||||
const dRow = row - focusRow;
|
||||
const mag = Math.hypot(dCol, dRow) || 1;
|
||||
const nx = (dCol / mag) * push * mag;
|
||||
const ny = (dRow / mag) * push * mag;
|
||||
card.style.setProperty("--pz-dx", `${nx}px`);
|
||||
card.style.setProperty("--pz-dy", `${ny}px`);
|
||||
});
|
||||
});
|
||||
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
tl.to(
|
||||
".parallax-zoom-card",
|
||||
{
|
||||
opacity: 1,
|
||||
duration: 0.5,
|
||||
ease: "power2.out",
|
||||
stagger: { each: 0.03, from: "center" },
|
||||
},
|
||||
0,
|
||||
);
|
||||
|
||||
tl.fromTo(
|
||||
".parallax-zoom-grid",
|
||||
{ "--pz-progress": 0 },
|
||||
{
|
||||
"--pz-progress": 1,
|
||||
duration: 3.0,
|
||||
ease: "power2.inOut",
|
||||
},
|
||||
1.7,
|
||||
);
|
||||
|
||||
tl.to(
|
||||
".parallax-zoom-card:not([data-pz-focus='true'])",
|
||||
{
|
||||
opacity: 0,
|
||||
duration: 1.0,
|
||||
ease: "power2.in",
|
||||
},
|
||||
3.5,
|
||||
);
|
||||
|
||||
tl.to(
|
||||
".focus-label",
|
||||
{
|
||||
opacity: 0,
|
||||
duration: 1.0,
|
||||
ease: "power2.in",
|
||||
},
|
||||
2.5,
|
||||
);
|
||||
|
||||
tl.to(
|
||||
".hero-headline",
|
||||
{
|
||||
opacity: 1,
|
||||
duration: 0.7,
|
||||
ease: "power2.out",
|
||||
},
|
||||
4.2,
|
||||
);
|
||||
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["parallax-zoom-demo"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,99 @@
|
||||
<!--
|
||||
Parallax Zoom — center card scales up while siblings parallax outward.
|
||||
|
||||
Inspired by the eBay Playbook hero transition: a grid of cards collapses
|
||||
as the focal card grows to fill the frame.
|
||||
|
||||
Usage:
|
||||
1. Wrap your card grid with class="parallax-zoom-grid".
|
||||
2. Mark each card with class="parallax-zoom-card".
|
||||
3. Add data-pz-row="0|1|2|..." and data-pz-col="0|1|2|..." per card
|
||||
so the snippet knows each card's grid offset.
|
||||
4. Mark the focal card with data-pz-focus="true" — this is the one
|
||||
that scales up to fill the frame.
|
||||
5. Drive --pz-progress 0 → 1 on the .parallax-zoom-grid from your
|
||||
composition's paused GSAP timeline (see example at bottom).
|
||||
|
||||
Tunable CSS variables on .parallax-zoom-grid:
|
||||
- --pz-focus-scale (default 6) maximum scale of the focused card
|
||||
- --pz-sibling-push (default 900px) outward translation strength
|
||||
- --pz-sibling-fade (default 1) sibling opacity falloff (0–1)
|
||||
-->
|
||||
|
||||
<style>
|
||||
.parallax-zoom-grid {
|
||||
--pz-progress: 0;
|
||||
--pz-focus-scale: 6;
|
||||
--pz-sibling-push: 900px;
|
||||
--pz-sibling-fade: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.parallax-zoom-card {
|
||||
transform-origin: center center;
|
||||
will-change: transform, opacity;
|
||||
transform: translate3d(
|
||||
calc(var(--pz-dx, 0px) * var(--pz-progress)),
|
||||
calc(var(--pz-dy, 0px) * var(--pz-progress)),
|
||||
0
|
||||
)
|
||||
scale(calc(1 - var(--pz-progress) * 0.4));
|
||||
opacity: calc(1 - var(--pz-progress) * var(--pz-sibling-fade));
|
||||
}
|
||||
|
||||
.parallax-zoom-card[data-pz-focus="true"] {
|
||||
z-index: 10;
|
||||
transform: translate3d(0, 0, 0)
|
||||
scale(calc(1 + var(--pz-progress) * (var(--pz-focus-scale) - 1)));
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const grids = document.querySelectorAll(".parallax-zoom-grid");
|
||||
|
||||
grids.forEach((grid) => {
|
||||
const cards = Array.from(grid.querySelectorAll(".parallax-zoom-card"));
|
||||
if (cards.length === 0) return;
|
||||
|
||||
let focal = cards.find((c) => c.dataset.pzFocus === "true");
|
||||
if (!focal) {
|
||||
focal = cards[Math.floor(cards.length / 2)];
|
||||
focal.dataset.pzFocus = "true";
|
||||
}
|
||||
|
||||
const focusRow = Number(focal.dataset.pzRow ?? 0);
|
||||
const focusCol = Number(focal.dataset.pzCol ?? 0);
|
||||
const push = parseFloat(getComputedStyle(grid).getPropertyValue("--pz-sibling-push")) || 900;
|
||||
|
||||
cards.forEach((card) => {
|
||||
if (card === focal) return;
|
||||
const row = Number(card.dataset.pzRow ?? 0);
|
||||
const col = Number(card.dataset.pzCol ?? 0);
|
||||
const dCol = col - focusCol;
|
||||
const dRow = row - focusRow;
|
||||
const mag = Math.hypot(dCol, dRow) || 1;
|
||||
const nx = (dCol / mag) * push * mag;
|
||||
const ny = (dRow / mag) * push * mag;
|
||||
card.style.setProperty("--pz-dx", `${nx}px`);
|
||||
card.style.setProperty("--pz-dy", `${ny}px`);
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!--
|
||||
Timeline integration example (paste into your composition's GSAP timeline):
|
||||
|
||||
tl.fromTo(
|
||||
".parallax-zoom-grid",
|
||||
{ "--pz-progress": 0 },
|
||||
{
|
||||
"--pz-progress": 1,
|
||||
duration: 2.4,
|
||||
ease: "power2.inOut",
|
||||
},
|
||||
1.0, // start time in seconds
|
||||
);
|
||||
-->
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
|
||||
"name": "parallax-zoom",
|
||||
"type": "hyperframes:component",
|
||||
"title": "Parallax Zoom",
|
||||
"description": "Center card scales up to fill the frame while siblings parallax outward — inspired by the eBay Playbook hero transition",
|
||||
"tags": ["transition", "zoom", "parallax", "grid", "hero"],
|
||||
"files": [
|
||||
{
|
||||
"path": "parallax-zoom.html",
|
||||
"target": "compositions/components/parallax-zoom.html",
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": {
|
||||
"poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/parallax-zoom.png"
|
||||
}
|
||||
}
|
||||
@@ -346,6 +346,14 @@
|
||||
{
|
||||
"name": "vfx-shatter",
|
||||
"type": "hyperframes:block"
|
||||
},
|
||||
{
|
||||
"name": "parallax-zoom",
|
||||
"type": "hyperframes:component"
|
||||
},
|
||||
{
|
||||
"name": "parallax-unzoom",
|
||||
"type": "hyperframes:component"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user