Effect
Effect
Effect
Effect
Magic Cursor Override for Framer
Magic Cursor Override for Framer
Magic Cursor Override for Framer
Magic Cursor Override for Framer
This is a code override in Framer that you can apply to any frame. So, whenever that element is hovered over on the website, a magic cursor animation gets triggered. Feel free to remix the project and have fun playing with the effect.
Props to Hyperplexed for creating the CodePen, and to Canva for the original concept.
This is a code override in Framer that you can apply to any frame. So, whenever that element is hovered over on the website, a magic cursor animation gets triggered. Feel free to remix the project and have fun playing with the effect.
Props to Hyperplexed for creating the CodePen, and to Canva for the original concept.
This is a code override in Framer that you can apply to any frame. So, whenever that element is hovered over on the website, a magic cursor animation gets triggered. Feel free to remix the project and have fun playing with the effect.
Props to Hyperplexed for creating the CodePen, and to Canva for the original concept.
This is a code override in Framer that you can apply to any frame. So, whenever that element is hovered over on the website, a magic cursor animation gets triggered. Feel free to remix the project and have fun playing with the effect.
Props to Hyperplexed for creating the CodePen, and to Canva for the original concept.
Features
This code override is super easy to use. You can just copy and paste the code into your Framer project and create the code override yourself from the assets panel.
It's also customizable. You can change the color of the stars by tweaking the RGB values here:
Below the RGB values, you can also specify three different sizes for the stars.
And here, you can specify the color of the glow, once more using an RGB value:
You can find and copy the code override below.
For the 3D effect, I used the 3D hover override that you can find on this link.
Step / 01
Remix the project.
Step / 02
Copy the override.
Step / 03
Make the override for yourself in your Framer project.
Code override for the magic cursor
Feel free to copy the override code from below and create the override yourself in your Framer project.
import { ComponentType, useEffect, useState } from "react"
import { motion, useSpring, useMotionValue } from "framer-motion"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faStar } from "@fortawesome/free-solid-svg-icons"
import ReactDOM from "react-dom"
export function withCursor(Component): ComponentType {
return (props) => {
const originPosition = { x: 0, y: 0 }
const [isHover, setIsHover] = useState(false)
const [count, setCount] = useState(0)
const [last, setLast] = useState({
starTimestamp: 0,
starPosition: originPosition,
mousePosition: originPosition,
})
const config = {
starAnimationDuration: 1500,
minimumTimeBetweenStars: 250,
minimumDistanceBetweenStars: 75,
glowDuration: 75,
maximumGlowPointSpacing: 10,
colors: ["144 211 252", "252 254 255"],
sizes: ["1.4rem", "1rem", "0.6rem"],
animations: ["fall-1", "fall-2", "fall-3"],
}
const rand = (min, max) =>
Math.floor(Math.random() * (max - min + 1)) + min
const selectRandom = (items) => items[rand(0, items.length - 1)]
const withUnit = (value, unit) => `${value}${unit}`
const px = (value) => withUnit(value, "px")
const ms = (value) => withUnit(value, "ms")
const calcDistance = (a, b) => {
const diffX = b.x - a.x,
diffY = b.y - a.y
return Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2))
}
const calcElapsedTime = (start, end) => end - start
const createStar = (position) => {
const star = document.createElement("span")
const color = selectRandom(config.colors)
star.className = "star"
// Use FontAwesomeIcon to render the star icon
const iconComponent = <FontAwesomeIcon icon={faStar} />
ReactDOM.render(iconComponent, star)
star.style.left = px(position.x)
star.style.top = px(position.y)
star.style.fontSize = selectRandom(config.sizes)
star.style.color = `rgb(${color})`
star.style.textShadow = `0px 0px 1.5rem rgb(${color} / 0.5)`
star.style.animationName = config.animations[count % 3]
setCount((prevCount) => prevCount + 1)
star.style.animationDuration = ms(config.starAnimationDuration)
document.body.appendChild(star)
setTimeout(
() => document.body.removeChild(star),
config.starAnimationDuration
)
}
const createGlowPoint = (position) => {
const glow = document.createElement("div")
glow.className = "glow-point"
glow.style.left = px(position.x)
glow.style.top = px(position.y)
document.body.appendChild(glow)
setTimeout(
() => document.body.removeChild(glow),
config.glowDuration
)
}
const determinePointQuantity = (distance) =>
Math.max(Math.floor(distance / config.maximumGlowPointSpacing), 1)
const createGlow = (lastPoint, currentPoint) => {
const distance = calcDistance(lastPoint, currentPoint)
const quantity = determinePointQuantity(distance)
const dx = (currentPoint.x - lastPoint.x) / quantity
const dy = (currentPoint.y - lastPoint.y) / quantity
Array.from(Array(quantity)).forEach((_, index) => {
const x = lastPoint.x + dx * index,
y = lastPoint.y + dy * index
createGlowPoint({ x, y })
})
}
const updateLastStar = (position) => {
setLast((prevLast) => ({
...prevLast,
starTimestamp: new Date().getTime(),
starPosition: position,
}))
}
const updateLastMousePosition = (position) => {
setLast((prevLast) => ({
...prevLast,
mousePosition: position,
}))
}
const adjustLastMousePosition = (position) => {
if (last.mousePosition.x === 0 && last.mousePosition.y === 0) {
setLast((prevLast) => ({
...prevLast,
mousePosition: position,
}))
}
}
const handleOnMove = (e) => {
const mousePosition = { x: e.clientX, y: e.clientY }
adjustLastMousePosition(mousePosition)
const now = new Date().getTime()
const hasMovedFarEnough =
calcDistance(last.starPosition, mousePosition) >=
config.minimumDistanceBetweenStars
const hasBeenLongEnough =
calcElapsedTime(last.starTimestamp, now) >
config.minimumTimeBetweenStars
if (isHover) {
if (hasMovedFarEnough || hasBeenLongEnough) {
createStar(mousePosition)
updateLastStar(mousePosition)
}
createGlow(last.mousePosition, mousePosition)
}
updateLastMousePosition(mousePosition)
}
useEffect(() => {
window.addEventListener("mousemove", handleOnMove)
window.addEventListener("touchmove", (e) =>
handleOnMove(e.touches[0])
)
document.body.addEventListener("mouseleave", () =>
updateLastMousePosition(originPosition)
)
return () => {
window.removeEventListener("mousemove", handleOnMove)
window.removeEventListener("touchmove", (e) =>
handleOnMove(e.touches[0])
)
document.body.removeEventListener("mouseleave", () =>
updateLastMousePosition(originPosition)
)
}
}, [last])
return (
<>
<style>{`
.glow-point {
position: absolute;
box-shadow: 0rem 0rem 1.2rem 0.6rem rgb(102, 242, 255, 0.85);
pointer-events: none;
}
.star {
position: absolute;
z-index: 2;
color: white;
font-size: 1rem;
animation-duration: 1500ms;
animation-fill-mode: forwards;
pointer-events: none;
}
@keyframes fall-1 {
0% {
transform: translate(0px, 0px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(0.25);
opacity: 0;
}
5% {
transform: translate(10px, -10px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(1);
opacity: 1;
}
100% {
transform: translate(25px, 200px) rotateX(180deg) rotateY(270deg) rotateZ(90deg) scale(1);
opacity: 0;
}
}
@keyframes fall-2 {
0% {
transform: translate(0px, 0px) rotateX(-20deg) rotateY(10deg) scale(0.25);
opacity: 0;
}
10% {
transform: translate(-10px, -5px) rotateX(-20deg) rotateY(10deg) scale(1);
opacity: 1;
}
100% {
transform: translate(-10px, 160px) rotateX(-90deg) rotateY(45deg) scale(0.25);
opacity: 0;
}
}
@keyframes fall-3 {
0% {
transform: translate(0px, 0px) rotateX(0deg) rotateY(45deg) scale(0.5);
opacity: 0;
}
15% {
transform: translate(7px, 5px) rotateX(0deg) rotateY(45deg) scale(1);
opacity: 1;
}
100% {
transform: translate(20px, 120px) rotateX(-180deg) rotateY(-90deg) scale(0.5);
opacity: 0;
}
}
`}</style>
<Component
{...props}
onHoverStart={() => setIsHover(true)}
onHoverEnd={() => setIsHover(false)}
/>
</>
)
}
}
import { ComponentType, useEffect, useState } from "react"
import { motion, useSpring, useMotionValue } from "framer-motion"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faStar } from "@fortawesome/free-solid-svg-icons"
import ReactDOM from "react-dom"
export function withCursor(Component): ComponentType {
return (props) => {
const originPosition = { x: 0, y: 0 }
const [isHover, setIsHover] = useState(false)
const [count, setCount] = useState(0)
const [last, setLast] = useState({
starTimestamp: 0,
starPosition: originPosition,
mousePosition: originPosition,
})
const config = {
starAnimationDuration: 1500,
minimumTimeBetweenStars: 250,
minimumDistanceBetweenStars: 75,
glowDuration: 75,
maximumGlowPointSpacing: 10,
colors: ["144 211 252", "252 254 255"],
sizes: ["1.4rem", "1rem", "0.6rem"],
animations: ["fall-1", "fall-2", "fall-3"],
}
const rand = (min, max) =>
Math.floor(Math.random() * (max - min + 1)) + min
const selectRandom = (items) => items[rand(0, items.length - 1)]
const withUnit = (value, unit) => `${value}${unit}`
const px = (value) => withUnit(value, "px")
const ms = (value) => withUnit(value, "ms")
const calcDistance = (a, b) => {
const diffX = b.x - a.x,
diffY = b.y - a.y
return Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2))
}
const calcElapsedTime = (start, end) => end - start
const createStar = (position) => {
const star = document.createElement("span")
const color = selectRandom(config.colors)
star.className = "star"
// Use FontAwesomeIcon to render the star icon
const iconComponent = <FontAwesomeIcon icon={faStar} />
ReactDOM.render(iconComponent, star)
star.style.left = px(position.x)
star.style.top = px(position.y)
star.style.fontSize = selectRandom(config.sizes)
star.style.color = `rgb(${color})`
star.style.textShadow = `0px 0px 1.5rem rgb(${color} / 0.5)`
star.style.animationName = config.animations[count % 3]
setCount((prevCount) => prevCount + 1)
star.style.animationDuration = ms(config.starAnimationDuration)
document.body.appendChild(star)
setTimeout(
() => document.body.removeChild(star),
config.starAnimationDuration
)
}
const createGlowPoint = (position) => {
const glow = document.createElement("div")
glow.className = "glow-point"
glow.style.left = px(position.x)
glow.style.top = px(position.y)
document.body.appendChild(glow)
setTimeout(
() => document.body.removeChild(glow),
config.glowDuration
)
}
const determinePointQuantity = (distance) =>
Math.max(Math.floor(distance / config.maximumGlowPointSpacing), 1)
const createGlow = (lastPoint, currentPoint) => {
const distance = calcDistance(lastPoint, currentPoint)
const quantity = determinePointQuantity(distance)
const dx = (currentPoint.x - lastPoint.x) / quantity
const dy = (currentPoint.y - lastPoint.y) / quantity
Array.from(Array(quantity)).forEach((_, index) => {
const x = lastPoint.x + dx * index,
y = lastPoint.y + dy * index
createGlowPoint({ x, y })
})
}
const updateLastStar = (position) => {
setLast((prevLast) => ({
...prevLast,
starTimestamp: new Date().getTime(),
starPosition: position,
}))
}
const updateLastMousePosition = (position) => {
setLast((prevLast) => ({
...prevLast,
mousePosition: position,
}))
}
const adjustLastMousePosition = (position) => {
if (last.mousePosition.x === 0 && last.mousePosition.y === 0) {
setLast((prevLast) => ({
...prevLast,
mousePosition: position,
}))
}
}
const handleOnMove = (e) => {
const mousePosition = { x: e.clientX, y: e.clientY }
adjustLastMousePosition(mousePosition)
const now = new Date().getTime()
const hasMovedFarEnough =
calcDistance(last.starPosition, mousePosition) >=
config.minimumDistanceBetweenStars
const hasBeenLongEnough =
calcElapsedTime(last.starTimestamp, now) >
config.minimumTimeBetweenStars
if (isHover) {
if (hasMovedFarEnough || hasBeenLongEnough) {
createStar(mousePosition)
updateLastStar(mousePosition)
}
createGlow(last.mousePosition, mousePosition)
}
updateLastMousePosition(mousePosition)
}
useEffect(() => {
window.addEventListener("mousemove", handleOnMove)
window.addEventListener("touchmove", (e) =>
handleOnMove(e.touches[0])
)
document.body.addEventListener("mouseleave", () =>
updateLastMousePosition(originPosition)
)
return () => {
window.removeEventListener("mousemove", handleOnMove)
window.removeEventListener("touchmove", (e) =>
handleOnMove(e.touches[0])
)
document.body.removeEventListener("mouseleave", () =>
updateLastMousePosition(originPosition)
)
}
}, [last])
return (
<>
<style>{`
.glow-point {
position: absolute;
box-shadow: 0rem 0rem 1.2rem 0.6rem rgb(102, 242, 255, 0.85);
pointer-events: none;
}
.star {
position: absolute;
z-index: 2;
color: white;
font-size: 1rem;
animation-duration: 1500ms;
animation-fill-mode: forwards;
pointer-events: none;
}
@keyframes fall-1 {
0% {
transform: translate(0px, 0px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(0.25);
opacity: 0;
}
5% {
transform: translate(10px, -10px) rotateX(45deg) rotateY(30deg) rotateZ(0deg) scale(1);
opacity: 1;
}
100% {
transform: translate(25px, 200px) rotateX(180deg) rotateY(270deg) rotateZ(90deg) scale(1);
opacity: 0;
}
}
@keyframes fall-2 {
0% {
transform: translate(0px, 0px) rotateX(-20deg) rotateY(10deg) scale(0.25);
opacity: 0;
}
10% {
transform: translate(-10px, -5px) rotateX(-20deg) rotateY(10deg) scale(1);
opacity: 1;
}
100% {
transform: translate(-10px, 160px) rotateX(-90deg) rotateY(45deg) scale(0.25);
opacity: 0;
}
}
@keyframes fall-3 {
0% {
transform: translate(0px, 0px) rotateX(0deg) rotateY(45deg) scale(0.5);
opacity: 0;
}
15% {
transform: translate(7px, 5px) rotateX(0deg) rotateY(45deg) scale(1);
opacity: 1;
}
100% {
transform: translate(20px, 120px) rotateX(-180deg) rotateY(-90deg) scale(0.5);
opacity: 0;
}
}
`}</style>
<Component
{...props}
onHoverStart={() => setIsHover(true)}
onHoverEnd={() => setIsHover(false)}
/>
</>
)
}
}
Free Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.
Free
Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.
Free Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.