<main class="room">
  <div class="floating-container">
    <section class="obj obj_name_rail">
      <div class="spr spr_name_rail"></div>
    </section>

    <section class="obj obj_name_loco">
      <div class="spr spr_name_loco"></div>
    </section>

    <button class="obj obj_name_wagon obj_type_btn" type="button">
      <div class="spr spr_name_wagon"></div>
    </button>

    <section class="obj obj_name_tunnel">
      <div class="spr spr_name_tunnel"></div>
    </section>

    <button class="obj obj_name_arrow obj_type_btn" type="button">
      <div class="spr spr_name_arrow"></div>
    </button>

    <section class="obj obj_name_tree">
      <div class="spr spr_name_tree"></div>
    </section>

    <button class="obj obj_name_gifts obj_type_btn" type="button">
      <div class="spr spr_name_gifts"></div>
    </button>

    <button class="obj obj_name_snowman obj_type_btn" type="button">
      <div class="spr spr_name_snowman"></div>
    </button>

    <section class="obj obj_name_snowman-dec">
      <div class="spr spr_name_snowman-dec"></div>
    </section>
  </div>

  <section class="overlay overlay_name_start">
    <div class="modal">
      <div class="modal__person">
        <div class="santa"></div>
        <h3>Santa</h3>
      </div>
      <p>
        Ho-ho-ho, Hello!
        <br />I hid the presents.
        <br />Can you find them?
      </p>
      <button class="modal__btn js_scr_start" type="button">Start</button>
    </div>
  </section>

  <section class="overlay overlay_name_end overlay_state_disabled">
    <div class="modal">
      <div class="modal__person">
        <div class="santa"></div>
        <h3>Santa</h3>
      </div>
      <p>
        Congratulations! 🥳
        <br />You found them!
        <br />You can open your gifts
        <br /><span class="timer"></span>.
      </p>
    </div>
  </section>

  <!-- snowflakes by @codeconvey | begin -->
  <section class="snowflakes" aria-hidden="true">
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
    <div class="snowflake"></div>
  </section>
  <!-- snowflakes by @codeconvey | end -->

  <section class="toggle-song">
    <button type="button" class="toggle-song__btn gg-play-button-o"></button>
    <span class="toggle-song__text">Music</span>
  </section>
</main>

<audio id="song">
  <source src="https://opengameart.org/sites/default/files/Christmas%20synths.ogg" type="audio/ogg">
  Your browser does not support the audio element.
</audio>
@import url("https://fonts.googleapis.com/css2?family=Ranchers&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Nerko+One&display=swap");

// ---------------------------------------
// | resets
// ---------------------------------------
html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-default.png),
    default;
}

// ---------------------------------------
// | room
// ---------------------------------------
.room {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: linear-gradient(147deg, #ff6666 0%, #db3445 74%);
}

// ---------------------------------------
// | floating
// ---------------------------------------
.floating-container {
  z-index: 1;
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: aFloating 2s ease-in-out alternate infinite;
}

// ---------------------------------------
// | pop-up
// ---------------------------------------
.overlay {
  z-index: 100;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-color: rgba(255, 255, 255, 0.35);
  transition: 1s ease-in-out;
  transition-property: opacity, z-index;
  animation: aModal 1s ease-in-out;

  &_state {
    &_disabled {
      z-index: -1;
      opacity: 0;
      animation: none;
    }
  }
}

.modal {
  width: 100%;
  max-width: 280px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%);
  text-align: center;
  background-color: #f5f5f5;
  padding: 20px;
  border-radius: 5px;
  border-bottom: 5px solid rgba(0, 0, 0, 0.15);
  box-shadow: rgba(0, 0, 0, 0.15) 0 4px 4px, rgba(0, 0, 0, 0.15) 0 8px 8px,
    rgba(0, 0, 0, 0.15) 0 16px 16px, rgba(0, 0, 0, 0.15) 0 32px 32px;

  & p {
    font-family: "Nerko One", cursive;
    margin: 0;
    margin-top: 20px;
    font-size: 20px;
    line-height: 120%;
    color: #333;

    & .timer {
      display: inline-block;
      color: #e0455f;
      font-size: 24px;
      margin-top: 8px;
    }
  }

  &__person {
    display: flex;
    align-items: center;

    & .santa {
      background-repeat: no-repeat;
      background-position: center;
      background-size: contain;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/santa.png);
      width: 70px;
      height: 70px;
      border: 3px solid rgba(0, 0, 0, 0.15);
      background-color: rgba(0, 0, 0, 0.05);
      margin-right: 20px;
    }

    & h3 {
      margin: 0;
      font-family: "Ranchers", cursive;
      font-size: 30px;
      color: #009b77;
      text-shadow: 2px 2px 0 #232323;
    }
  }

  &__btn {
    font-family: "Ranchers", cursive;
    display: inline-block;
    margin: 0;
    margin-top: 20px;
    padding: 8px 32px;
    font-size: 20px;
    color: #fff;
    background-color: #e0455f;
    border: 2px solid rgba(0, 0, 0, 0.3);
    border-radius: 10px;
    box-shadow: 4px 4px 0 #333;
    transition: 0.1s ease-in-out;
    transition-property: box-shadow, transform;
    cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-pointer.png),
      pointer;

    &:focus {
      outline: none;
    }

    &:hover,
    &:focus {
      transform: translate(4px, 4px);
      box-shadow: 0 0 0 transparent;
    }
  }
}

