Star Wars container
Inspired by the in-game UI in Star Wars Outlaws.
<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>