Animations have a significant affect on the impression a web site offers. On this article, we introduce 4 transition results that easily swap full-screen pictures.
Utilizing GSAP, ScrollTrigger, and SVG masks, we’ll implement scroll-synchronized animations with grid and blind-style constructions. Moderately than merely altering pictures, the aim is to offer intention to the scene transitions themselves, creating transitions that convey the location’s data and environment extra naturally.
Frequent markup construction (HTML)
Lets have a look at the inspiration utilized in all 4 demos.
Part transition
Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content
Part transition
Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content
Part transition
Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content Textual content
Responsive SVG canvas
Set viewBox="0 0 100 100" on .layer (the SVG component) and handle inside coordinates utilizing digital items (0–100). This permits the masks calculation logic to stay constant even when the display screen dimension adjustments.
Defining the SVG Masks
Outline a singular for every layer.
Base (black): Place a rectangle with fill="#000000" to set the preliminary state to “utterly hidden.”
Dynamic components (white): Put together an empty the place white rectangles generated by JavaScript can be inserted. Solely the areas the place this “white” overlaps change into seen.
The picture component as content material
That is the primary component that will get masked. It’s linked to the masks above utilizing the masks="url(#masks*)" attribute.
preserveAspectRatio="xMidYMid slice": Recreates conduct just like CSS object-fit: cowl inside SVG, stopping picture distortion whereas masking all the display screen.
Textual content and progress bar
Parts that visually complement the animation’s state and environment.
Core Logic (Shared JavaScript)
Easy interplay (Lenis)
Converts commonplace scrolling into movement with inertia. When mixed with scrub, it creates a easy, responsive really feel because the masks follows the scroll.
Dynamic structure calculation (updateLayout)
The width is dynamically calculated (vbWidth) based mostly on the display screen top (100). On resize, the present timeline is kill()ed and rebuilt, guaranteeing the pictures proceed to cowl the total display screen with out distortion whatever the display screen ratio.
Excessive-precision synchronization (ScrollTrigger)
The general progress is synchronized with scrub: 2.0–2.5. Even after scrolling stops, the animation continues barely, including a delicate and nice trailing movement.
Hole prevention (Anti-aliasing)
Along with utilizing shape-rendering="crispEdges", small overlaps (about +0.01 to +0.1) are added relying on every impact’s calculation logic. This visually eliminates the tiny 1px gaps that may seem between segmented rectangles.
Animation Variations
This part explains the core of every demo: the JavaScript logic used to generate and animate the rectangles.
1. Horizontal Blinds
An impact the place horizontal strains broaden vertically, steadily filling the display screen.
1. Coordinate Calculation Logic (Placement)
Contained in the createBlinds operate, the display screen top (vbHeight) is evenly divided by BLIND_COUNT (30 strains), and the middle line (centerY) the place every line needs to be positioned is calculated.
const h = vbHeight / BLIND_COUNT; // Remaining top of a single blind slit
// ...inside loop...
// Calculate the middle Y coordinate for every slit.
// Subtracting from vbHeight flips the order, stacking them from backside to high.
const centerY = vbHeight - (currentY + h / 2);
The important thing level right here is that the strains are not merely positioned from high to backside. As a substitute, by subtracting from vbHeight, a reversed stacking calculation is carried out in order that the strains accumulate from the underside upward. This course of causes the blinds to be positioned ranging from the underside of the display screen and shifting towards the highest.
Moreover, for every slit, two rectangles—rectTop and rectBottom—are positioned on the very same centerY, overlapping one another. Since their preliminary top is 0, nothing is seen at first.
2. Animation Mechanism
When the openBlinds operate runs, the 2 overlapping rectangles start shifting in reverse vertical instructions.
y: (i) => {
const b = blinds[Math.floor(i / 2)];
// Even index strikes as much as reveal, odd index stays on the middle line
return i % 2 === 0 ? b.y - b.h : b.y;
},
top: (i) => {
const b = blinds[Math.floor(i / 2)];
// Develop top to full dimension with a tiny offset (0.01) to get rid of gaps
return b.h + 0.01;
}
rectTop (when i is even): whereas extending its top, its y coordinate strikes upward by half of its personal top (b.h).
rectBottom (when i is odd): its y coordinate stays unchanged whereas its top extends downward from the middle.
This contrasting movement—one shifting upward whereas the opposite expands in place—creates the visible impact of opening each upward and downward from the middle line.
3. The “0.01” that eliminates gaps
The b.h + 0.01 within the code performs an essential function.
In SVG rendering, even when shapes are mathematically positioned precisely subsequent to one another, browser calculations involving subpixels can generally produce tiny gaps of lower than 1px. By deliberately rising the scale by 0.01 so adjoining parts overlap barely, the fill stays seamless at any decision.
4. Staggered timing for visible impact
stagger: { every: 0.02, from: "begin" }
Not all the strains open on the similar time. As a substitute, they react with a 0.02-second offset.
The essential level right here is that the animation targets are ordered like this:[top1, bottom1, top2, bottom2, ...]
Consequently, the highest and backside pair of the identical slit transfer nearly concurrently, then the animation proceeds to the subsequent slit in sequence. In different phrases, the blinds open one after the other from the underside upward.
This delicate time offset creates a rhythmic, steady flap-flap-flap… unfolding movement rising from the underside of the display screen, including a lovely sense of response to the scroll interplay.
2. Random Grid
The display screen is split right into a grid the place panels open at totally different timings, making a digital but natural visible impact.
1. Coordinate Calculation Logic (Placement)
Contained in the createBlinds operate, the variety of columns (cols) is decided for every gadget based mostly on the display screen width, and the variety of rows (rows) is then robotically calculated to match the display screen’s facet ratio.
// ------------------
// Grid configuration
// ------------------
const cols = getGridCols(); // 14 (PC) / 10 (Pill) / 6 (SP)
const rows = GRID_ROWS || Math.spherical(cols * (vbHeight / vbWidth));
// ------------------
// Cell dimensions
// ------------------
const cellW = vbWidth / cols;
const cellH = vbHeight / rows;
The important thing level right here is that the rows are not calculated merely from the display screen ratio alone. As a substitute, the calculation makes use of the variety of columns (cols) because the reference in order that the cell sizes stay as whilst doable each vertically and horizontally.
The method cols * (vbHeight / vbWidth) adjusts the vertical division depend by multiplying the horizontal division density by the display screen’s facet ratio. This retains the grid balanced in each instructions.
Consequently, even when the variety of columns adjustments relying on the gadget, the cells don’t change into excessively tall or broad, and their proportions keep near sq..
Utilizing a double for loop, rectangles with the calculated cellW (width) and cellH (top) are laid out like tiles. Within the preliminary state, opacity: 0 is utilized, so all the pieces begins utterly hidden.
2. Animation Mechanism
Within the openBlinds operate, random movement is utilized to all generated rectangles (cells) utilizing GSAP utilities.
operate openBlinds(cells) {
// Shuffle cells to create a random reveal impact
const shuffled = gsap.utils.shuffle([...cells]);
return gsap.timeline()
.to(shuffled, {
opacity: 1,
period: 1,
ease: "power3.out",
stagger: {
every: 0.02
}
});
}
After shuffling the panel order utilizing gsap.utils.shuffle, the opacity is returned to 1 with a 0.02-second stagger. This creates a visually attention-grabbing impact the place the grid itself stays orderly, however the best way it seems is irregular.
3. Machine Optimization (Responsive)
On this impact, the grid density adjustments dynamically relying on the display screen dimension.
PC: 14 columns
Cell: 6 columns
When the display screen is resized, updateLayout runs and redraws the grid utilizing the optimum variety of cells based mostly on the newest display screen dimension. This ensures the supposed stage of immersion is maintained on any gadget.
4. Consideration to Visible High quality
As with Horizontal Blinds, shape-rendering="crispEdges" is specified.
This suppresses edge blurring brought on by anti-aliasing and forces the panel edges to render nearer to pixel boundaries.
Consequently, the boundaries between adjoining cells seem sharper, giving all the grid a cleaner and extra strong impression.
As a result of SVG rendering typically entails scaling, subpixel calculations can generally trigger slight blurring alongside edges. By specifying crispEdges, this visible “softness” is minimized, stopping small gaps the place the background colour would possibly in any other case seem between cells.
3. Vertical Blinds
An impact the place vertical strips broaden horizontally, filling the display screen backward and forward. It creates a well-recognized but refined transition, just like curtains or blinds opening and shutting.
1. Coordinate Calculation Logic (Placement)
Contained in the createBlinds operate, the display screen width (vbWidth) is evenly divided by BLIND_COUNT (12 strains) to calculate the width of every strip (w). Two rectangles (rectLeft, rectRight) are then positioned overlapping one another on the middle line (centerX) of every strip.
const w = vbWidth / BLIND_COUNT; // Remaining width of every vertical slit
// ...inside loop...
// Calculate the middle X coordinate for every slit to broaden from.
const centerX = currentX + w / 2;
Because the preliminary width is ready to 0, nothing is seen contained in the masks at first. Whereas the horizontal blinds divide and management the top, this model divides and controls the width.
Preliminary layer
On this model, isFirstLayer is used as a result of the primary picture is meant to be seen from the start. Within the different patterns, the animation begins from the primary picture as properly, however on this model solely the primary layer is proven initially to help instances the place the visible must be established earlier than scrolling begins. This isn’t a structural requirement, however a alternative made for expressive functions.
2. Animation Mechanism
With the openBlinds operate, the 2 rectangles that overlap on the middle broaden their width whereas sliding outward to the left and proper.
x: (i) => Odd index: stays on the middle line
return i % 2 === 0 ? b.x - b.w : b.x;
,
width: (i) => {
const b = blinds[Math.floor(i / 2)];
// Develop width to full dimension with a 0.05 offset to stop hairline gaps
return b.w + 0.05;
}
Why Math.ground(i / 2) is used
In GSAP’s attr animation, the array is handed within the following order:[b0.left, b0.right, b1.left, b1.right, ...]
This implies each two parts symbolize one set (one blind). By dividing the index i by 2 and rounding down, the code can appropriately decide which blind (0th, 1st, and many others.) the present rect belongs to.
Growth logic
An SVG rect usually grows to the precise from its top-left origin.
rectLeft (even index): By shifting the x coordinate to b.x - b.w (to the left) whereas increasing its width, it visually seems to increase towards the left.
rectRight (odd index): The x coordinate stays mounted on the middle (b.x) whereas the width expands, naturally extending to the precise.
By combining this motion and scaling, the animation creates a movement the place a wiper-like form expands outward from the middle line to either side.
3. Hole prevention and structure robustness
By including a small worth in width: b.w + 0.05, every strip barely overlaps with its neighbors. This prevents 1px gaps brought on by subpixel calculations.
Impact of crispEdges
r.setAttribute("shape-rendering", "crispEdges"); suppresses anti-aliasing and prevents edge blurring. For designs dominated by straight strains—like blinds—this setting produces extraordinarily sharp edges and reduces visible noise.
4. Facet-ratio dealing with logic
In updateLayout, vbWidth is recalculated dynamically in keeping with the display screen ratio.
Top reference: vbHeight is mounted at 100
Width calculation: (width / top) * 100
This calculates the relative width when the peak is normalized to 100. With this technique, the 12 strips stay evenly divided whatever the window ratio, guaranteeing the display screen is at all times utterly crammed in a responsive structure.
5. Continuity by means of stagger
stagger: { every: 0.02, from: "begin" } is utilized.
As a result of pairs (left, proper) are organized consecutively within the array, a slight timing offset happens between every pair. Consequently, every strip seems to open sequentially from the left aspect towards the precise.
As scrolling progresses, the picture is revealed easily from left to proper, creating a nice visible rhythm.
4. Column Random Grid
Probably the most intricate and dynamic impact, combining directionality and randomness inside a grid construction. It delivers a richly layered visible expertise, the place a wave-like movement sweeps from left to proper whereas irregular panel openings interweave all through.
1. Coordinate Calculation Logic (Placement)
The bottom grid technology is similar as in 02. Random Grid, however the construction is designed in order that it might exactly observe which column every cell belongs to for animation management.
// ------------------
// Grid configuration
// ------------------
const cols = getGridCols(); // Adaptive columns: 14 (PC) / 10 (Pill) / 6 (SP)
// Calculate rows based mostly on facet ratio to maintain cells as sq. as doable
const rows = GRID_ROWS || Math.spherical(cols * (vbHeight / vbWidth));
// ------------------
// Cell dimensions
// ------------------
const cellW = vbWidth / cols;
const cellH = vbHeight / rows;
// Generate all cells through nested loops and retailer in a flat array (row-major order)
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
// Rectangle technology logic...
}
}
Intent behind the row calculation (aspect-ratio preservation logic)
const rows = GRID_ROWS || Math.spherical(cols * (vbHeight / vbWidth));
This expression does greater than merely calculate the variety of rows robotically. By sustaining the connection cols : rows ≒ vbWidth : vbHeight, it prevents every cell from turning into excessively tall or broad. In different phrases, this logic makes use of the variety of columns as a reference, multiplies it by the viewBox facet ratio, and generates cells which are as near sq. as doable. It is a essential design level for preserving each grid density and visible stability in responsive environments.
Concerning the array construction (row-major flat array)
As a result of the cells are generated within the order for (let y...) { for (let x...) {, the cells array turns into a flat construction organized row by row (row-major order).
[ row0-col0, row0-col1, ... row0-colN, row1-col0, row1-col1, ... ]
The later column-extraction logic is constructed on high of this construction.
2. Animation Mechanism (Column-based management)
The core of this impact lies within the reconstruction of the array contained in the openBlinds operate. Moderately than making use of randomness throughout all the grid, it reorders the weather whereas treating every column as a definite group.
operate openBlinds({ cells, rows, cols }) {
const ordered = [];
// Reconstruct the flat array into columns
for (let x = 0; x < cols; x++) {
const column = [];
for (let y = 0; y < rows; y++) {
// Extract cell index from the unique row-major array
const index = y * cols + x;
column.push(cells[index]);
}
// Randomize the order of cells WITHIN the particular column
const shuffledColumn = gsap.utils.shuffle(column);
// Push the randomized column again into the ultimate ordered sequence
ordered.push(...shuffledColumn);
}
// 'ordered' is now: [Column 0 (random), Column 1 (random), ...]
}
The ultimate ordered array finally ends up with the next construction: “column 0 randomized group, column 1 randomized group, column 2 randomized group, …” As a result of GSAP’s stagger is utilized on this array order, it creates a two-layered conduct:
Macro view (total): progresses like a wave from left to proper, following the column order
Micro view (element): inside every column, panels seem in a vertically randomized order
This management makes it doable to create a posh, natural rhythm through which the animation strikes from left to proper as a complete, whereas the panels inside every column seem unpredictably from high to backside.
3. Sturdy hole prevention
As within the different demos, shape-rendering="crispEdges" can also be used right here. In a grid impact the place many rectangles are drawn quickly and irregularly, stopping 1px gaps brought on by anti-aliasing is crucial for sustaining the clear visible high quality of the design.
Wrapping up
The mix of SVG masks and GSAP (ScrollTrigger) elevates scene transitions on a web site from a easy operate right into a compelling type of visible path that attracts customers in.
Utilizing the code created right here as a basis, attempt customizing the variety of divisions, the order of look, and the easing to create your personal unique transition results.