// ---------------------------------------
// | sprites
// ---------------------------------------
.spr {
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;

  &_name {
    &_rail {
      width: 90vmin;
      height: 90vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/railway.svg);
      filter: drop-shadow(0 18vmin 3vmin rgba(0, 0, 0, 0.35));
    }

    &_loco {
      width: 4vmin;
      height: 4vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/locomotive.svg);
    }

    &_wagon {
      width: 4vmin;
      height: 4vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/wagon-gift.svg);
    }

    &_tunnel {
      width: 25vmin;
      height: 25vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/tunnel-bottom.svg);
      filter: drop-shadow(10vmin 0 3vmin rgba(0, 0, 0, 0.35));
    }

    &_arrow {
      width: 6vmin;
      height: 6vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/arrow.svg);
      transform: rotateY(180deg);
      transition: 0.35s ease-in-out;
      transition-property: transform;
    }

    &_tree {
      width: 16vmin;
      height: 16vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/decorated-tree.svg);
      animation: aTree 3s ease-in-out alternate infinite;
      filter: drop-shadow(0vmin 1vmin 1vmin rgba(0, 0, 0, 0.6));
    }

    &_gifts {
      width: 6vmin;
      height: 6vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/gifts.svg);
      display: none;
    }

    &_snowman {
      width: 7vmin;
      height: 7vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/snowman.svg);
    }

    &_snowman-dec {
      width: 7vmin;
      height: 7vmin;
      background-image: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/mdrrZPe/snowman-active.png);
      animation: aSnowmanAppear 0.35s ease-in-out;
    }
  }
}

// ---------------------------------------
// | objects and layers
// ---------------------------------------
.obj {
  position: absolute;

  &_type {
    &_btn {
      border: none;
      border-radius: 0;
      padding: 0;
      margin: 0;
      background-color: transparent;
      transition: 0.15s ease-in-out;
      transition-property: filter;
      filter: drop-shadow(0 0 0.3vmin #ff0);
      cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-pointer.png),
        pointer;

      &:focus {
        outline: none;
      }

      &:hover,
      &:focus {
        filter: drop-shadow(0 0 0.4vmin #0f0);
      }
    }
  }

  &_name {
    &_rail {
      z-index: 1;
    }

    &_loco {
      z-index: 2;
      display: none;
    }

    &_wagon {
      z-index: 3;
      display: none;
    }

    &_tunnel {
      z-index: 4;
      transform: translate(-31.5vmin, 11.5vmin);
    }

    &_arrow {
      z-index: 5;
      transform: translate(-5vmin, 5vmin);
    }

    &_tree {
      z-index: 5;
      transform: translate(28vmin, -17vmin);
    }

    &_gifts {
      z-index: 6;
      transform: translate(25vmin, -9vmin);

      &.obj_type_btn {
        cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-default.png),
          default;
      }
    }

    &_snowman {
      z-index: 6;
      transform: translate(-31vmin, 4vmin);
      transition: 0.35s ease-in-out;
      transition-property: filter, opacity;
    }

    &_snowman-dec {
      display: none;
      z-index: 7;
      transform: translate(-31vmin, 3.5vmin);
    }
  }

  &_state {
    &_run {
      &.obj_name_loco {
        display: block;
        animation: aLoco 10s ease-in-out infinite;
      }

      &.obj_name_wagon {
        display: block;
        animation: aWagon 10s ease-in-out infinite;
      }

      &.obj_name_gifts {
        animation: aGiftsBounce 1s ease-in-out;

        &.obj_type_btn {
          cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-pointer.png),
            pointer;
        }
      }

      & .spr_name_gifts {
        display: block;
      }
    }

    &_active {
      &.obj_type_btn {
        cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-default.png),
          default;
      }

      &.obj_name_loco,
      &.obj_name_wagon {
        animation-play-state: paused;
      }

      & .spr_name_loco,
      & .spr_name_wagon {
        opacity: 0;
        animation: aSprZoomOut 1.5s ease-in-out;
      }

      &.obj_name_arrow {
        filter: none;
        animation: aArrowBounce 0.5s ease-in-out;
      }

      & .spr_name_arrow {
        transform: none;
      }

      &.obj_name_gifts {
        &.obj_type_btn {
          filter: none;
          cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-default.png),
            default;
        }
      }

      &.obj_name_snowman {
        opacity: 0;
      }

      &.obj_name_snowman-dec {
        display: block;
      }

      & .spr_name_snowman-dec {
        opacity: 1;
      }
    }
  }
}

