Apple Vision Pro UI in JavaScript

Apple Vision Pro UI in JavaScript
Project: Apple Vision PRO - App UI
Author: Gabriele Bessi
Edit Online: View on CodePen
License: MIT

This code provides a ready-to-use HTML template for implementing the Apple Vision Pro UI in your web application. The code includes a parallax effect background, augmented UI elements, and various app icons. Simply integrate this code into your project to achieve an immersive and visually appealing user interface.

Moreover, this coding project utilizes HTML and SVG elements to create a dynamic user interface. Notable components include a sidebar with selectable items, as well as icons representing different applications like notes, app store, Apple TV, music, photos, safari, and settings. The code incorporates animation effects for smooth transitions and visual appeal.

How to Create Apple Vision Pro UI in JavaScript

1. Create the HTML structure for Apple Vision like interface as follows:

<main id="parallax" class="parallax">
  <img src="https://images.unsplash.com/photo-1617978241112-898785df45b9?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2ODY2NTg2ODV8&ixlib=rb-4.0.3&q=85" />
  <div class="agumented-ui">
    <div class="ui">
      <div class="sidebar">
        <div class="selector"></div>
        <svg class="selected" xmlns="http://www.w3.org/2000/svg" width="95" height="84" fill="none" viewBox="0 0 95 84">
          <path fill="none" fill-rule="evenodd" d="m58.651 27.556.024.04-.024-.04Zm.912 36.928-.002.005.004-.005h-.002Z" clip-rule="evenodd" />
          <path fill="currentColor" d="M0 58.584c0 3.242 2.653 5.9 5.9 5.9h53.663c2.592-4.81-.745-11.796-6.7-11.796h-18.32l25.31-43.842c1.624-2.8.68-6.43-2.152-8.053-2.8-1.624-6.43-.68-8.053 2.153l-2.624 4.54-2.625-4.54C42.78.146 39.18-.831 36.346.793c-2.799 1.62-3.776 5.22-2.152 8.053l6.046 10.441-19.29 33.396H5.9c-3.242 0-5.9 2.658-5.9 5.9Zm18.588 21.798c-1.623 2.832-5.253 3.776-8.052 2.152-2.832-1.623-3.777-5.253-2.153-8.052l4.22-7.288c4.749-1.445 8.643-.326 11.683 3.36l-5.698 9.828Z" />
          <path fill="currentColor" fill-rule="evenodd" d="M59.565 64.484h-.002l-.002.005.004-.005Z" clip-rule="evenodd" />
          <path fill="currentColor" d="M88.506 64.484h-8.558l5.782 10.002c1.624 2.832.647 6.434-2.152 8.053-2.833 1.624-6.434.647-8.053-2.152-4.276-7.396-8.077-13.984-11.408-19.757l-.007-.011a7940.194 7940.194 0 0 0-10.417-18.023c-4.928-8.558-1.416-17.111 2.096-20l2.858 4.953.004.008.024.04 1.407 2.44a26119.19 26119.19 0 0 0 13.083 22.651h15.34c3.248 0 5.901 2.657 5.901 5.9a5.896 5.896 0 0 1-5.9 5.896Z" />
        </svg>

        <svg xmlns="http://www.w3.org/2000/svg" width="88" height="95" fill="none" viewBox="0 0 88 95">
          <path fill="currentColor" d="M81.877 58.443 71.72 51.872l3.91-7.09a12.238 12.238 0 0 0 1.44-5.74V27.804a16.091 16.091 0 0 0-2.663-8.9 16.362 16.362 0 0 0-7.162-6 16.58 16.58 0 0 0-9.317-1.136 16.483 16.483 0 0 0-8.422 4.1v65.628h37.668V68.15a11.456 11.456 0 0 0-1.402-5.519 11.61 11.61 0 0 0-3.895-4.188Z" />
          <path fill="currentColor" d="m63.737 63.294-13.555-8.87 5.219-9.568a16.668 16.668 0 0 0 1.922-7.75V21.939A21.955 21.955 0 0 0 35.402 0c-12.076 0-21.9 9.842-21.9 21.938v15.169c-.012 2.7.64 5.36 1.9 7.747l5.247 9.62-13.476 8.82A15.595 15.595 0 0 0 .105 76.376L0 94.41h70.806V76.396a15.602 15.602 0 0 0-7.069-13.102Z" />
        </svg>

        <svg xmlns="http://www.w3.org/2000/svg" width="95" height="91" fill="none" viewBox="0 0 95 91">
          <path fill="currentColor" d="M94.41 66.475 65.838 37.903l11.955-11.955L94.41 42.563v23.912ZM0 52.431l34.378-34.377L94.41 78.086v11.955H0v-37.61Z" />
          <circle cx="58.035" cy="9.224" r="9.224" fill="currentColor" />
        </svg>

      </div>
      <div class="icons">
        <div class="row">
          <div class="app">
            <a href="https://codepen.io/William-Bardon/pen/OJayjwz" target="_blank">
              <img alt="notes" src="https://kingudakuix.github.io/assets/assets/icons/notes.png"></img>
            </a>
          </div>
          <div class="app">
            <a href="https://codepen.io/William-Bardon/pen/OJayjwz" target="_blank">
              <img alt="store" src="https://kingudakuix.github.io/assets/assets/icons/app-store.png"></img>
            </a>
          </div>
        </div>
        <div class="row">
          <div class="app">
            <a href="https://codepen.io/William-Bardon/pen/OJayjwz" target="_blank">
              <img alt="apple-tv" src="https://kingudakuix.github.io/assets/assets/icons/apple-tv.png"></img>
            </a>
          </div>
          <div class="app">
            <a href="https://codepen.io/William-Bardon/pen/OJayjwz" target="_blank">
              <img alt="music" src="https://kingudakuix.github.io/assets/assets/icons/music.png"></img>
            </a>
          </div>
          <div class="app">
            <a href="https://codepen.io/William-Bardon/pen/OJayjwz" target="_blank">
              <img alt="photos" src="https://kingudakuix.github.io/assets/assets/icons/photos.png"></img>
            </a>
          </div>
        </div>
        <div class="row">
          <div class="app">
            <a href="https://codepen.io/William-Bardon/pen/OJayjwz" target="_blank">
              <img alt="safari" src="https://kingudakuix.github.io/assets/assets/icons/safari.png"></img>
            </a>
          </div>
          <div class="app">
            <a href="https://codepen.io/William-Bardon/pen/OJayjwz" target="_blank">
              <img alt="settings" src="https://kingudakuix.github.io/assets/assets/icons/settings.png"></img>
            </a>
          </div>
        </div>
      </div>
    </div>
  </div>
