Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I've have make this animation on the weekend as a "just for fun" thing. And for to play with various techniques I've seen in others code.

I think it works quite alright.

Nevertheless I would appreciate comments about:

  1. How to structure / shorten the JavaScript- and Sass-code better?

  2. How could the animation be improved? So that it runs smoother and more "natural"?

  3. How to improve the responsiveness?

Looking forward to read your comments and suggestions.

'use strict';

var field = document.querySelector('.field');
var starCount = 1000;

function addStar(parent, maxX, maxY) {
  var x = Math.floor(Math.random() * (maxX + 1));
  var y = Math.floor(Math.random() * (maxY + 1));
  var randomNumber = Math.random();

  var star = document.createElement('div');
  var starTop = document.createElement('div');
  var starBottom = document.createElement('div');
  var styleValue = 'left: ' + x + 'px; top: ' + y + 'px;';
  var starKind = '';

  switch (true) {
    case randomNumber < 0.25:
      starKind = 'large-star';
      break;
    case randomNumber < 0.5:
      starKind = 'medium-star';
      break;
    case randomNumber < 0.75:
      starKind = 'small-star';
      break;
    default:
      starKind = 'tiny-star';
  }

  starTop.classList.add(starKind + '-top');
  starBottom.classList.add(starKind + '-bottom');

  star.appendChild(starTop);
  star.appendChild(starBottom);

  star.setAttribute('style', styleValue);
  star.classList.add('star');
  star.classList.add(starKind);

  parent.appendChild(star);

  return star;
}

for (var i = 0; i < starCount; i++) {
  addStar(field, 4000, 400);
}
@keyframes rotateStar {
  0% {
    transform: rotate(0deg);
    opacity: 0.09; }
  10% {
    transform: rotate(36deg);
    opacity: 0.18; }
  20% {
    transform: rotate(72deg);
    opacity: 0.27; }
  30% {
    transform: rotate(108deg);
    opacity: 0.36; }
  40% {
    transform: rotate(144deg);
    opacity: 0.45; }
  50% {
    transform: rotate(180eg);
    opacity: 0.54; }
  60% {
    transform: rotate(216deg);
    opacity: 0.63; }
  70% {
    transform: rotate(248deg);
    opacity: 0.72; }
  80% {
    transform: rotate(284deg);
    opacity: 0.81; }
  90% {
    transform: rotate(320deg);
    opacity: 0.9; }
  100% {
    transform: rotate(356deg);
    opacity: 1.0; } }
@keyframes moveGlass {
  100% {
    margin-left: -3200px; } }
* {
  padding: 0;
  border: 0;
  margin: 0; }

body {
  background-color: black; }

.wrap {
  width: 100%;
  max-width: 800px;
  height: 200px;
  margin: 50px auto;
  overflow: hidden;
  border: 2px solid white;
  border-radius: 8px;
  line-height: 0;
  padding: 0 20px; }

.field {
  height: 200px;
  position: relative;
  background-color: #000000;
  animation: moveGlass 55s ease-in infinite alternate;
  display: inline-block; }

.star {
  background-color: white;
  opacity: 1.0;
  position: absolute;
  animation: rotateStar 2s infinite alternate; }

.star .large-star-top:before {
  border-bottom-right-radius: 100%; }

.star .large-star-top:after {
  left: 7px;
  border-bottom-left-radius: 100%; }

.star .large-star-bottom:before {
  top: 7px;
  border-top-right-radius: 100%; }

.star .large-star-bottom:after {
  top: 7px;
  left: 7px;
  border-top-left-radius: 100%; }

.star .large-star-top:before, .star .large-star-top:after,
.star .large-star-bottom:before, .star .large-star-bottom:after {
  content: "";
  position: absolute;
  background-color: black;
  width: 8px;
  height: 8px; }

.star .medium-star-top:before {
  border-bottom-right-radius: 100%; }

.star .medium-star-top:after {
  left: 6px;
  border-bottom-left-radius: 100%; }

.star .medium-star-bottom:before {
  top: 6px;
  border-top-right-radius: 100%; }

.star .medium-star-bottom:after {
  top: 6px;
  left: 6px;
  border-top-left-radius: 100%; }

.star .medium-star-top:before, .star .medium-star-top:after,
.star .medium-star-bottom:before, .star .medium-star-bottom:after {
  content: "";
  position: absolute;
  background-color: black;
  width: 7px;
  height: 7px; }

.star .small-star-top:before {
  border-bottom-right-radius: 100%; }

.star .small-star-top:after {
  left: 4px;
  border-bottom-left-radius: 100%; }

.star .small-star-bottom:before {
  top: 4px;
  border-top-right-radius: 100%; }

.star .small-star-bottom:after {
  top: 4px;
  left: 4px;
  border-top-left-radius: 100%; }

.star .small-star-top:before, .star .small-star-top:after,
.star .small-star-bottom:before, .star .small-star-bottom:after {
  content: "";
  position: absolute;
  background-color: black;
  width: 5px;
  height: 5px; }