// ---------------------------------------
// | animations
// ---------------------------------------
@keyframes aFloating {
  0% {
    transform: translateY(0) translateX(1vmin);
  }
  100% {
    transform: translateY(-1vmin) translateX(-1vmin);
  }
}

@keyframes aModal {
  0% {
    transform: scale(1);
    opacity: 0;
  }
  50% {
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes aLoco {
  0% {
    transform: translate(-27vmin, 11vmin);
  }
  80% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(29vmin, -18vmin);
  }
}

@keyframes aWagon {
  0% {
    transform: translate(-30vmin, 12.5vmin);
  }
  90% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(26vmin, -16.5vmin);
  }
}

@keyframes aSprZoomOut {
  0% {
    opacity: 1;
    transform: rotate(0deg) scale(1);
  }
  15% {
    transform: rotate(-10deg) scale(1.2);
  }
  100% {
    opacity: 0;
    transform: rotate(360deg) scale(0);
  }
}

@keyframes aArrowBounce {
  0% {
    transform: translate(-5vmin, 5vmin) scale(1);
  }
  50% {
    transform: translate(-5vmin, 5vmin) scale(0.8);
  }
  100% {
    transform: translate(-5vmin, 5vmin) scale(1);
  }
}

@keyframes aTree {
  0% {
    transform: skewX(3deg);
  }
  100% {
    transform: skewX(-2deg);
  }
}

@keyframes aGiftsBounce {
  0% {
    opacity: 0;
    transform: translate(25vmin, -9vmin) scale(0);
  }
  50% {
    transform: translate(25vmin, -9vmin) scale(1.3);
  }
  100% {
    opacity: 1;
    transform: translate(25vmin, -9vmin) scale(1);
  }
}

