Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotating Text around a circle to make it look like a sphere

Trying to get my nav bar to be a series of circles where if you hover over them it displays the text that goes with them. Heres what I have so far:

document.querySelectorAll('.color-circle').forEach((circle, index) => {
  circle.addEventListener('click', () => {
    alert(`Navigate to: ${circle.querySelector('.orbit-text').innerText}`);
  });
});
.color-circle {
  position: relative;
  border-radius: 50%;
  cursor: pointer;
  transition: transform 0.3s ease;
}

.color-circle:hover {
  transform: scale(1.2);
}

.orbit {
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.color-circle:hover .orbit {
  opacity: 1;
  animation: orbit 2s linear infinite;
}

.orbit-text {
  position: absolute;
  left: 50%;
  top: 50%;
  transform-origin: center;
  transform: translate(-50%, -50%) rotateY(0deg);
  color: white;
  font-size: 8px;
  font-weight: bold;
  text-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
  animation: orbit3D 4s linear infinite;
}

@keyframes orbit3D {
  from {
    transform: translate(-50%, -50%) rotateY(0deg) translateZ(15px);
  }
  to {
    transform: translate(-50%, -50%) rotateY(360deg) translateZ(15px);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.3/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>

<div class="top-bar visible">
  <div class="circle-container">
    <div class="color-circle" style="background-color: rgb(227, 197, 103); width: 40px; height: 40px;">
      <div class="orbit">
        <span class="orbit-text">HOME</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(200, 150, 62); width: 30px; height: 30px;">
      <div class="orbit">
        <span class="orbit-text">DEV & DESIGN</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(87, 61, 28); width: 25px; height: 25px;">
      <div class="orbit">
        <span class="orbit-text">ACTING</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(217, 174, 97); width: 20px; height: 20px;">
      <div class="orbit">
        <span class="orbit-text">FILMMAKING</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(209, 70, 47); width: 15px; height: 15px;">
      <div class="orbit">
        <span class="orbit-text">GALLERY</span>
      </div>
    </div>
  </div>
</div>

Spacing and other formatting isn't done but I am hitting a wall with having the text distort as if its curving when turned away and flatter when closer as if it was actually etched onto the rotating sphere.

Thanks!

like image 604
mmkranz7 Avatar asked Sep 29 '25 10:09

mmkranz7


1 Answers

Position the desired text on the bottom a "stick" DIV that is positioned at the center of the circle. Set the "stick" transformation origin to its top. Apply the needed rotations and counter-rotations, transform-style: preserve-3d;, and the infinite rotation animation:

body { background: #343536; }

.color-circle {
  position: relative;
  width: calc(var(--size) * 1em);
  aspect-ratio: 1;
  background-color: var(--bg);
  border-radius: 50%;
  margin: 1em;
  perspective: 220px;
  transform-style: preserve-3d;
  display: flex;
  
  .orbit {
    position: absolute;
    left: 50%;
    top: 50%;
    background: #0006;
    width: 2px;
    height: calc(var(--size) / 2 * 1em + 1em);
    display: flex;
    transform-origin: 50% 0%;
    transform-style: preserve-3d;
    rotate: 1 0 0 90deg;
    animation: orbit 4s linear infinite;
    display: flex;
    
    .orbit-text {
      translate: -50% 50%;
      align-self: flex-end;
      /* white-space: nowrap; */
      rotate: -1 0 0 90deg;
      color: white;
      font-size: 1rem;
      font-weight: bold;
      text-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
    }
  }
}

@keyframes orbit {
  to {
    transform: rotate3d(0, 0, 1, 360deg);
  }
}
<div class="color-circle" style="--size:4; --bg:#ec6;">
  <div class="orbit">
    <span class="orbit-text">HOME</span>
  </div>
</div>
<div class="color-circle" style="--size:3.5; --bg:#c96;">
  <div class="orbit">
    <span class="orbit-text">DEV &amp; DESIGN</span>
  </div>
</div>
<div class="color-circle" style="--size:3; --bg:#754;">
  <div class="orbit">
    <span class="orbit-text">ACTING</span>
  </div>
</div>
<div class="color-circle" style="--size:2.5; --bg:#da6;">
  <div class="orbit">
    <span class="orbit-text">FILMMAKING</span>
  </div>
</div>
<div class="color-circle" style="--size:2; --bg:#d42;">
  <div class="orbit">
    <span class="orbit-text">GALLERY</span>
  </div>
</div>

The code is inspired by this similar answer: Create a 3D asteroid belt.

What I would also do is: use white-space: nowrap; on the text, create (with JS) separate SPAN elements for every character, add a CSS property --index and rotate each SPAN element by the needed index degrees to make it look like every character orbits on its own. The only downside I guess would be using monospace font.

like image 189
Roko C. Buljan Avatar answered Oct 02 '25 05:10

Roko C. Buljan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!