.star .tiny-star-top:before {
  border-bottom-right-radius: 100%; }

.star .tiny-star-top:after {
  left: 3px;
  border-bottom-left-radius: 100%; }

.star .tiny-star-bottom:before {
  top: 3px;
  border-top-right-radius: 100%; }

.star .tiny-star-bottom:after {
  top: 3px;
  left: 3px;
  border-top-left-radius: 100%; }

.star .tiny-star-top:before, .star .tiny-star-top:after,
.star .tiny-star-bottom:before, .star .tiny-star-bottom:after {
  content: "";
  position: absolute;
  background-color: black;
  width: 4px;
  height: 4px; }

.star.large-star {
  width: 14px;
  height: 14px; }

.star.medium-star {
  width: 12px;
  height: 12px; }

.star.small-star {
  width: 8px;
  height: 8px; }

.star.tiny-star {
  width: 6px;
  height: 6px; }
<div class="wrap">
  <div class="field"></div>
</div>

Here's the uncompiled Sass-code:

$largeStarDimension: 14px;
$mediumStarDimension: 12px;
$smallStarDimension: 8px;
$tinyStarDimension: 6px;
$animationDuration: 2s;
$windowDimension: 200px;
$primaryColor: #000000;
@mixin addOffsets($starClass, $dimension) {
  .star .#{$starClass}-top:before {
    border-bottom-right-radius:  100%;
  }
  .star .#{$starClass}-top:after {
    left: $dimension;
    border-bottom-left-radius:  100%;
  }
  .star .#{$starClass}-bottom:before {
    top: $dimension;
    border-top-right-radius: 100%;
  }
  .star .#{$starClass}-bottom:after {
    top: $dimension;
    left: $dimension;
    border-top-left-radius: 100%;
  }
  .star .#{$starClass}-top:before, .star .#{$starClass}-top:after, 
  .star .#{$starClass}-bottom:before, .star .#{$starClass}-bottom:after {
    content: "";
    position: absolute;
    background-color: black;
    width: $dimension + 1;
    height: $dimension + 1;
  }
}
@mixin setStarDimensions($className, $starDimension) {
  .star.#{$className} {
    width: $starDimension;
    height: $starDimension;
  }  
}
@keyframes rotateStar {
  0% {
    transform: rotate(0deg);
    opacity: 0.09;
  }
  10%{
    transform: rotate(36deg);
    opacity: 0.18;
  }
  20% {
    transform: rotate(72deg);
    opacity: 0.27;
  }
  30% {
    transform: rotate(108deg);
    opacity: 0.36;
  }
  40% {
    transform: rotate(144deg);
    opacity: 0.45;
  }
  50% {
    transform: rotate(180eg);
    opacity: 0.54;
  }
  60% {
    transform: rotate(216deg);
    opacity: 0.63;
  }
  70% {
    transform: rotate(248deg);
    opacity: 0.72;
  }
  80% {
    transform: rotate(284deg);
    opacity: 0.81;
  }
  90% {
    transform: rotate(320deg);
    opacity: 0.9;
  }
  100% {
    transform: rotate(356deg);
    opacity: 1.0;
  }
}
@keyframes moveGlass {
  100% {
    margin-left: -3200px;
  }
}
* {
  padding: 0;
  border: 0;
  margin: 0;
}
body {
  background-color: black;
}
.wrap {
  width: 100%;
  max-width: 800px;
  height: 200px;
  margin: 50px auto;
  overflow: hidden;
  border: 2px solid white;
  border-radius: 8px;
  line-height: 0;
  padding: 0 20px;
}
.field {
  height: $windowDimension;
  position: relative;
  background-color: $primaryColor;
  animation: moveGlass 55s ease-in infinite alternate;
  display: inline-block;
}
.star {
  background-color: white;
  opacity: 1.0;
  position: absolute;
  animation: rotateStar 2s infinite alternate;
}
@include addOffsets("large-star", $largeStarDimension / 2);
@include addOffsets("medium-star", $mediumStarDimension / 2);
@include addOffsets("small-star", $smallStarDimension / 2);
@include addOffsets("tiny-star", $tinyStarDimension / 2);
@include setStarDimensions("large-star", $largeStarDimension);
@include setStarDimensions("medium-star", $mediumStarDimension);
@include setStarDimensions("small-star", $smallStarDimension);
@include setStarDimensions("tiny-star", $tinyStarDimension);
share|improve this question

There's no need to define an animation frame at every 10%. This is prone to many errors (e.g. the change in angle from 60% to 70%).

You need only a from and a to (aliases for 0% and 100%):

@keyframes rotateStar {
    from { transform: rotate(0); }
    to { transform: rotate(360); }
}

I'm guessing you'd like the stars to always rotate in one direction, not alternate in animation-direction. One way to do that would be to decouple the star "blinking" and the rotation. Have the opacity be its own keyframe animation. Then you can have the blinking alternate while keeping the rotation normal.

The rotation animation would work with a linear animation-timing-function.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.