Genie Effect
ProA macOS genie minimize built on a real per-slice warp that sucks any window, folder, or panel down into a waiting dock.
Overview
Genie Effect is a React and Tailwind CSS macOS genie minimize animation, in Next.js or any React app, built on Framer Motion. Content is cloned into horizontal slices that each travel to the target on their own delayed timeline, so the window stretches into a neck and pours into the dock instead of scaling. Set open to minimize or restore, aim it with originX and originY, and trade smoothness for DOM nodes with slices. Minimized content is inert and leaves the tab order, and reduced motion swaps states directly. Keep children presentational, since effects and refs run once per slice.
Installation
Run the following command
pnpm dlx wensity@latest add genie-effect
Usage
Import GenieEffect from @/components/wensity/genie-effect and render it anywhere in your React or Next.js app. The source lands in your own repo, so every prop, class and animation below is yours to edit.
"use client";import { useState } from "react";import { GenieEffect } from "@/components/wensity/genie-effect";export default function Example() {const [open, setOpen] = useState(true);return (// The stage needs a height — the genie travels to its bottom edge.<div className="relative"><GenieEffect open={open} originX="center" className="h-[280px]"><Window onMinimize={() => setOpen(false)} /></GenieEffect><button type="button" onClick={() => setOpen(true)}>Restore</button></div>);}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | - | false sucks the content into the origin point; true restores it. |
originX | "left" | "center" | "right" | number | "center" | Horizontal target — a keyword or a 0-1 fraction of the stage width. Values outside 0-1 are allowed, so the target may sit off-stage. |
originY | "top" | "center" | "bottom" | number | "bottom" | Vertical target — a keyword or a 0-1 fraction of the stage height. Set it when the target is not a dock along the bottom edge. |
duration | number | 0.72 | Animation duration in seconds. |
slices | number | 48 | Slice count. More slices means a smoother curve and more DOM nodes. |
onAnimationComplete | (open: boolean) => void | - | Fires once the minimize or restore animation settles. |
