{"id":20252363,"url":"https://github.com/alexjedi/magnetic-wrapper","last_synced_at":"2025-09-25T12:21:57.529Z","repository":{"id":242890889,"uuid":"810835294","full_name":"alexjedi/magnetic-wrapper","owner":"alexjedi","description":"Magnetic Effect component, wrapper for code project and override for Framer","archived":false,"fork":false,"pushed_at":"2024-07-16T16:56:55.000Z","size":341,"stargazers_count":27,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-12T07:34:33.399Z","etag":null,"topics":["animation","button","effects","framer","framer-motion","magnetic"],"latest_commit_sha":null,"homepage":"https://magnetic-wrapper.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexjedi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-06-05T12:47:00.000Z","updated_at":"2024-09-01T07:19:22.000Z","dependencies_parsed_at":"2025-04-10T23:16:34.591Z","dependency_job_id":"225e7dc2-8a69-470b-a78e-35d8108fbc94","html_url":"https://github.com/alexjedi/magnetic-wrapper","commit_stats":null,"previous_names":["alexjedi/magnetic-wrapper"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/alexjedi/magnetic-wrapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexjedi%2Fmagnetic-wrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexjedi%2Fmagnetic-wrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexjedi%2Fmagnetic-wrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexjedi%2Fmagnetic-wrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexjedi","download_url":"https://codeload.github.com/alexjedi/magnetic-wrapper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexjedi%2Fmagnetic-wrapper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276916277,"owners_count":25727737,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-25T02:00:09.612Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","button","effects","framer","framer-motion","magnetic"],"created_at":"2024-11-14T10:16:23.751Z","updated_at":"2025-09-25T12:21:57.486Z","avatar_url":"https://github.com/alexjedi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Magnetic Wrapper\n\n## Overview\n\nThe **Magnetic Wrapper** project provides a reusable React component and a Framer code override that adds a magnetic hover effect to your elements. This document will guide you through using the Magnetic Wrapper in your code repository and within the Framer website editor.\n\n## Getting Started\n\n### Prerequisites\n\nBefore you start, make sure you have the following tools installed:\n\n- Node.js\n- npm or yarn\n- Framer account (for Framer usage)\n- framer-motion (for code usage)\n\n### Usage in a Code Repository\n\n#### MagneticWrapper Component\n\n1. Copy the `MagneticWrapper` component code:\n\n   ```jsx\n   'use client'\n\n   import { useState, useEffect, useRef, ReactNode } from 'react'\n   import { motion, useMotionValue, useSpring } from 'framer-motion'\n\n   const SPRING_CONFIG = { damping: 30, stiffness: 150, mass: 0.2 }\n   const MAX_DISTANCE = 0.3\n   const MAX_SCALE = 1.1\n\n   interface MagneticWrapperProps {\n     children: ReactNode;\n   }\n\n   const MagneticWrapper: React.FC\u003cMagneticWrapperProps\u003e = ({ children }) =\u003e {\n     const [isHovered, setIsHovered] = useState(false)\n     const x = useMotionValue(0)\n     const y = useMotionValue(0)\n     const scale = useMotionValue(1)\n     const ref = useRef \u003c HTMLDivElement \u003e null\n     const springX = useSpring(x, SPRING_CONFIG)\n     const springY = useSpring(y, SPRING_CONFIG)\n     const springScale = useSpring(scale, { damping: 20, stiffness: 300 })\n\n     useEffect(() =\u003e {\n       const calculateDistance = (e: MouseEvent) =\u003e {\n         if (ref.current) {\n           const rect = ref.current.getBoundingClientRect()\n           const centerX = rect.left + rect.width / 2\n           const centerY = rect.top + rect.height / 2\n           const distanceX = (e.clientX - centerX) * MAX_DISTANCE\n           const distanceY = (e.clientY - centerY) * MAX_DISTANCE\n\n           if (isHovered) {\n             x.set(distanceX)\n             y.set(distanceY)\n             scale.set(MAX_SCALE)\n           } else {\n             x.set(0)\n             y.set(0)\n             scale.set(1)\n           }\n         }\n       }\n\n       const handleMouseMove = (e: MouseEvent) =\u003e {\n         requestAnimationFrame(() =\u003e calculateDistance(e))\n       }\n\n       document.addEventListener('mousemove', handleMouseMove)\n       return () =\u003e {\n         document.removeEventListener('mousemove', handleMouseMove)\n       }\n     }, [isHovered, x, y, scale])\n\n     return (\n       \u003cmotion.div\n         ref={ref}\n         onMouseEnter={() =\u003e setIsHovered(true)}\n         onMouseLeave={() =\u003e setIsHovered(false)}\n         style={{\n           position: 'relative',\n           x: springX,\n           y: springY,\n           scale: springScale,\n         }}\n       \u003e\n         {children}\n       \u003c/motion.div\u003e\n     )\n   }\n\n   export default MagneticWrapper\n   ```\n\n2. Use Magic Wapper in your app:\n\n   ```jsx\n   import React from 'react'\n   import MagneticWrapper from './MagneticWrapper'\n\n   const CustomLink = ({ href, children }) =\u003e {\n     return (\n       \u003cMagneticWrapper\u003e\n         \u003ca\n           href={href}\n           target=\"_blank\"\n           className=\"p-4 rounded-full flex items-center justify-center bg-background text-accent-foreground hover:bg-accent hover:text-accent-foreground transition-colors\"\n         \u003e\n           {children}\n         \u003c/a\u003e\n       \u003c/MagneticWrapper\u003e\n     )\n   }\n\n   export default CustomLink\n   ```\n\n### Usage in Framer Website Editor\n\n1. Copy the `MagneticWrapper` code override:\n\n   ```jsx\n   import { useState, useEffect, useRef, ComponentType } from 'react'\n   import { motion, useMotionValue, useSpring } from 'framer-motion'\n\n   const SPRING_CONFIG = { damping: 30, stiffness: 150, mass: 0.2 }\n   const MAX_DISTANCE = 0.3\n   const MAX_SCALE = 1.1\n\n   export const MagneticWrapper = (Component): ComponentType =\u003e {\n     return (props) =\u003e {\n       const [isHovered, setIsHovered] = useState(false)\n       const x = useMotionValue(0)\n       const y = useMotionValue(0)\n       const scale = useMotionValue(1)\n       const ref = useRef \u003cHTMLDivElement\u003e(null)\n       const springX = useSpring(x, SPRING_CONFIG)\n       const springY = useSpring(y, SPRING_CONFIG)\n       const springScale = useSpring(scale, { damping: 20, stiffness: 300 })\n\n       useEffect(() =\u003e {\n         const calculateDistance = (e: MouseEvent) =\u003e {\n           if (ref.current) {\n             const rect = ref.current.getBoundingClientRect()\n             const centerX = rect.left + rect.width / 2\n             const centerY = rect.top + rect.height / 2\n             const distanceX = (e.clientX - centerX) * MAX_DISTANCE\n             const distanceY = (e.clientY - centerY) * MAX_DISTANCE\n\n             if (isHovered) {\n               x.set(distanceX)\n               y.set(distanceY)\n               scale.set(MAX_SCALE)\n             } else {\n               x.set(0)\n               y.set(0)\n               scale.set(1)\n             }\n           }\n         }\n\n         const handleMouseMove = (e: MouseEvent) =\u003e {\n           requestAnimationFrame(() =\u003e calculateDistance(e))\n         }\n\n         document.addEventListener('mousemove', handleMouseMove)\n         return () =\u003e {\n           document.removeEventListener('mousemove', handleMouseMove)\n         }\n       }, [isHovered, x, y, scale])\n\n       return (\n         \u003cmotion.div\n           ref={ref}\n           onMouseEnter={() =\u003e setIsHovered(true)}\n           onMouseLeave={() =\u003e setIsHovered(false)}\n           style={{\n             position: 'relative',\n             x: springX,\n             y: springY,\n             scale: springScale,\n           }}\n         \u003e\n           \u003cComponent {...props} /\u003e\n         \u003c/motion.div\u003e\n       )\n     }\n   }\n   ```\n\n2. In your Framer project, create a new code override snippet [right bottom part of the right sidebar -\u003e Code Override -\u003e New File] and paste the copied code.\n\n3. Apply the `MagneticWrapper` override to any component or element you want to have the magnetic effect. Don't forget to choose in the panel both: File Name and Override name!\n\n## Troubleshoting\n\n1. Components not responding to hover:\n\n- Ensure that the component is properly wrapped with the MagneticWrapper. If the component is not wrapped correctly, it won't respond to hover events.\n- Verify that the correct file name and override name are selected in the Framer panel.\n\n2. Component alignment issues:\n\n- If the component appears misaligned, try wrapping it in an overflow: visible frame. This can help with alignment issues by allowing the component to expand beyond its container's bounds.\n- If the frame is moved to the left, wrap the component in another frame that is aligned to the center. This ensures that both the component and its container are properly centered.\n\n3. Problems when converting an image into a component:\n\n- If you encounter issues when converting an image into a component, try wrapping the image component in a frame first. Then, apply the MagneticWrapper override to the frame instead of the image component directly.\n- This method ensures that the image component remains stable while the magnetic effect is applied to its containing frame.\n\nThank you, @schemetastic, for finding the errors and ways to fix them!\n\n## Contributing\n\nContributions are welcome! Please open an issue or submit a pull request with any changes.\n\n## License\n\nThis project is licensed under the MIT License.\n\n## Contact\n\nFeel free to reach out on [Twitter](https://twitter.com/pxl_alexjedi), [LinkedIn](https://www.linkedin.com/in/alex-shelvey/), or [Dribbble](https://dribbble.com/pxlhead).\n\nDon't forget to star the repo if you found it useful!\n\n---\n\nHappy coding!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexjedi%2Fmagnetic-wrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexjedi%2Fmagnetic-wrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexjedi%2Fmagnetic-wrapper/lists"}