Atelier UI®

Read the docsGithub
Docs 0.7.0

Getting started

  • Browse Catalog
  • Installation
  • How to contribute
  • Code of conduct

Collage (01)

  • Fluid Scene

Components (27)

  • Clip Reveal
  • Stripe Wipe
  • Sweep Exit
  • Dither Flow
    pro
  • Glowing Fog
    pro
  • Halftone Glow
    pro
  • Fluid Distortion
  • Image Trail
  • Lens Image
  • Liquid Image
  • Magnetic Dot Grid
  • Pixel Image
  • Pixel Trail
  • Pixelated Text
  • Text Bounce
  • Text Fluid
  • Text Roll
  • Text Scramble
  • Curve Image
  • Elastic Stick
    pro
  • Infinite Gallery
  • Infinite Parallax
  • Infinite Zoom
  • Scattered Scroll
  • Text Split
  • WebGL Image
  • WebGL Text
Atelier UI 0.7.0 ©2026
Star on githubBuy me a coffeellms.txt
  1. Docs
  2. /
  3. Components
  4. /
  5. Sweep Exit

Sweep Exit

A staggered clip-path sweep that reveals the page beneath an overlay.

Motion
Tailwind CSS
https://atelier-ui.com/sweep-exit

Settings

duration
1.0
inset-x
20
inset-y
10
See the documentation below for more options.

Install

npx atelier-ui add sweep-exit
npm install motion
sweep-exit.tsx
"use client"

import type { Easing } from "motion"
import { stagger, useAnimate } from "motion/react"
import { type ReactNode, useEffect, useRef } from "react"

export type SweepExitProps = {
    children?: ReactNode
    backgroundSlot: ReactNode
    duration?: number
    ease?: Easing
    insetX?: number
    insetY?: number
    trigger?: boolean
    onComplete?: () => void
}

export function SweepExit({
    children,
    backgroundSlot,
    duration = 1,
    ease = [0.85, 0, 0.2, 1],
    insetX = 20,
    insetY = 10,
    trigger = true,
    onComplete,
}: SweepExitProps) {
    const [scope, animate] = useAnimate()
    const configRef = useRef({ duration, ease, onComplete })
    configRef.current = { duration, ease, onComplete }

    useEffect(() => {
        if (!trigger) return

        let cancelled = false
        let controls: ReturnType<typeof animate> | undefined

        async function run() {
            const { duration, ease } = configRef.current
            controls = animate([
                [
                    ".aui-clip, .aui-clip > :not(.aui-clip-bg)",
                    {
                        clipPath: [
                            "inset(0% 0% 0% 0%)",
                            `inset(${insetY}% ${insetX}% ${insetY}% ${insetX}%)`,
                        ],
                    },
                    { duration: 1.3 * duration, ease },
                ],
                [
                    ".aui-clip",
                    {
                        scale: [1, 0.9],
                    },
                    { duration: 1.3 * duration, ease, at: 0 },
                ],
                [
                    ".aui-bg-overlay",
                    {
                        scale: [2, 1],
                    },
                    { duration: 1.8 * duration, ease, at: 0 },
                ],
                [
                    ".aui-clip, .aui-clip > :not(.aui-clip-bg)",
                    { clipPath: `inset(${insetY}% ${insetX}% ${100 - insetY}% ${insetX}%)` },
                    {
                        duration: 1 * duration,
                        ease,
                        at: 1.3 * duration,
                        delay: stagger(0.05 * duration, { from: "last" }),
                    },
                ],
                [
                    ".aui-bg-overlay",
                    {
                        clipPath: `inset(0% 0% 100% 0%)`,
                    },
                    { duration: 3 * duration, ease, at: 0 },
                ],
            ])

            await controls

            if (!cancelled) {
                configRef.current.onComplete?.()
            }
        }

        run()

        return () => {
            cancelled = true
            controls?.stop()
        }
    }, [trigger, animate, insetY, insetX])

    return (
        <div ref={scope}>
            <div className="aui-bg-overlay fixed inset-0 z-50 w-screen h-screen overflow-hidden">
                {backgroundSlot}
            </div>
            <div className="aui-clip fixed inset-0 z-[60] overflow-hidden origin-center">
                <div className="aui-clip-bg absolute inset-0 -z-10">{backgroundSlot}</div>
                {children}
            </div>
        </div>
    )
}

API

NameTypeDefaultDescription
childrenReactNode—Content rendered on top of the overlay layer.
backgroundSlotReactNode—Content rendered in the background overlay. Required.
durationnumber1Time-scale multiplier applied to every sub-step.
easeEasing[0.85, 0, 0.2, 1]Motion easing: bezier array, named string, or easing function.
insetXnumber20Horizontal inset at peak contraction in percent.
insetYnumber10Vertical inset at peak contraction in percent.
triggerbooleantrueStarts the animation when set to true.
onComplete() => void—Called when the animation finishes.

Credits

Zajno
Page transition that inspired this effect.

Motion
React animation library.

  • Install
  • API
  • Credits
Star on githubBuy me a coffeellms.txt