logo

Aki UI

アキ ウイ

Mouse Effect Card

マウスエフェクトカード

A field of dots that parts around the cursor. Each dot subscribes to the same pair of motion values holding the pointer position and derives its own offset from them, so the whole field updates outside React — no state changes, no re-render per frame. Within the repulsion radius the offset is the unit vector away from the pointer scaled by how close it is, and a spring on each axis gives the dots weight on the way out and on the way back. Opacity is driven from the same distance over a slightly wider radius, which is what makes the cursor look like it is carrying a light. Dots thin out towards the edges on a probability that falls with distance from the centre, so the field fades into the card rather than stopping at a rectangle; that randomness is why generation happens in an effect and never during server render. Arrow keys walk a virtual pointer in fifths of the card, so the effect is reachable without a mouse. Adapted from Kokonut UI under the MIT licence.

Case study

Acme

Move the cursor across the field, or focus the card and use the arrow keys.

Installation

Copy and paste the following code into a new component file:1

"use client"

/**
* Adapted for Aki UI from Kokonut UI's Mouse Effect Card.
* Original author: @dorianbaffier — https://kokonutui.com
* Copyright (c) 2025 kokonutUI, MIT License.
* https://github.com/kokonut-labs/kokonutui
*
* Reworked here onto the local palette, with shadcn primitives and
* class-variance-authority removed and motion/react swapped for framer-motion.

How to use it2

"use client"

import { MouseEffectCard } from "@/components/ui/mouse-effect-card"

export default function Page() {
return (
<MouseEffectCard>
<h2 className="text-lg font-medium">Acme</h2>
<p className="text-sm text-[#888888]">Move the cursor across the field.</p>
</MouseEffectCard>

Props

MouseEffectCard

NameDefaultDescription
children

ReactNode

Centred content, laid over the field and not clickable

width400

number

Card width in pixels; the field is generated to fit

height340

number

Card height in pixels

dotSize2

number

Diameter of one dot in pixels

spacing18

number

Grid pitch before thinning — lower means many more dots

radius80

number

Pixels within which a dot is pushed away

strength20

number

Pixels a dot moves at the centre of the pointer

darkfalse

boolean

Render the dark palette