April 9, 2026IntermediatePage Transitions
Shutter Section
Scroll-driven venetian-blind effect using GSAP ScrollTrigger. Horizontal rows animate their scaleY to reveal or cover a full-viewport media section as the user scrolls. Supports image and video, two modes (reveal / cover), and responsive row counts.
Preview

Source
import ShutterSection from "./index.jsx";
import styles from "./demo.module.css";
export default function ShutterSectionDemo() {
return (
<div className={styles.demo}>
{/* ── Intro ─────────────────────────────────────────────────── */}
<section className={styles.intro}>
<p className={styles.label}>Shutter Section</p>
<h1 className={styles.heading}>
Scroll-driven<br />venetian blind
</h1>
<p className={styles.body}>
Scroll down to see both modes — the section is first revealed,
then covered, as you move through the page.
</p>
</section>
{/* ── Mode: reveal ──────────────────────────────────────────── */}
{/* Shutter starts closed (scaleY 1), dissolves open as section enters */}
<ShutterSection
mediaSrc="/demo-assets/card-sample-1.jpg"
mediaAlt="Shutter reveal demo"
mode="reveal"
shutterColor="var(--color-bg)"
rows={16}
rowsTablet={10}
rowsMobile={6}
>
<div className={styles.sectionContent}>
<p className={styles.sectionLabel}>mode: reveal</p>
<h2 className={styles.sectionHeading}>Revealed on scroll</h2>
</div>
</ShutterSection>
{/* ── Bridge ────────────────────────────────────────────────── */}
<section className={styles.bridge}>
<p className={styles.bridgeLabel}>mode: cover</p>
<p className={styles.bridgeBody}>
The next section closes its shutter as it scrolls out of view.
</p>
</section>
{/* ── Mode: cover ───────────────────────────────────────────── */}
{/* Shutter starts open (scaleY 0), seals shut as section exits */}
<ShutterSection
mediaSrc="/demo-assets/card-sample-2.jpg"
mediaAlt="Shutter cover demo"
mode="cover"
shutterColor="var(--color-bg)"
rows={16}
rowsTablet={10}
rowsMobile={6}
>
<div className={styles.sectionContent}>
<p className={styles.sectionLabel}>mode: cover</p>
<h2 className={styles.sectionHeading}>Covered on scroll</h2>
</div>
</ShutterSection>
{/* ── Outro ─────────────────────────────────────────────────── */}
<section className={styles.outro}>
<p className={styles.outroText}>End of demo</p>
</section>
</div>
);
}
Dependencies
gsap