
This is a modern design concept that transforms webpage content into full-screen views where users are able to navigate between them using smooth, fluid SVG transitions powered by GSAP.
It is ideal for presentations, side decks, or dynamic page sliders built directly from your content.
How to use it:
1. Structure your HTML: Divide your content into separate “views” within a main wrapper. Each view represents a full-screen section. Include navigation buttons within each view to trigger the transitions.
<div class="wrapper">
<main>
<div class="view view--1">
<div>
<h1>View 1</h1>
<p>This is view 1</p>
<button class="unbutton button button--open" aria-label="Open other view">Next Page</button>
</div>
</div>
<div class="view view--2">
<h1>View 2</h1>
<p>This is view 2</p>
<button class="unbutton button button--close" aria-label="Close current view">Previous Page</button>
</div>
<svg class="overlay" width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
<path class="overlay__path" vector-effect="non-scaling-stroke" d="M 0 0 h 0 c 0 50 0 50 0 100 H 0 V 0 Z" />
</svg>
</main>
</div>2. Apply these CSS styles to position the views and set up the transitions:
html,
body {
margin: 0;
padding: 0;
--color-text: #000;
--color-bg-view-1: #9da0dd;
--color-bg-view-2: #6a6468;
--color-link: #000;
--color-link-hover: #000;
--color-button: #000;
--color-button-hover: #22267d;
color: var(--color-text);
background-color: var(--color-bg-view-1);
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
font-weight: 500;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
height: 100vh;
}
.unbutton {
background: none;
border: 0;
padding: 0;
margin: 0;
font: inherit;
cursor: pointer;
}
.unbutton:focus {
outline: none;
}
main {
display: grid;
grid-template-columns: 100%;
grid-template-rows: 100vh;
}
@media (max-width: 576px) {
main {
grid-auto-rows: min-content;
grid-template-rows: auto;
}
}
.button {
color: var(--color-button);
border-radius: 30px;
min-width: 150px;
padding: 1rem 2rem;
border: 1px solid currentColor;
}
.button:hover,
.button:focus-visible {
color: var(--color-button-hover);
}
.frame--view-open .button-open {
opacity: 0;
pointer-events: none;
}
.view {
position: relative;
grid-area: 1/1/2/2;
display: grid;
place-items: center;
}
.view--1 {
display: flex;
justify-content: space-around;
}
.view--1 p {
text-align: left;
margin-bottom: 30px;
}
.view--2 {
background: var(--color-bg-view-2);
pointer-events: none;
opacity: 0;
}
.view.view--open {
pointer-events: auto;
opacity: 1;
}
.overlay {
grid-area: 1/1/2/2;
position: relative;
z-index: 1000;
pointer-events: none;
width: 100%;
height: 100%;
}3. Load the needed GSAP JavaScript library via a CDN:
<script src='https://unpkg.com/gsap@3/dist/gsap.min.js'></script>
4. Implement the JavaScript: The JavaScript code orchestrates the transition. It defines the SVG path transformations for each step of the animation, controls the timing and easing, and manages the visibility of the views.
const overlayPath = document.querySelector('.overlay__path');
const paths = {
step1: {
unfilled: 'M 0 0 h 0 c 0 50 0 50 0 100 H 0 V 0 Z',
inBetween: 'M 0 0 h 43 c -60 55 140 65 0 100 H 0 V 0 Z',
filled: 'M 0 0 h 100 c 0 50 0 50 0 100 H 0 V 0 Z',
},
step2: {
filled: 'M 100 0 H 0 c 0 50 0 50 0 100 h 100 V 50 Z',
inBetween: 'M 100 0 H 50 c 28 43 4 81 0 100 h 50 V 0 Z',
unfilled: 'M 100 0 H 100 c 0 50 0 50 0 100 h 0 V 0 Z',
}
};
const landingEl = document.querySelector('.view--2');
const switchCtrl = document.querySelector('button.button--open');
const backCtrl = landingEl.querySelector('.button--close');
let isAnimating = false;
let page = 1;
const pageSwitchTimeline = gsap.timeline({
paused: true,
onComplete: () => isAnimating = false
})
.set(overlayPath, {
attr: {
d: paths.step1.unfilled
}
})
.to(overlayPath, {
duration: 0.8,
ease: 'power3.in',
attr: {
d: paths.step1.inBetween
}
}, 0)
.to(overlayPath, {
duration: 0.2,
ease: 'power1',
attr: {
d: paths.step1.filled
},
onComplete: () => switchPages()
})
.set(overlayPath, {
attr: {
d: paths.step2.filled
}
})
.to(overlayPath, {
duration: 0.15,
ease: 'sine.in',
attr: {
d: paths.step2.inBetween
}
})
.to(overlayPath, {
duration: 1,
ease: 'power4',
attr: {
d: paths.step2.unfilled
}
});
const switchPages = () => {
if (page === 2) {
landingEl.classList.add('view--open');
} else {
landingEl.classList.remove('view--open');
}
}
const reveal = () => {
if (isAnimating) return;
isAnimating = true;
page = 2;
pageSwitchTimeline.play(0);
}
const unreveal = () => {
if (isAnimating) return;
isAnimating = true;
page = 1;
pageSwitchTimeline.play(0);
}
switchCtrl.addEventListener('click', reveal);
backCtrl.addEventListener('click', unreveal);