@keyframes aSnowmanAppear {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

// ---------------------------------------
// | customizable snowflake styling
// | by @codeconvey
// ---------------------------------------
.snowflakes {
  color: #fff;
  font-size: 1em;
  font-family: Arial;
  text-shadow: 0 0 1px #000;
}

@keyframes snowflakes-fall {
  0% {
    top: -10%;
  }
  100% {
    top: 100%;
  }
}

@keyframes snowflakes-shake {
  0% {
    transform: translateX(0px);
  }
  50% {
    transform: translateX(80px);
  }
  100% {
    transform: translateX(0px);
  }
}

.snowflake {
  position: fixed;
  top: -10%;
  user-select: none;
  animation-name: snowflakes-fall, snowflakes-shake;
  animation-duration: 10s, 3s;
  animation-timing-function: linear, ease-in-out;
  animation-iteration-count: infinite, infinite;
  animation-play-state: running, running;
}

.snowflake:nth-of-type(0) {
  left: 1%;
  animation-delay: 0s, 0s;
}

.snowflake:nth-of-type(1) {
  left: 10%;
  animation-delay: 1s, 1s;
}

.snowflake:nth-of-type(2) {
  left: 20%;
  animation-delay: 6s, 0.5s;
}

.snowflake:nth-of-type(3) {
  left: 30%;
  animation-delay: 4s, 2s;
}

.snowflake:nth-of-type(4) {
  left: 40%;
  animation-delay: 2s, 2s;
}

.snowflake:nth-of-type(5) {
  left: 50%;
  animation-delay: 8s, 3s;
}

.snowflake:nth-of-type(6) {
  left: 60%;
  animation-delay: 6s, 2s;
}

.snowflake:nth-of-type(7) {
  left: 70%;
  animation-delay: 2.5s, 1s;
}

.snowflake:nth-of-type(8) {
  left: 80%;
  animation-delay: 1s, 0s;
}

.snowflake:nth-of-type(9) {
  left: 90%;
  animation-delay: 3s, 1.5s;
}
// end of snowflakes

// ---------------------------------------
// | play / pause button
// ---------------------------------------
.toggle-song {
  z-index: 1000;
  position: absolute;
  top: 20px;
  left: 20px;
  display: flex;
  align-items: center;

  &__btn {
    border: none;
    background-color: transparent;
    color: #fafafa;
    transition: 0.2s ease-in-out;
    transition-property: transform, opacity;
    cursor: url(https://raw.githubusercontent.com/elsemeow/cdn/main/img/cdpn/gOwYMNR/cursor-pointer.png),
      pointer;

    &:focus {
      outline: none;
    }

    &:hover,
    &:focus {
      transform: translateY(2px);
      opacity: 0.7;
    }
  }

  &__text {
    font-family: "Nerko One", cursive;
    font-size: 14px;
    color: #f1f1f1;
    margin-left: 8px;
    text-shadow: 1px 1px 0 #333;
  }
}

// icons from https://css.gg/
.gg-play-button-o,
.gg-play-pause-o {
  box-sizing: border-box;
  position: relative;
  display: block;
  transform: scale(var(--ggs, 1));
  width: 22px;
  height: 22px;
  border: 2px solid;
  border-radius: 22px;
}

.gg-play-button-o::before {
  content: "";
  display: block;
  box-sizing: border-box;
  position: absolute;
  width: 0;
  height: 10px;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 6px solid;
  top: 4px;
  left: 7px;
}

.gg-play-pause-o::before {
  content: "";
  display: block;
  box-sizing: border-box;
  position: absolute;
  width: 6px;
  height: 6px;
  left: 6px;
  top: 6px;
  border-left: 2px solid;
  border-right: 2px solid;
}
View Compiled
(() => {
  // constants
  const timeEl = document.querySelector(".timer");

  const start = document.querySelector(".js_scr_start");
  const startOverlay = document.querySelector(".overlay_name_start");
  const endOverlay = document.querySelector(".overlay_name_end");

  const arrow = document.querySelector(".obj_name_arrow");
  const loco = document.querySelector(".obj_name_loco");
  const wagon = document.querySelector(".obj_name_wagon");
  const gifts = document.querySelector(".obj_name_gifts");
  const snowman = document.querySelector(".obj_name_snowman");
  const snowmanDec = document.querySelector(".obj_name_snowman-dec");

  const song = document.querySelector("#song");
  const toggleSong = document.querySelector(".toggle-song__btn");

  // sequence of events
  start.addEventListener("click", () => {
    startOverlay.classList.add("overlay_state_disabled");
  });

  arrow.addEventListener("click", () => {
    arrow.classList.add("obj_state_active");
    loco.classList.add("obj_state_run");
    wagon.classList.add("obj_state_run");
  });

  wagon.addEventListener("click", () => {
    loco.classList.add("obj_state_active");
    wagon.classList.add("obj_state_active");
    gifts.classList.add("obj_state_run");
  });

  gifts.addEventListener("click", () => {
    gifts.classList.add("obj_state_active");
    endOverlay.classList.remove("overlay_state_disabled");
  });

  snowman.addEventListener("click", () => {
    snowman.classList.add("obj_state_active");
    snowmanDec.classList.add("obj_state_active");
  });

  // countdown
  const countDownDate = new Date("Jan 1, 2021 00:00:00").getTime();

  let x = setInterval(() => {
    const now = new Date().getTime();
    const distance = countDownDate - now;
    const days = Math.floor(distance / (1000 * 60 * 60 * 24));
    const hours = Math.floor(
      (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
    );
    const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));

    timeEl.innerHTML = ` in ${days}d ${hours}h ${minutes}m`;

    if (distance < 0) {
      clearInterval(x);
      timeEl.innerHTML = " right now";
    }
  }, 1000);

  // song
  song.volume = 0.1;
  song.loop = true;

  toggleSong.addEventListener("click", () => {
    if (song.paused) {
      song.play();
      toggleSong.classList.remove("gg-play-button-o");
      toggleSong.classList.add("gg-play-pause-o");
    } else {
      song.pause();
      toggleSong.classList.remove("gg-play-pause-o");
      toggleSong.classList.add("gg-play-button-o");
    }
  });
})();
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.