htmlcssanimation

Making a 3d planet environment


I have a planet I have given a linear-gradient and I am trying to make rocks circle the perimeter of the planet while also having maybe some visible weather on the planet look like typhoons wandering around on it.

The goal is to make a planet with a orbiting rocks that the user can move the cursor to push slightly for a cool effect. That might require javascript but I'll tackle the first project first.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background: black;
}

.planet,
.planet2 {
  position: absolute;
  margin: 5px;
  top: 50%;
  left: 50%;
  transform: translate(-60%, 0);
  height: 1100px;
  width: 900px;
  border-radius: 50%;
  z-index: 2;
  background: linear-gradient(40deg, #4a190290 20%, #7b222235, #2b2a29df);
  box-shadow: -20px -20px 40px 40px #801a1a6f inset, 0 0 20px 40px #cb221f90;
}

.astroid__belt {
  width: 100%;
  height: 100%;
  top: 10%;
  left: calc(50% - 50%);
  transform-style: preserve-3d;
  transform: perspective(1000px);
  text-align: center;
  overflow: hidden;
  position: relative;
}

.planet2 {
  position: absolute;
  background: linear-gradient(45deg, transparent 50%, #ac4444, #b90f0fde, #542408b0);
  z-index: 3;
}

.astroid1 {
  position: relative;
  top: 10%;
  width: 200px;
  height: 400px;
  left: calc(50% - 200px);
  background-color: #090606;
  border-right: 3px solid transparent;
  border-radius: 50%;
  z-index: 2;
  animation: animateAstroid 7s linear infinite;
  transform: tranzlateZ(550px);
}

.astroid__belt .astroid {
  position: absolute;
  inset: 0 0 0 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.astroid,
div {
  position: absolute;
  transform-style: preserve-3d;
  border-radius: 70%;
}

@keyframes animateAstroid1 {
  0% {
    transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);
  }
  100% {
    transform: rotateX(0deg) rotateY(75deg) rotateZ(360deg);
  }
}

@keyframes animateAstroid2 {
  0% {
    transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);
  }
  100% {
    transform: rotateX(0deg) rotateY(20deg) rotateZ(360deg);
  }
}
<div class="astroid__belt">
  <div class="astroid1"></div>
  <div class="astroid2"></div>
  <div class="astroid3"></div>
  <div class="astroid4"></div>
  <div class="astroid5"></div>
  <div class="astroid6"></div>
  <div class="astroid7"></div>
  <div class="astroid8"></div>
  <div class="astroid9"></div>
  <div class="astroid10"></div>
  <div class="astroid12"></div>
</div>
<div class="planet"></div>

I've tried getting the rings around the planet to circle around like a planet normally would, not just in a 2d space.


Solution

  • Here's my take at creating an asteroid belt,
    create .orbit elements for your .asteroid-s. Rotate the .orbit elements on the X axis and counter-rotate the asteroids. Animate the orbits on the Z axis and the asteroids on the Y axis by negative 360 degrees to counter-rotate and keep them in a circle shape.

    * {
      margin: 0;
      box-sizing: border-box;
    }
    
    body {
      overflow: hidden;
      min-height: 100dvh;
      display: flex;
      align-items: center;
      justify-content: center;
      background: #000;
    }
    
    .system {
      --size: 100;
      container-type: size;
      transform-style: preserve-3d;
      perspective: 2000px;
      width:calc(var(--size) * 1cqmin);
      aspect-ratio: 1;
    }
    
    .planet,
    .orbit,
    .asteroid {
      --y: 0;
      transform-style: preserve-3d;
      position: absolute;
      inset: 0;
      height: calc(var(--size) * 1%);
      margin: auto;
      aspect-ratio: 1;
      border-radius: 50%;
    }
    
    .planet {
      background: hsl(var(--hue) 50% 50%) linear-gradient(50deg, #0000 0%, #0000 45%, #000a 55%, #000e 100%);
    }
    
    .orbit {
      --duration: 6;
      box-shadow: 0 0 0 2vmin #fff4, inset 0 0 0 2cqmin #fff4;
      animation: orbit calc(var(--duration) * 1s) linear infinite;
      rotate: 1 var(--y) 0 80deg;
    }
    
    .asteroid {
      margin-left: calc(var(--size) * -0.5%);
      background: hsl(var(--hue) 50% 50%) linear-gradient(115deg, #0000 0%, #0000 45%, #000a 55%, #000e 100%);
      animation: asteroid calc(var(--duration) * 1s) linear infinite;
      rotate: 1 0 0 90deg;
    }
    
    @keyframes orbit { to { transform: rotate3d(0, 0, 1, 360deg); } }
    @keyframes asteroid { to { transform: rotate3d(0, 1, 0, -360deg); } }
    <div class="system">
      <div class="planet" style="--size:40; --hue:10;"></div>
      
      <div class="orbit" style="--size:68; --y:-0.2; --duration:10;">
        <div class="asteroid" style="--size:8; --hue:20;"></div>
      </div>
      
      <div class="orbit" style="--size:80; --y:-0.2; --duration:6;">
        <div class="asteroid" style="--size:5; --hue:30;"></div>
      </div>
      
      <div class="orbit" style="--size:100; --y:-0.28; --duration:30;">
        <div class="asteroid" style="--size:10; --hue:190;"></div>
      </div>
    </div>

    Not perfect (a steeper orbit angle would reveal that gimballing the asteroids/moons to always face the "camera" gets quite hard...), but hopefully you can explore the idea further, like: create oval, elliptical orbits for certain rocks, and use a Bezier-curve animation instead of linear, play with other angles of inclination, etc.

    The planets' weather (like typhoons, formations, etc.) can be achieved in the same way as for the asteroids, with the only difference that they should orbit the planet much closer, and you don't need to counter rotate the elements. Let them pancake/deform as they rotate on their orbits, just add a swirl rotation around their Z axis. Also a clipping area would be necessary to circumvent the flat nature of the orbiting element/pane.