Atelier UI®

DocsCatalogShader StudioPricingGithub
Docs 1.0.0

tools

  • Browse Catalog
  • Shader Studio
    pro
  • Collage
    new

Documentation

  • Installation
  • How to contribute

Components (38)

  • Orbit Gallery
  • Sphere Gallery
  • Glowing Fog
  • Gradient Flow
  • Halftone Glow
  • Scattered Grid
  • Tag Cloud
  • Edge Bounce
  • Fluid Distortion
  • Image Trail
  • Lens Media
  • Liquid Media
  • Magnetic Dot Grid
  • Pixel Media
  • Pixel Trail
  • Curve Media
  • Infinite Gallery
  • Infinite Parallax
  • Infinite Zoom
  • Pixel Scroll
  • Scattered Scroll
  • Elastic Stick
  • Wavy Scroll
  • Pixelated Text
  • Text Bounce
  • Text Fluid
  • Text Scramble
  • Text Roll
  • Clip Reveal
  • Stripe Wipe
  • Sweep Exit
  • Smooth Scroll
  • Text Split
  • WebGL Image
  • WebGL Provider
  • WebGL Scene
  • WebGL Text
  • WebGL Video
Atelier UI 1.0.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"

const EASE: Easing = [0.85, 0, 0.2, 1]

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

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

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

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

        async function run() {
            const { duration } = 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: EASE },
                ],
                [
                    ".aui-clip",
                    {
                        scale: [1, 0.9],
                    },
                    { duration: 1.3 * duration, ease: EASE, at: 0 },
                ],
                [
                    ".aui-bg-overlay",
                    {
                        scale: [2, 1],
                    },
                    { duration: 1.8 * duration, ease: EASE, at: 0 },
                ],
                [
                    ".aui-clip, .aui-clip > :not(.aui-clip-bg)",
                    { clipPath: `inset(${insetY}% ${insetX}% ${100 - insetY}% ${insetX}%)` },
                    {
                        duration: 1 * duration,
                        ease: 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: 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>
    )
}
prompt.md
## Integrate the <SweepExit /> component from Atelier UI

You are helping integrate an open-source React component into an existing application.

### Component: SweepExit
### Description: A staggered clip-path sweep that reveals the page beneath an overlay.
### Dependencies: motion

---

### Usage Example

`backgroundSlot` is required: it holds the overlay shown before the sweep reveals the children beneath.

```tsx
<SweepExit
  backgroundSlot={
    <img src="/overlay.jpg" alt="" className="absolute inset-0 h-full w-full object-cover" />
  }
>
  <YourPage />
</SweepExit>
```

---

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | — | Content rendered on top of the overlay layer. |
| `backgroundSlot` | `ReactNode` | — | Content rendered in the background overlay. Required. |
| `duration` | `number` | `1` | Time-scale multiplier applied to every sub-step. |
| `insetX` | `number` | `20` | Horizontal inset at peak contraction in percent. |
| `insetY` | `number` | `10` | Vertical inset at peak contraction in percent. |
| `trigger` | `boolean` | `true` | Starts the animation when set to true. |
| `onComplete` | `() => void` | — | Called when the animation finishes. |

---

### Full Component Source

#### src/components/sweep-exit/sweep-exit.tsx

```tsx
"use client"

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

const EASE: Easing = [0.85, 0, 0.2, 1]

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

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

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

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

        async function run() {
            const { duration } = 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: EASE },
                ],
                [
                    ".aui-clip",
                    {
                        scale: [1, 0.9],
                    },
                    { duration: 1.3 * duration, ease: EASE, at: 0 },
                ],
                [
                    ".aui-bg-overlay",
                    {
                        scale: [2, 1],
                    },
                    { duration: 1.8 * duration, ease: EASE, at: 0 },
                ],
                [
                    ".aui-clip, .aui-clip > :not(.aui-clip-bg)",
                    { clipPath: `inset(${insetY}% ${insetX}% ${100 - insetY}% ${insetX}%)` },
                    {
                        duration: 1 * duration,
                        ease: 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: 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>
    )
}
```

---

### Integration Instructions

1. If you can execute shell commands, run `npx atelier-ui add sweep-exit` from the project root instead of steps 2-3 (it installs everything automatically).
2. Install the npm dependencies: motion.
3. Copy each file from the component source above to the exact path shown.
4. Render `<SweepExit />` where it belongs in the app, using the usage example as a starting point and the props table to adjust it.

Full documentation: https://atelier-ui.com/en/docs/components/transition/sweep-exit

Usage

backgroundSlot is required: it holds the overlay shown before the sweep reveals the children beneath.

<SweepExit
  backgroundSlot={
    <img src="/overlay.jpg" alt="" className="absolute inset-0 h-full w-full object-cover" />
  }
>
  <YourPage />
</SweepExit>

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.
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
  • Usage
  • API
  • Credits
Star on githubBuy me a coffeellms.txt