Eldora UI
Eldora UI
  1. Components
  2. Special Animations
  3. Globe anime

Globe anime

A 3d illustuation globe for backgrounds

globe wireframe
<Globeanime/>

Installation

Install the following dependencies:

npm install animejs lucide-react react-copy-to-clipboard typed.js

Copy and paste the following code into your project.

"use client";
import React, { useEffect, useRef, useState } from 'react';
import Image from 'next/image';
import anime from 'animejs';
import { Check, Copy } from 'lucide-react';
import CopyToClipboard from 'react-copy-to-clipboard';
import Typed from 'typed.js';

const Globeanime = () => {
  const ref = useRef(null);
  const typerRef = useRef(null);
  const [copied, setCopied] = useState(false);
  const [darkMode, setDarkMode] = useState(false); // State to manage dark mode

  const handleCopy = () => {
    setCopied(true);
    setTimeout(() => {
      setCopied(false);
    }, 1000);
  };

  const dots = [
    {
      id: 'dot1',
      type: 'dot',
      left: '50%',
      top: '29.9%',
      delay: 1,
    },
    {
      id: 'dot2',
      type: 'dot',
      left: '24.3%',
      top: '50.2%',
      delay: 1,
    },
    {
      id: 'dot3',
      type: 'dot',
      left: '77.8%',
      top: '63.4%',
      delay: 1,
    },
  ];

  const svgs = [
    {
      id: 'svg1',
      type: 'svg',
      viewbox: '0 0 155 284',
      width: '15.244%',
      height: '41.24%',
      left: '38.8%',
      top: '31.2%',
      path: 'M.797 283.216c14.605-22.693 64.498-78.738 87.739-104.396-22.406-17.823-47.852-46.354-57.983-58.555 36.536-29.153 96.735-65.699 122.267-80.327-6.727-8.041-21.226-27.282-26.518-39.053',
      x1: '100%',
      x2: '100%',
      y1: '-20%',
      y1config: {
        initial: '-20%',
        frames: ['-20%', '100%'],
      },
      y2: '0',
      y2config: {
        initial: '0',
        frames: ['0', '130%'],
      },
      duration: 350,
      delay: 1350,
      offset: 0,
      easing: 'linear',
    },
    {
      id: 'svg2',
      type: 'svg',
      viewbox: '0 0 272 235',
      width: '27.458%',
      height: '34.045%',
      left: '50.8%',
      top: '31.4%',
      path: 'M271.749 233.614C215.075 230.474 159.599 210.964 138.945 201.602C144.38 186.681 156.517 152.612 161.587 135.71C126.058 122.39 44.25 76.75 1.25 0.75',
      x1: '100%',
      x2: '100%',
      y1: '-20%',
      y1config: {
        initial: '-20%',
        frames: ['-20%', '100%'],
      },
      y2: '0',
      y2config: {
        initial: '0',
        frames: ['0', '130%'],
      },
      duration: 300,
      delay: 1350,
      offset: 0,
      easing: 'linear',
    },
    {
      id: 'svg3',
      type: 'svg',
      viewbox: '0 0 261 144',
      width: '26.687%',
      height: '20.49%',
      left: '25.1%',
      top: '31.4%',
      path: 'M260.5 1.5C157.75 30.75 67.75 89 1.13281 143.202',
      x1: '100%',
      x2: '100%',
      y1: '-20%',
      y1config: {
        initial: '-20%',
        frames: ['-20%', '100%'],
      },
      y2: '0',
      y2config: {
        initial: '0',
        frames: ['0', '130%'],
      },
      duration: 200,
      delay: 1350,
      offset: 0,
      easing: 'linear',
    },
  ];

  useEffect(() => {
    animate();
  }, []);

  const animate = () => {
    const tl = anime.timeline({
      loop: false,
      autoplay: true,
    });

    svgs.forEach((s) => {
      tl.add(
        {
          targets: `#functions-hero #${s.id} linearGradient`,
          y2: s.y2config.frames,
          easing: s.easing,
          duration: s.duration,
          delay: s.delay,
        },
        s.offset
      );
    });

    const typed = new Typed(typerRef.current, {
      strings: ['npm install eldoraui'],
      typeSpeed: 10,
      startDelay: 300,
      showCursor: false,
      loop: false,
    });

    setTimeout(() => {
      typed.start();
      tl.play();
    }, 100);

    return () => {
      typed.destroy();
    };
  };

  // Function to toggle dark mode
  const toggleDarkMode = () => {
    setDarkMode(!darkMode);
  };

  return (
    <div
      ref={ref}
      id="functions-hero"
      className="
        absolute inset-0
        -left-28 top-4 w-[150%] md:w-[150%] aspect-[978/678]
        sm:-left-32 sm:-top-2
        md:-left-44
        lg:-left-10 lg:-top-10 lg:w-[130%]
        xl:-left-32 xl:w-[130%]
      "
    >
      {/* Snippet element */}
      <div
        className="
          opacity-0 animate-fade-in absolute z-20 flex-1 flex items-center justify-center h-auto
          w-[60%] left-[25%] top-[2%]
          sm:w-[35%] sm:left-[34%] sm:top-[6%]
          md:left-[33.5%] md:w-[35%] md:top-[6%]
          lg:left-[26%] lg:w-[52%] lg:top-[3%]
          xl:left-[28%] xl:w-[48%] xl:top-[3%]
          2xl:left-[32%] 2xl:w-[40%] 2xl:top-[3%]
        "
      >
        <CopyToClipboard text="npm install eldoraui">
          <button
            onClick={handleCopy}
            className="w-full px-3 py-2 group hover:border-strong flex gap-1 sm:gap-2 items-center bg-alternative rounded-xl border"
          >
            <div className="text-foreground-muted text-sm font-mono">$</div>
            <div
              ref={typerRef}
              className="opacity-0 flex-1 text-left animate-fade-in text-foreground text-xs md:text-sm font-mono"
            />
            <div className="text-foreground rounded p-1.5 opacity-0 group-hover:opacity-100 transition-opacity">
              {copied ? (
                <span className="text-brand">
                  <Check className="w-3.5 h-3.5" />
                </span>
              ) : (
                <Copy className="w-3.5 h-3.5" />
              )}
            </div>
          </button>
        </CopyToClipboard>
      </div>
      {/* Animated svgs in globe */}
      {svgs.map((s) => (
        <svg
          key={s.id}
          id={s.id}
          xmlns="http://www.w3.org/2000/svg"
          width="100%"
          height="100%"
          fill="none"
          viewBox={s.viewbox}
          className="absolute"
          style={{
            width: s.width,
            height: s.height,
            left: s.left,
            top: s.top,
          }}
        >
          <path stroke={`url(#lg-${s.id})`} strokeWidth="1.396" d={s.path} />
          <defs>
            <linearGradient
              id={`lg-${s.id}`}
              x1={s.x1}
              x2={s.x2}
              y1={s.y1}
              y2={s.y2}
              gradientUnits="userSpaceOnUse"
            >
              {/* Define colors for both light and dark modes */}
              <stop offset="0" stopColor={darkMode ? '#000000' : '#FFFFFF'} stopOpacity="0" />
              <stop offset="0.5" stopColor={darkMode ? '#000000' : '#FFFFFF'} stopOpacity="0.6" />
              <stop offset="1" stopColor={darkMode ? '#000000' : '#FFFFFF'} stopOpacity="0" />
            </linearGradient>
          </defs>
        </svg>
      ))}

      {/* Dots on globe */}
      {dots.map((dot) => (
        <div
          key={dot.id}
          id={dot.id}
          style={{ left: dot.left, top: dot.top }}
          className="absolute origin-center w-[2.5%] h-[3.6%] flex items-center justify-center opacity-0 transition-opacity animate-fade-in delay-75"
        >
          <span className="absolute inset-0 w-full h-full rounded-full bg-black dark:bg-white bg-opacity-20" />
          <span className="absolute w-4/5 h-4/5 rounded-full bg-black dark:bg-white bg-opacity-90" />
        </div>
      ))}
      <div className="absolute left-[51.15%] top-[10%] w-px h-[20%] overflow-hidden">
        <span className="absolute inset-0 w-full bg-gradient-to-t from-current to-transparent h-full delay-1200 animate-slide-in" />
      </div>
      {/* Globe background */}
      <Image
        src="/usage/globe-light.svg"
        alt="globe wireframe"
        width={400}
        height={400}
        className={`w-full h-full ${darkMode ? 'hidden' : 'block'}`} // Hide/show based on dark mode
        quality={100}
        priority
      />
      <Image
        src="/usage/globe.svg"
        alt="globe wireframe"
        width={400}
        height={400}
        className={`w-full h-full ${darkMode ? 'block' : 'hidden'}`} // Hide/show based on dark mode
        quality={100}
        priority
      />
    </div>
  );
};

export default Globeanime;

Add background globe svg's to your project from here .

Update the import paths to match your project setup.

Built by karthikmudunuri. The source code is available on GitHub.