</main>

<div class="logo-wrapper">
  <svg class="logo" xmlns="http://www.w3.org/2000/svg" id="logo" viewBox="0 0 119 90">
    <style>
      #logo {
        overflow: visible;
      }

      #logo path:nth-child(2) {
        animation: logo-child-1 0.55s cubic-bezier(.23, 1.24, .8, 1.06);
      }

      #logo path:nth-child(3) {
        animation: logo-child-2 0.55s cubic-bezier(.23, 1.24, .8, 1.06);
      }

      #logo path:nth-child(4) {
        animation: logo-child-3 0.55s cubic-bezier(.23, 1.24, .8, 1.06);
      }

      #logo path:nth-child(5) {
        animation: logo-child-4 0.55s cubic-bezier(.23, 1.24, .8, 1.06);
      }

      #logo path:nth-child(6) {
        animation: logo-child-5 0.55s cubic-bezier(.23, 1.24, .8, 1.06);
      }

      @keyframes logo-child-1 {
        from {
          transform: translateX(100%);
        }

        to {
          transform: translateY(0%);
        }
      }

      @keyframes logo-child-2 {
        from {
          transform: translateY(-100%);
        }

        to {
          transform: translateY(0%);
        }
      }

      @keyframes logo-child-3 {
        from {
          transform: translateY(100%) translateX(-100%);
        }

        to {
          transform: translateY(0%) translateX(0%);
        }
      }

      @keyframes logo-child-4 {
        from {
          transform: translateY(100%);
        }

        to {
          transform: translateY(0%);
        }
      }

      @keyframes logo-child-5 {
        from {
          transform: translateY(-100%);
        }

        to {
          transform: translateY(0%);
        }
      }
    </style>
    <path fill="currentColor" d="M79.25 89.125v-7.75h8.875c5.833 0 10.625-1.208 14.375-3.625 5.083-3.333 7.625-8.125 7.625-14.375 0-1.167-.083-2.292-.25-3.375-1.333-7.417-6.625-11.125-15.875-11.125H79.25V41.25H94c10.333-.083 15.583-4.833 15.75-14.25 0-2.833-.667-5.583-2-8.25-3.167-6.333-8.75-9.5-16.75-9.5H79.25V1.5h12.625c7.583 0 13.792 2.208 18.625 6.625 5.167 4.833 7.75 11 7.75 18.5 0 1-.042 2-.125 3-.833 6.75-3.667 11.917-8.5 15.5 5.917 4.5 8.917 10.708 9 18.625 0 5.833-1.667 10.958-5 15.375-4.917 6.667-12.042 10-21.375 10h-13Z" class="logo2-right-b" />
    <path fill="currentColor" d="M64.75 1.5V89h8.5V1.5h-8.5Z" class="logo2-left-b" />
    <path fill="currentColor" fill-rule="evenodd" d="M46.598 82.945c.3-.265.602-.538.902-.82 5.167-5 7.75-10.042 7.75-15.125V44.875h-23.5v8h15V65.25c-.076 3.633-1.56 7.025-4.454 10.176l4.302 7.52Z" class="logo2-right-g" clip-rule="evenodd" />
    <path fill="currentColor" d="M.875 23.5V65c.083 8.083 3.375 14.542 9.875 19.375 4.917 3.5 9.917 5.25 15 5.25h6c2.668-.042 5.336-.709 8.004-2l-4.117-7.233c-1.333.572-2.628.858-3.887.858h-6c-1.833 0-4-.625-6.5-1.875C12.75 76.292 9.5 71.5 9.5 65V34.483L1.33 20.13a20.206 20.206 0 0 0-.456 3.37Z" class="logo2-left-g" />
    <path fill="currentColor" d="M25.703.875c-7.5 0-13.708 2.792-18.625 8.375a32.14 32.14 0 0 0-1.574 1.953l4.994 8.727A16.981 16.981 0 0 1 12.703 16c3.25-4.5 7.583-6.75 13-6.75h6c1.667 0 3.583.5 5.75 1.5 5.833 2.833 8.958 7.5 9.375 14 .083.417.125 1.333.125 2.75l8.25-3c0-5.583-2.167-10.792-6.5-15.625-5-5.417-10.667-8.083-17-8h-6Z" class="logo2-top-g" />
  </svg>
  <div class="circle">
    <svg fill="none" viewBox="0 0 100 100">
      <circle strokeDashoffset={360} strokeDasharray={360 + 280 / 100 * percentage} stroke="#fff" cx="50" cy="50" r="48" />
    </svg>
  </div>
