creepy-button
vengenceui/creepy-buttonFreeComponent
vengenceui publishes no description for this item.
Live preview
live · rendered by the registry
Rendered by vengenceui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://www.vengenceui.com/r/creepy-button.jsonSource
1"use client";23import React, { useRef, useState } from "react";4import { motion } from "framer-motion";5import { cn } from "@/lib/utils";67interface CreepyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {8 children: React.ReactNode;9 /**10 * Optional custom class for the button container11 */12 className?: string;13 /**14 * Optional custom class for the button cover (the visible part)15 */16 coverClassName?: string;17}1819type Coords = {20 x: number;21 y: number;22};2324export const CreepyButton = ({25 children,26 className,27 coverClassName,28 onClick,29 ...props30}: CreepyButtonProps) => {31 const eyesRef = useRef<HTMLSpanElement>(null);32 const [eyeCoords, setEyeCoords] = useState<Coords>({ x: 0, y: 0 });33 const [isHovered, setIsHovered] = useState(false);3435 const updateEyes = (e: React.MouseEvent | React.TouchEvent) => {36 const userEvent =37 "touches" in e ? (e as React.TouchEvent).touches[0] : (e as React.MouseEvent);3839 if (!eyesRef.current) return;4041 // get the center of the eyes container42 const eyesRect = eyesRef.current.getBoundingClientRect();43 const eyesCenter = {44 x: eyesRect.left + eyesRect.width / 2,45 y: eyesRect.top + eyesRect.height / 2,46 };4748 // cursor position49 const cursor = {50 x: userEvent.clientX,51 y: userEvent.clientY,52 };5354 // calculate the eye angle55 const dx = cursor.x - eyesCenter.x;56 const dy = cursor.y - eyesCenter.y;57 const angle = Math.atan2(-dy, dx) + Math.PI / 2;5859 // pupil distance from the eye center60 const visionRangeX = 180; // Max distance to look horizontally61 const visionRangeY = 75; // Max distance to look vertically62 const distance = Math.hypot(dx, dy);6364 // Limit the movement so pupils don't go too far65 // We normalize the distance influence66 const x = (Math.sin(angle) * Math.min(distance, visionRangeX)) / visionRangeX;67 const y = (Math.cos(angle) * Math.min(distance, visionRangeY)) / visionRangeY;6869 setEyeCoords({ x, y });70 };7172 // Reset eyes when mouse leaves73 const resetEyes = () => {74 setEyeCoords({ x: 0, y: 0 });75 setIsHovered(false);76 };7778 const pupilStyle = {79 transform: `translate(calc(-50% + ${eyeCoords.x * 50}%), calc(-50% + ${eyeCoords.y * 50}%))`,80 };8182 return (83 <button84// … truncated
What it pulls in
npm packages
Files it writes
More from vengenceui
All 128 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| accordionaccordion | vengenceui | Components | Free | 2 deps | |
| agent-bento-gridagent-bento-grid | vengenceui | Components | Free | 1 dep | |
| alertalert | vengenceui | Components | Free | no deps | |
| animated-buttonanimated-button | vengenceui | Components | Free | 1 dep | |
| animated-footeranimated-footer | vengenceui | Components | Free | 2 deps | |
| animated-numberanimated-number | vengenceui | Components | Free | 1 dep | |
| animated-raysanimated-rays | vengenceui | Components | Free | no deps | |
| animated-tooltipanimated-tooltip | vengenceui | Components | Free | 1 dep |
