I wanted to build a cursor reveal that felt less mechanical than a simple circle mask.
Something softer, more alive, and a little unpredictable.
So I built mouse-reveal-organique: an open-source React component that reveals an image through an evolving liquid mask.
What it does
Move the pointer over a container to reveal a second image through an organic shape.
The reveal leaves a trail, changes over time, and can be configured to feel subtle or expressive.
It can be used for:
- Creative landing page heroes
- Portfolio project cards
- Editorial layouts
- Product cards
- Interactive visual storytelling
Installation
npm install mouse-reveal-organique
Basic usage
import BoxMouseOrganique from "mouse-reveal-organique";
export default function Hero() {
return (
<BoxMouseOrganique
img_cover="/images/cover.jpg"
img_background="/images/reveal.jpg"
size_mouse={1}
>
<h1>Your content, your CSS</h1>
</BoxMouseOrganique>
);
}
The component works like a regular React container.
You can place headings, buttons, links, grids, and other interactive content inside it. The content remains usable above the canvas effect.
The main options are:
-
size_mouse: controls the size of the reveal. -
trail_duration: controls how long the trail remains visible. -
organic: controls how irregular the reveal boundary becomes.
Each instance runs independently, so several reveals can coexist on the same page with different settings.
What I wanted to get right
The visual effect was only part of the work.
I also wanted the component to be practical for real React projects:
- React 18/19 and TypeScript support
- Compatible with Next.js App Router
- No animation dependency
- Interactive content remains clickable
- Reduced-motion support
- Touch devices gracefully display the cover image
- Animation pauses offscreen and in hidden tabs
- Canvas resolution is capped to avoid unnecessary rendering cost
Try it
The live demo includes several layouts: a large hero, a portfolio card, an editorial card, and a product card.
I would love to know where you would use an interaction like this, or what examples would make the package more useful.

Top comments (0)