</div>

2. Style the interface using the following CSS styles:

*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
/* width */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
/* Track */
::-webkit-scrollbar-track {
  background: #0a0a0a;
}
/* Handle */
::-webkit-scrollbar-thumb {
  background: #ad3955;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
  background: #ad3955;
}
html,
body {
  height: 100%;
  width: 100%;
}
body {
  background: #191919;
  overflow: hidden;
}

.parallax {
  width: 100%;
  height: 100%;
}
.parallax img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: bottom;
}
.parallax > img {
  filter: blur(2px);
}
.agumented-ui {
  position: absolute;
  left: 0;
  bottom: 4rem;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
}
.ui {
  width: 100%;
  max-width: 800px;
  display: flex;
  gap: 5rem;
}
.agumented-ui .sidebar {
  background: rgba(255, 255, 255, 0.35);
  backdrop-filter: blur(10px);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.5rem 0.25rem;
  border-radius: 3rem;
  box-shadow: 2px 2px 8px rgba(155, 155, 155),
    inset 2px 2px 8px rgba(255, 255, 255);
  width: 2.5rem;
  height: fit-content;
  margin: auto 0;
}
.agumented-ui .sidebar svg {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  overflow: hidden;
  position: relative;
  z-index: 2;
  margin: 0 auto;
  cursor: pointer;
  color: #555;
}
.agumented-ui .sidebar svg.selected {
  color: #fff;
}
.selector {
  position: absolute;
  top: 0.25rem;
  left: 0.25rem;
  width: 2rem;
  height: 2rem;
  background: rgba(135, 135, 135);
  box-shadow: 2px 2px 8px rgba(95, 95, 95),
    inset 2px 2px 8px rgba(175, 175, 175);
  border-radius: 50%;
}
.agumented-ui .icons {
  display: flex;
  flex-direction: column;
  gap: 3.5rem;
}
.agumented-ui .icons .row {
  display: flex;
  justify-content: center;
  gap: 3.5rem;
}
.agumented-ui .icons .row .app {
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  background: #ccc;
  box-shadow: 2px 2px 8px #777, inset 2px 2px 8px #eee;
  padding: 0.5rem;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.agumented-ui .icons .row .app img {
  width: 3rem;
  height: 3rem;
}

.logo-wrapper {
  position: fixed;
  bottom: 1rem;
  right: 1rem;
  display: grid;
  place-items: center;
  opacity: 0;
  animation: fade-in 0.8s linear forwards;
}
@keyframes fade-in {
  to {
    opacity: 1;
  }
}
.logo {
  width: 3rem;
  height: auto;
  color: #fff;
}
.circle {
  position: absolute;
  width: 4rem;
  height: 4rem;
  top: 50%;
  left: 50%;
  transform: translate3d(-50%, -50%, 0);
  stroke-dasharray: 52;
  stroke-dashoffset: 40;
  animation: rotate 3s linear infinite;
  filter: drop-shadow(0px 0px 6px #fff);
}
@keyframes rotate {
  from {
    transform: translate3d(-50%, -50%, 0) rotate(0deg);
  }
  to {
    transform: translate3d(-50%, -50%, 0) rotate(360deg);
  }
}

3. Finally, add the following JavaScript code between the <script> tag just before closing the body element to activate the parallax effect.

const parallax = document.getElementById("parallax");
const rect = parallax.getBoundingClientRect();
const icons = document.getElementsByClassName("ui")[0];
const iconsRect = icons.getBoundingClientRect();
var pos = {
  x: 0,
  y: 0
};
var mousePos = {
  x: 0,
  y: 0
};
var iconPos = {
  x: 0,
  y: 0
}
var iconDesiredPos = {
  x: 0,
  y: 0
}
parallax.addEventListener("pointermove", function (e) {
  mousePos = {
    x: e.clientX - rect.left,
    y: e.clientY - rect.top
  };
    
  iconDesiredPos = {
    x: (e.clientX - window.innerWidth / 2) - iconsRect.left,
    y: (e.clientY - window.innerHeight / 2) - iconsRect.top
  }
  /*
  var apps = document.getElementsByClassName("app");
  if (apps.length > 0) {
    for(var i = 0; i < apps.length; i++) {
      var app = apps[i];
      var appRect = app.getBoundingClientRect();
      // Calc distance to point
      var a = mousePos.x - appRect.left;
      var b = mousePos.y - appRect.top;
      var c = Math.sqrt( a*a + b*b );
      console.log("distance", c);
    }
  }
  */
});
function render() {
  pos.x += easing(pos.x, mousePos.x, 0.01);
  pos.y += easing(pos.y, mousePos.y, 0.01);
  parallax.style.transformOrigin = `${pos.x}px ${pos.y}px`;
  parallax.style.transform = `scale(1.25)`;
  
  iconPos.x += easing(iconPos.x, iconDesiredPos.x / -10, 0.01);
  iconPos.y += easing(iconPos.y, iconDesiredPos.y / -10, 0.01);
  icons.style.transform = `translateX(${iconPos.x}px) translateY(${iconPos.y}px)`;
  
  requestAnimationFrame(render);
}
render();
function easing(a, b, speed) {
  return (b - a) * speed;
}

That’s all! hopefully, you have successfully integrated Apple Vision Pro like UI in your JavaScript project. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *