Star Wars container

Inspired by the in-game UI in Star Wars Outlaws.

html #ui
<div id="star-wars-container">
  <span>Quest Completed</span>
  Underworld
</div>

<script>
  function interpolateColor(color, factor) {
    const result = color.slice()
    return `rgba(${result.join(",")},${1 - 0.75 * factor})`
  }

  function animatePulse() {
    const container = document.getElementById("star-wars-container")
    const computedStyle = window.getComputedStyle(container)

    let t = 0
    const animate = () => {
      t = (t + 0.01) % 1
      const factor1 = Math.sin((t % 1) * Math.PI * 2)
      const factor2 = Math.sin(((t + 0.25) % 1) * Math.PI * 2)

      const color = [255, 232, 31] // #FFE81F

      const interpolatedColor1 = interpolateColor(color, Math.max(0, factor1))
      const interpolatedColor2 = interpolateColor(color, Math.max(0, factor2))

      const beforeImage = `url("data:image/svg+xml,%3Csvg width='278' height='8' viewBox='0 0 278 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cline x1='8.74228e-08' y1='1' x2='278' y2='1.00002' stroke='${encodeURIComponent(interpolatedColor2)}' stroke-width='2'/%3E%3Cline x1='7' y1='7' x2='278' y2='7.00002' stroke='${encodeURIComponent(interpolatedColor1)}' stroke-width='2'/%3E%3C/svg%3E")`

      const afterImage = `url("data:image/svg+xml,%3Csvg width='45' height='7' viewBox='0 0 45 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cline y1='1' x2='37' y2='1' stroke='${encodeURIComponent(interpolatedColor1)}' stroke-width='2'/%3E%3Cline y1='6' x2='45' y2='6' stroke='${encodeURIComponent(interpolatedColor2)}' stroke-width='2'/%3E%3C/svg%3E")`

      container.style.setProperty("--before-image", beforeImage)
      container.style.setProperty("--after-image", afterImage)

      requestAnimationFrame(animate)
    }

    requestAnimationFrame(animate)
  }

  document.addEventListener("DOMContentLoaded", animatePulse)
</script>

<style>
  @font-face {
    font-family: Marvin Visions;
    src: url("/fonts/MarvinVisions.woff2") format("woff2");
    font-weight: 20 170;
  }

  body {
    background-color: black;
    color: white;
    font-family: Marvin Visions;
    padding: 80px;
    font-size: 52px;
  }

  span {
    font-size: 0.6em;
    position: absolute;
    top: -0.6em;
    left: calc(48 * (100% / 364));
    background-color: black;
    padding: 0 0.25em;
    color: #ffe81f;
  }

  div {
    width: fit-content;
    aspect-ratio: 364 / 102;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 364 102' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M27.7986 12H352.352C357.865 12 362.083 16.9126 361.248 22.3626L352.991 76.2709C351.87 83.5929 345.572 89 338.164 89H11.9968C6.37723 89 2.13198 83.9071 3.14387 78.3794L13.0438 24.299C14.3479 17.1749 20.5561 12 27.7986 12Z' stroke='%23FFE81F' stroke-width='2'/%3E%3C/svg%3E");
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 1em;
  }

  div::after,
  div::before {
    content: "";
    position: absolute;
    background-repeat: no-repeat;
    background-size: contain;
  }

  div::before {
    aspect-ratio: 278 / 8;
    background-image: var(--before-image);
    bottom: 0;
    left: calc(12 * (100% / 364));
    width: calc(278 * (100% / 364));
  }

  div::after {
    aspect-ratio: 45 / 7;
    background-image: var(--after-image);
    right: calc(12 * (100% / 364));
    top: 0;
    width: calc(45 * (100% / 364));
  }
</style>