Credits
Shout out to Magic UI for the inspiration. I actually discovered this package while browsing their website.
Getting Started
Add Animation
You will need to add this to your tailwind.config.js
file.
// tailwind.config.js
module.exports = {
theme: {
extend: {
animation: {
meteor: "meteor 5s linear infinite",
},
keyframes: {
meteor: {
"0%": { transform: "rotate(215deg) translateX(0)", opacity: 1 },
"70%": { opacity: 1 },
"100%": {
transform: "rotate(215deg) translateX(-500px)",
opacity: 0,
},
},
},
},
},
};
Create Component
Create the component UiMeteors.client.vue
in the components
directory.
<template>
<span
v-for="(s, i) in meteorStyles"
:key="i"
:class="localStyles().wrapper({ class: props.class })"
:style="s"
>
<div :class="localStyles().tail()" />
</span>
</template>
<script lang="ts" setup>
import type { CSSProperties, HTMLAttributes } from "vue";
interface MeteorsProps {
number?: number;
minDelay?: number;
maxDelay?: number;
minDuration?: number;
maxDuration?: number;
angle?: number;
class?: HTMLAttributes["class"];
}
const props = withDefaults(defineProps<MeteorsProps>(), {
number: 20,
minDelay: 0.2,
maxDelay: 1.2,
minDuration: 2,
maxDuration: 10,
angle: 215,
});
const meteorStyles = ref<CSSProperties[]>(
[...Array.from({ length: props.number })].map(() => ({
"--angle": -props.angle + "deg",
top: "-5%",
left: `calc(0% + ${Math.floor(Math.random() * window.innerWidth)}px)`,
animationDelay: Math.random() * (props.maxDelay - props.minDelay) + props.minDelay + "s",
animationDuration:
Math.floor(Math.random() * (props.maxDuration - props.minDuration) + props.minDuration) +
"s",
}))
);
const setStyles = () => {
const styles = [...new Array(props.number)].map(() => ({
"--angle": -props.angle + "deg",
top: "-5%",
left: `calc(0% + ${Math.floor(Math.random() * window.innerWidth)}px)`,
animationDelay: Math.random() * (props.maxDelay - props.minDelay) + props.minDelay + "s",
animationDuration:
Math.floor(Math.random() * (props.maxDuration - props.minDuration) + props.minDuration) +
"s",
}));
meteorStyles.value = styles;
};
setStyles();
watch(
() => [
props.number,
props.minDelay,
props.maxDelay,
props.minDuration,
props.maxDuration,
props.angle,
],
setStyles
);
const localStyles = tv({
slots: {
wrapper:
"pointer-events-none absolute size-0.5 rotate-[var(--angle)] animate-meteor rounded-full bg-zinc-500 shadow-[0_0_0_1px_#ffffff10]",
tail: "pointer-events-none absolute top-1/2 -z-10 h-px w-[50px] -translate-y-1/2 bg-gradient-to-r from-zinc-500 to-transparent",
},
});
</script>
Usage
Basic
We can add the UiMeteors
component to trigger the meteors.
Meteors