Components
Loading preview...
A custom React hook that tracks mouse/touch movement and calculates motion vectors. Provides both position coordinates and movement vectors relative to a container or the window.
@danielpetho
npx shadcn@latest add https://21st.dev/r/danielpetho/use-mouse-vector'use client'
import { useRef } from "react"
import { motion } from "framer-motion"
import { useMouseVector } from "@/components/hooks/use-mouse-vector"
function MouseVectorDemo() {
const containerRef = useRef<HTMLDivElement>(null)
const { position, vector } = useMouseVector(containerRef)
// Calculate vector magnitude and angle
const magnitude = Math.sqrt(vector.dx * vector.dx + vector.dy * vector.dy)
const angle = (Math.atan2(vector.dy, vector.dx) * 180) / Math.PI
// Scale the magnitude for visualization
const scaledMagnitude = Math.min(magnitude * 2, 100)
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 p-8 max-w-4xl mx-auto">
{/* Interactive Area */}
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-lg font-medium">Mouse Vector Visualization</h3>
<p className="text-sm text-muted-foreground">
Move your cursor inside the box to see the vector
</p>
</div>
<div
ref={containerRef}
className="relative aspect-square w-full border rounded-lg bg-muted/30 overflow-hidden"
>
{/* Current Position Indicator */}
<motion.div
className="absolute w-4 h-4 bg-blue-500 rounded-full"
style={{
left: position.x - 8,
top: position.y - 8,
}}
/>
{/* Vector Line */}
<svg
className="absolute inset-0 w-full h-full pointer-events-none"
style={{ overflow: 'visible' }}
>
<motion.line
x1={position.x}
y1={position.y}
x2={position.x + vector.dx * 5}
y2={position.y + vector.dy * 5}
stroke="#3b82f6"
strokeWidth="2"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
/>
</svg>
</div>
</div>
{/* Real-time Data Display */}
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-lg font-medium">Vector Data</h3>
<p className="text-sm text-muted-foreground">
Real-time mouse movement metrics
</p>
</div>
<div className="space-y-4 p-6 border rounded-lg bg-muted/30">
<div className="grid grid-cols-2 gap-4">
<div>
<div className="text-sm font-medium mb-1">Position</div>
<div className="font-mono text-sm">
x: {Math.round(position.x)}<br />
y: {Math.round(position.y)}
</div>
</div>
<div>
<div className="text-sm font-medium mb-1">Vector</div>
<div className="font-mono text-sm">
dx: {vector.dx.toFixed(2)}<br />
dy: {vector.dy.toFixed(2)}
</div>
</div>
<div>
<div className="text-sm font-medium mb-1">Magnitude</div>
<div className="font-mono text-sm">
{magnitude.toFixed(2)}
</div>
</div>
<div>
<div className="text-sm font-medium mb-1">Angle</div>
<div className="font-mono text-sm">
{angle.toFixed(2)}°
</div>
</div>
</div>
{/* Magnitude Visualizer */}
<div className="mt-4">
<div className="text-sm font-medium mb-2">Velocity</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">
<motion.div
className="h-full bg-blue-500"
animate={{ width: `${scaledMagnitude}%` }}
transition={{ type: "spring", bounce: 0 }}
/>
</div>
</div>
</div>
</div>
{/* Documentation */}
<div className="md:col-span-2">
<div className="space-y-4 p-6 border rounded-lg">
<h3 className="text-lg font-medium">About useMouseVector</h3>
<div className="space-y-4">
<pre className="bg-muted p-4 rounded-md text-xs overflow-x-auto">
{`const { position, vector } = useMouseVector(containerRef)
// position: { x: number, y: number }
// vector: { dx: number, dy: number }`}
</pre>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<div>
<h4 className="font-medium mb-2">Features</h4>
<ul className="list-disc list-inside space-y-1 text-muted-foreground">
<li>Mouse position tracking</li>
<li>Movement vector calculation</li>
<li>Container-relative coordinates</li>
<li>Touch support</li>
</ul>
</div>
<div>
<h4 className="font-medium mb-2">Use Cases</h4>
<ul className="list-disc list-inside space-y-1 text-muted-foreground">
<li>Particle effects</li>
<li>Cursor trails</li>
<li>Interactive animations</li>
<li>Gesture detection</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export { MouseVectorDemo }