Skip to content

Instantly share code, notes, and snippets.

@natemoo-re
Created October 20, 2023 20:06
Show Gist options
  • Save natemoo-re/af5472e5c9a37b6e9790cb9c9b07920a to your computer and use it in GitHub Desktop.
Save natemoo-re/af5472e5c9a37b6e9790cb9c9b07920a to your computer and use it in GitHub Desktop.
Houston component
---
interface Props {
pose?:
| "default"
| "happy"
| "disappointed"
| "shocked"
| "love"
| "grumpy"
| "sad"
| "cry"
| "wink";
theme?: "default" | "mono";
glow?: boolean;
}
const {
pose = "default",
glow = false,
theme = "default",
} = Astro.props;
---
<hey-houston
class:list={{ glow, [`theme-${theme}`]: theme !== "default" }}
pose={pose}
>
<div class="container">
<div class="body">
<div class="face">
<div class="eye" data-shape="circle"></div>
<div class="mouth" data-shape="half-up"></div>
<div class="eye" data-shape="circle"></div>
</div>
</div>
</div>
</hey-houston>
<script>
const poses = {
default: "circle half-up circle",
happy: "half-down half-up half-down",
disappointed: "half-up bar-bottom half-up",
shocked: "circle-stroke bar circle-stroke",
love: "heart half-up heart",
grumpy: "bar-top half-down bar-top",
sad: "circle half-down-bottom circle",
cry: "half-down square half-down",
wink: "circle half-up bar",
};
const eyes = [
"circle",
"half-down",
"circle-small",
"circle-small",
"square",
"circle-stroke",
];
const mouths = [
"circle-small",
"square",
"square-small",
"bar",
"circle-small",
"square-small",
];
const randBetween = (from: number, to: number) =>
from + Math.floor(Math.random() * to);
const lerp = (start: number, end: number, amt: number) =>
(1 - amt) * start + amt * end;
class HeyHouston extends HTMLElement {
private _rect!: DOMRect;
private _handle?: number;
constructor() {
super();
this.onPointerMove = this.onPointerMove.bind(this);
this.onResize = this.onResize.bind(this);
this.onResize();
}
connectedCallback() {
window.addEventListener("resize", this.onResize);
this.addEventListener("pointermove", this.onPointerMove);
}
disconnectedCallback() {
window.removeEventListener("resize", this.onResize);
this.removeEventListener("pointermove", this.onPointerMove);
}
onPointerMove(event: PointerEvent) {
const x = (event.clientX - this._rect.x) / this._rect.width - 0.5;
const y = (event.clientY - this._rect.y) / this._rect.height - 0.5;
const deltaX = 0 - x;
const deltaY = 0 - y;
const rad = Math.atan2(deltaY, deltaX);
let deg = rad * (180 / Math.PI);
deg = deg < 0 ? Math.abs(deg) : deg;
this.style.setProperty("--x", `${x.toPrecision(2)}`);
this.style.setProperty("--y", `${y.toPrecision(2)}`);
this.style.setProperty(
"--deg",
`${lerp(0, -35, Math.abs(deg / 180))}deg`
);
}
onResize() {
this._rect = this.getBoundingClientRect();
}
static get observedAttributes() {
return ["shapes", "pose"];
}
get eye0() {
return this.querySelector(".eye:first-child")! as HTMLElement;
}
get mouth() {
return this.querySelector(".mouth")! as HTMLElement;
}
get eye1() {
return this.querySelector(".eye:last-child")! as HTMLElement;
}
attributeChangedCallback(name: string, oldValue: string, newValue: string) {
if (name === "shapes") {
this.updateShapes(newValue);
}
if (name === "pose") {
const shapes = poses[newValue as keyof typeof poses] ?? poses.default;
this.updateShapes(shapes);
}
}
reset() {
if (this._handle) clearTimeout(this._handle);
this.updateShapes(
poses[(this.getAttribute("pose") as keyof typeof poses) ?? "default"]
);
}
updateShapes(value: string) {
const [eye0, mouth, eye1] = value.split(" ");
this.eye0.dataset.shape = eye0;
this.mouth.dataset.shape = mouth;
this.eye1.dataset.shape = eye1;
}
emote(name: keyof typeof poses) {
const shapes = poses[name] ?? poses.default;
this.updateShapes(shapes);
this._handle = setTimeout(() => {
this.reset();
}, randBetween(1000, 1750));
}
talk() {
const shapes = poses.default;
this.updateShapes(shapes);
let i = 0;
let pace = randBetween(3, 5);
const loop = () => {
i++;
if (i === pace) {
const eye = eyes[randBetween(0, eyes.length - 1)];
this.eye0.dataset.shape = eye;
this.eye1.dataset.shape = eye;
pace = randBetween(3, 5);
i = 0;
}
this.mouth.dataset.shape = mouths[randBetween(0, mouths.length - 1)];
this._handle = setTimeout(() => loop(), randBetween(100, 300));
};
loop();
return {
stop: () => this.reset(),
};
}
think() {
this.classList.add("active");
this.classList.add("loading");
return {
stop: () => {
this.classList.remove("loading");
},
};
}
}
customElements.define("hey-houston", HeyHouston);
</script>
<style>
hey-houston {
--scale: 1;
--size: calc(
clamp(6.25rem, calc(3.75rem + 12.5vw), 13.75rem) * var(--scale)
);
--border-width: calc(
clamp(0.31rem, calc(0.21rem + 0.52vw), 0.63rem) * var(--scale)
);
--border-color: conic-gradient(
from var(--deg, 0deg) at 50% 50%,
#3245ff 0deg,
#bc52ee 102deg,
#4af2c8 150deg,
#4af2c8 200deg,
#3245ff 360deg
);
--body-color: radial-gradient(
80% 80% at 50% 37.5%,
#191c24 33%,
#111218 67%,
#040506 100%
);
color: white;
position: relative;
aspect-ratio: 128 / 96;
width: var(--size);
margin-top: 6rem;
transition: transform 600ms cubic-bezier(0.23, 1, 0.32, 1), margin-top 600ms cubic-bezier(0.23, 1, 0.32, 1);
--border-squircle: polygon(
100% 50%,
100% 68.2%,
100% 71.6%,
100% 73.9%,
100% 75.7%,
100% 77.2%,
99.9% 78.4%,
99.9% 79.5%,
99.9% 80.5%,
99.8% 81.4%,
99.8% 82.3%,
99.8% 83%,
99.7% 83.8%,
99.7% 84.4%,
99.6% 85.1%,
99.6% 85.7%,
99.5% 86.2%,
99.4% 86.8%,
99.4% 87.3%,
99.3% 87.8%,
99.2% 88.2%,
99.1% 88.7%,
99.1% 89.1%,
99% 89.5%,
98.9% 89.9%,
98.8% 90.3%,
98.7% 90.7%,
98.6% 91%,
98.5% 91.4%,
98.4% 91.7%,
98.2% 92%,
98.1% 92.4%,
98% 92.7%,
97.8% 93%,
97.7% 93.2%,
97.6% 93.5%,
97.4% 93.8%,
97.3% 94%,
97.1% 94.3%,
96.9% 94.5%,
96.8% 94.8%,
96.6% 95%,
96.4% 95.2%,
96.2% 95.4%,
96% 95.6%,
95.9% 95.9%,
95.6% 96%,
95.4% 96.2%,
95.2% 96.4%,
95% 96.6%,
94.8% 96.8%,
94.5% 96.9%,
94.3% 97.1%,
94% 97.3%,
93.8% 97.4%,
93.5% 97.6%,
93.2% 97.7%,
93% 97.8%,
92.7% 98%,
92.4% 98.1%,
92% 98.2%,
91.7% 98.4%,
91.4% 98.5%,
91% 98.6%,
90.7% 98.7%,
90.3% 98.8%,
89.9% 98.9%,
89.5% 99%,
89.1% 99.1%,
88.7% 99.1%,
88.2% 99.2%,
87.8% 99.3%,
87.3% 99.4%,
86.8% 99.4%,
86.2% 99.5%,
85.7% 99.6%,
85.1% 99.6%,
84.4% 99.7%,
83.8% 99.7%,
83% 99.8%,
82.3% 99.8%,
81.4% 99.8%,
80.5% 99.9%,
79.5% 99.9%,
78.4% 99.9%,
77.2% 100%,
75.7% 100%,
73.9% 100%,
71.6% 100%,
68.2% 100%,
50% 100%,
31.8% 100%,
28.4% 100%,
26.1% 100%,
24.3% 100%,
22.8% 100%,
21.6% 99.9%,
20.5% 99.9%,
19.5% 99.9%,
18.6% 99.8%,
17.7% 99.8%,
17% 99.8%,
16.2% 99.7%,
15.6% 99.7%,
14.9% 99.6%,
14.3% 99.6%,
13.8% 99.5%,
13.2% 99.4%,
12.7% 99.4%,
12.2% 99.3%,
11.8% 99.2%,
11.3% 99.1%,
10.9% 99.1%,
10.5% 99%,
10.1% 98.9%,
9.7% 98.8%,
9.3% 98.7%,
9% 98.6%,
8.6% 98.5%,
8.3% 98.4%,
8% 98.2%,
7.6% 98.1%,
7.3% 98%,
7% 97.8%,
6.8% 97.7%,
6.5% 97.6%,
6.2% 97.4%,
6% 97.3%,
5.7% 97.1%,
5.5% 96.9%,
5.2% 96.8%,
5% 96.6%,
4.8% 96.4%,
4.6% 96.2%,
4.4% 96%,
4.1% 95.9%,
4% 95.6%,
3.8% 95.4%,
3.6% 95.2%,
3.4% 95%,
3.2% 94.8%,
3.1% 94.5%,
2.9% 94.3%,
2.7% 94%,
2.6% 93.8%,
2.4% 93.5%,
2.3% 93.2%,
2.2% 93%,
2% 92.7%,
1.9% 92.4%,
1.8% 92%,
1.6% 91.7%,
1.5% 91.4%,
1.4% 91%,
1.3% 90.7%,
1.2% 90.3%,
1.1% 89.9%,
1% 89.5%,
0.9% 89.1%,
0.9% 88.7%,
0.8% 88.2%,
0.7% 87.8%,
0.6% 87.3%,
0.6% 86.8%,
0.5% 86.2%,
0.4% 85.7%,
0.4% 85.1%,
0.3% 84.4%,
0.3% 83.8%,
0.2% 83%,
0.2% 82.3%,
0.2% 81.4%,
0.1% 80.5%,
0.1% 79.5%,
0.1% 78.4%,
0% 77.2%,
0% 75.7%,
0% 73.9%,
0% 71.6%,
0% 68.2%,
0% 50%,
0% 31.8%,
0% 28.4%,
0% 26.1%,
0% 24.3%,
0% 22.8%,
0.1% 21.6%,
0.1% 20.5%,
0.1% 19.5%,
0.2% 18.6%,
0.2% 17.7%,
0.2% 17%,
0.3% 16.2%,
0.3% 15.6%,
0.4% 14.9%,
0.4% 14.3%,
0.5% 13.8%,
0.6% 13.2%,
0.6% 12.7%,
0.7% 12.2%,
0.8% 11.8%,
0.9% 11.3%,
0.9% 10.9%,
1% 10.5%,
1.1% 10.1%,
1.2% 9.7%,
1.3% 9.3%,
1.4% 9%,
1.5% 8.6%,
1.6% 8.3%,
1.8% 8%,
1.9% 7.6%,
2% 7.3%,
2.2% 7%,
2.3% 6.8%,
2.4% 6.5%,
2.6% 6.2%,
2.7% 6%,
2.9% 5.7%,
3.1% 5.5%,
3.2% 5.2%,
3.4% 5%,
3.6% 4.8%,
3.8% 4.6%,
4% 4.4%,
4.1% 4.1%,
4.4% 4%,
4.6% 3.8%,
4.8% 3.6%,
5% 3.4%,
5.2% 3.2%,
5.5% 3.1%,
5.7% 2.9%,
6% 2.7%,
6.2% 2.6%,
6.5% 2.4%,
6.8% 2.3%,
7% 2.2%,
7.3% 2%,
7.6% 1.9%,
8% 1.8%,
8.3% 1.6%,
8.6% 1.5%,
9% 1.4%,
9.3% 1.3%,
9.7% 1.2%,
10.1% 1.1%,
10.5% 1%,
10.9% 0.9%,
11.3% 0.9%,
11.8% 0.8%,
12.2% 0.7%,
12.7% 0.6%,
13.2% 0.6%,
13.8% 0.5%,
14.3% 0.4%,
14.9% 0.4%,
15.6% 0.3%,
16.2% 0.3%,
17% 0.2%,
17.7% 0.2%,
18.6% 0.2%,
19.5% 0.1%,
20.5% 0.1%,
21.6% 0.1%,
22.8% 0%,
24.3% 0%,
26.1% 0%,
28.4% 0%,
31.8% 0%,
50% 0%,
68.2% 0%,
71.6% 0%,
73.9% 0%,
75.7% 0%,
77.2% 0%,
78.4% 0.1%,
79.5% 0.1%,
80.5% 0.1%,
81.4% 0.2%,
82.3% 0.2%,
83% 0.2%,
83.8% 0.3%,
84.4% 0.3%,
85.1% 0.4%,
85.7% 0.4%,
86.2% 0.5%,
86.8% 0.6%,
87.3% 0.6%,
87.8% 0.7%,
88.2% 0.8%,
88.7% 0.9%,
89.1% 0.9%,
89.5% 1%,
89.9% 1.1%,
90.3% 1.2%,
90.7% 1.3%,
91% 1.4%,
91.4% 1.5%,
91.7% 1.6%,
92% 1.8%,
92.4% 1.9%,
92.7% 2%,
93% 2.2%,
93.2% 2.3%,
93.5% 2.4%,
93.8% 2.6%,
94% 2.7%,
94.3% 2.9%,
94.5% 3.1%,
94.8% 3.2%,
95% 3.4%,
95.2% 3.6%,
95.4% 3.8%,
95.6% 4%,
95.9% 4.1%,
96% 4.4%,
96.2% 4.6%,
96.4% 4.8%,
96.6% 5%,
96.8% 5.2%,
96.9% 5.5%,
97.1% 5.7%,
97.3% 6%,
97.4% 6.2%,
97.6% 6.5%,
97.7% 6.8%,
97.8% 7%,
98% 7.3%,
98.1% 7.6%,
98.2% 8%,
98.4% 8.3%,
98.5% 8.6%,
98.6% 9%,
98.7% 9.3%,
98.8% 9.7%,
98.9% 10.1%,
99% 10.5%,
99.1% 10.9%,
99.1% 11.3%,
99.2% 11.8%,
99.3% 12.2%,
99.4% 12.7%,
99.4% 13.2%,
99.5% 13.8%,
99.6% 14.3%,
99.6% 14.9%,
99.7% 15.6%,
99.7% 16.2%,
99.8% 17%,
99.8% 17.7%,
99.8% 18.6%,
99.9% 19.5%,
99.9% 20.5%,
99.9% 21.6%,
100% 22.8%,
100% 24.3%,
100% 26.1%,
100% 28.4%,
100% 31.8%,
100% 0
);
--border-squircle-inner: polygon(
100% 50%,
100% 72.3%,
100% 75.6%,
100% 77.7%,
100% 79.4%,
100% 80.7%,
99.9% 81.8%,
99.9% 82.8%,
99.9% 83.7%,
99.9% 84.5%,
99.8% 85.2%,
99.8% 85.9%,
99.8% 86.5%,
99.7% 87.1%,
99.7% 87.6%,
99.7% 88.2%,
99.6% 88.6%,
99.6% 89.1%,
99.5% 89.5%,
99.4% 89.9%,
99.4% 90.3%,
99.3% 90.7%,
99.2% 91.1%,
99.2% 91.4%,
99.1% 91.8%,
99% 92.1%,
98.9% 92.4%,
98.9% 92.7%,
98.8% 93%,
98.7% 93.3%,
98.6% 93.5%,
98.5% 93.8%,
98.4% 94%,
98.3% 94.3%,
98.2% 94.5%,
98% 94.7%,
97.9% 95%,
97.8% 95.2%,
97.7% 95.4%,
97.5% 95.6%,
97.4% 95.8%,
97.3% 96%,
97.1% 96.1%,
97% 96.3%,
96.8% 96.5%,
96.7% 96.7%,
96.5% 96.8%,
96.3% 97%,
96.1% 97.1%,
96% 97.3%,
95.8% 97.4%,
95.6% 97.5%,
95.4% 97.7%,
95.2% 97.8%,
95% 97.9%,
94.7% 98%,
94.5% 98.2%,
94.3% 98.3%,
94% 98.4%,
93.8% 98.5%,
93.5% 98.6%,
93.3% 98.7%,
93% 98.8%,
92.7% 98.9%,
92.4% 98.9%,
92.1% 99%,
91.8% 99.1%,
91.4% 99.2%,
91.1% 99.2%,
90.7% 99.3%,
90.3% 99.4%,
89.9% 99.4%,
89.5% 99.5%,
89.1% 99.6%,
88.6% 99.6%,
88.2% 99.7%,
87.6% 99.7%,
87.1% 99.7%,
86.5% 99.8%,
85.9% 99.8%,
85.2% 99.8%,
84.5% 99.9%,
83.7% 99.9%,
82.8% 99.9%,
81.8% 99.9%,
80.7% 100%,
79.4% 100%,
77.7% 100%,
75.6% 100%,
72.3% 100%,
50% 100%,
27.7% 100%,
24.4% 100%,
22.3% 100%,
20.6% 100%,
19.3% 100%,
18.2% 99.9%,
17.2% 99.9%,
16.3% 99.9%,
15.5% 99.9%,
14.8% 99.8%,
14.1% 99.8%,
13.5% 99.8%,
12.9% 99.7%,
12.4% 99.7%,
11.8% 99.7%,
11.4% 99.6%,
10.9% 99.6%,
10.5% 99.5%,
10.1% 99.4%,
9.7% 99.4%,
9.3% 99.3%,
8.9% 99.2%,
8.6% 99.2%,
8.2% 99.1%,
7.9% 99%,
7.6% 98.9%,
7.3% 98.9%,
7% 98.8%,
6.7% 98.7%,
6.5% 98.6%,
6.2% 98.5%,
6% 98.4%,
5.7% 98.3%,
5.5% 98.2%,
5.3% 98%,
5% 97.9%,
4.8% 97.8%,
4.6% 97.7%,
4.4% 97.5%,
4.2% 97.4%,
4% 97.3%,
3.9% 97.1%,
3.7% 97%,
3.5% 96.8%,
3.3% 96.7%,
3.2% 96.5%,
3% 96.3%,
2.9% 96.1%,
2.7% 96%,
2.6% 95.8%,
2.5% 95.6%,
2.3% 95.4%,
2.2% 95.2%,
2.1% 95%,
2% 94.7%,
1.8% 94.5%,
1.7% 94.3%,
1.6% 94%,
1.5% 93.8%,
1.4% 93.5%,
1.3% 93.3%,
1.2% 93%,
1.1% 92.7%,
1.1% 92.4%,
1% 92.1%,
0.9% 91.8%,
0.8% 91.4%,
0.8% 91.1%,
0.7% 90.7%,
0.6% 90.3%,
0.6% 89.9%,
0.5% 89.5%,
0.4% 89.1%,
0.4% 88.6%,
0.3% 88.2%,
0.3% 87.6%,
0.3% 87.1%,
0.2% 86.5%,
0.2% 85.9%,
0.2% 85.2%,
0.1% 84.5%,
0.1% 83.7%,
0.1% 82.8%,
0.1% 81.8%,
0% 80.7%,
0% 79.4%,
0% 77.7%,
0% 75.6%,
0% 72.3%,
0% 50%,
0% 27.7%,
0% 24.4%,
0% 22.3%,
0% 20.6%,
0% 19.3%,
0.1% 18.2%,
0.1% 17.2%,
0.1% 16.3%,
0.1% 15.5%,
0.2% 14.8%,
0.2% 14.1%,
0.2% 13.5%,
0.3% 12.9%,
0.3% 12.4%,
0.3% 11.8%,
0.4% 11.4%,
0.4% 10.9%,
0.5% 10.5%,
0.6% 10.1%,
0.6% 9.7%,
0.7% 9.3%,
0.8% 8.9%,
0.8% 8.6%,
0.9% 8.2%,
1% 7.9%,
1.1% 7.6%,
1.1% 7.3%,
1.2% 7%,
1.3% 6.7%,
1.4% 6.5%,
1.5% 6.2%,
1.6% 6%,
1.7% 5.7%,
1.8% 5.5%,
2% 5.3%,
2.1% 5%,
2.2% 4.8%,
2.3% 4.6%,
2.5% 4.4%,
2.6% 4.2%,
2.7% 4%,
2.9% 3.9%,
3% 3.7%,
3.2% 3.5%,
3.3% 3.3%,
3.5% 3.2%,
3.7% 3%,
3.9% 2.9%,
4% 2.7%,
4.2% 2.6%,
4.4% 2.5%,
4.6% 2.3%,
4.8% 2.2%,
5% 2.1%,
5.3% 2%,
5.5% 1.8%,
5.7% 1.7%,
6% 1.6%,
6.2% 1.5%,
6.5% 1.4%,
6.7% 1.3%,
7% 1.2%,
7.3% 1.1%,
7.6% 1.1%,
7.9% 1%,
8.2% 0.9%,
8.6% 0.8%,
8.9% 0.8%,
9.3% 0.7%,
9.7% 0.6%,
10.1% 0.6%,
10.5% 0.5%,
10.9% 0.4%,
11.4% 0.4%,
11.8% 0.3%,
12.4% 0.3%,
12.9% 0.3%,
13.5% 0.2%,
14.1% 0.2%,
14.8% 0.2%,
15.5% 0.1%,
16.3% 0.1%,
17.2% 0.1%,
18.2% 0.1%,
19.3% 0%,
20.6% 0%,
22.3% 0%,
24.4% 0%,
27.7% 0%,
50% 0%,
72.3% 0%,
75.6% 0%,
77.7% 0%,
79.4% 0%,
80.7% 0%,
81.8% 0.1%,
82.8% 0.1%,
83.7% 0.1%,
84.5% 0.1%,
85.2% 0.2%,
85.9% 0.2%,
86.5% 0.2%,
87.1% 0.3%,
87.6% 0.3%,
88.2% 0.3%,
88.6% 0.4%,
89.1% 0.4%,
89.5% 0.5%,
89.9% 0.6%,
90.3% 0.6%,
90.7% 0.7%,
91.1% 0.8%,
91.4% 0.8%,
91.8% 0.9%,
92.1% 1%,
92.4% 1.1%,
92.7% 1.1%,
93% 1.2%,
93.3% 1.3%,
93.5% 1.4%,
93.8% 1.5%,
94% 1.6%,
94.3% 1.7%,
94.5% 1.8%,
94.7% 2%,
95% 2.1%,
95.2% 2.2%,
95.4% 2.3%,
95.6% 2.5%,
95.8% 2.6%,
96% 2.7%,
96.1% 2.9%,
96.3% 3%,
96.5% 3.2%,
96.7% 3.3%,
96.8% 3.5%,
97% 3.7%,
97.1% 3.9%,
97.3% 4%,
97.4% 4.2%,
97.5% 4.4%,
97.7% 4.6%,
97.8% 4.8%,
97.9% 5%,
98% 5.3%,
98.2% 5.5%,
98.3% 5.7%,
98.4% 6%,
98.5% 6.2%,
98.6% 6.5%,
98.7% 6.7%,
98.8% 7%,
98.9% 7.3%,
98.9% 7.6%,
99% 7.9%,
99.1% 8.2%,
99.2% 8.6%,
99.2% 8.9%,
99.3% 9.3%,
99.4% 9.7%,
99.4% 10.1%,
99.5% 10.5%,
99.6% 10.9%,
99.6% 11.4%,
99.7% 11.8%,
99.7% 12.4%,
99.7% 12.9%,
99.8% 13.5%,
99.8% 14.1%,
99.8% 14.8%,
99.9% 15.5%,
99.9% 16.3%,
99.9% 17.2%,
99.9% 18.2%,
100% 19.3%,
100% 20.6%,
100% 22.3%,
100% 24.4%,
100% 27.7%,
100% 0
);
}
.theme-mono {
--border-color: white;
--body-color: #17191e;
}
hey-houston::before,
.glow::after {
content: "";
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
aspect-ratio: 128 / 96;
width: var(--size);
background: var(--border-color);
clip-path: var(--border-squircle);
animation: floating 6s 0.3s ease-in-out infinite;
}
.glow::after {
filter: blur(12px);
border-radius: calc(var(--border-width) * 3);
clip-path: initial;
z-index: -1;
opacity: 0.8;
}
.container {
display: flex;
align-items: center;
justify-content: center;
aspect-ratio: 128 / 96;
width: var(--size);
background: var(--border-color);
clip-path: var(--border-squircle);
animation: floating 6s cubic-bezier(0.76, 0, 0.24, 1) infinite;
}
@keyframes floating {
from,
to {
transform: translateY(0);
}
50% {
transform: translateY(calc(var(--border-width) * -1.5));
}
}
@keyframes fade {
from,
to {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
hey-houston * {
box-sizing: border-box;
}
hey-houston[theme="simple"] {
background: black;
}
hey-houston[theme="simple"] .body {
background: none;
}
.body {
display: flex;
aspect-ratio: 132 / 96;
width: calc(100% - calc(var(--border-width) * 2));
background: var(--body-color);
clip-path: var(--border-squircle-inner);
}
.face {
display: grid;
grid-template-columns: repeat(3, 1fr);
align-items: center;
aspect-ratio: 102 / 34;
height: 40%;
margin: auto auto 12.5%;
transform: translate(0, 0);
transition: transform 500ms cubic-bezier(0.23, 1, 0.32, 1);
}
[pose="cry"] .eye {
z-index: 1;
border: 0;
background: linear-gradient(to bottom, #3245ff, #4af2c8);
}
[pose="cry"] .eye::before {
content: "";
display: block;
position: relative;
width: calc(100% - var(--border-width));
height: calc(var(--border-width) * 8);
margin: 0 auto;
}
[pose="cry"] .eye::after {
content: "";
display: block;
position: absolute;
top: 0;
width: calc(100% - calc(var(--border-width) * 2));
height: var(--border-width);
margin: 0 auto;
border: var(--border-width) solid currentColor;
border-top-left-radius: 999px;
border-top-right-radius: 999px;
border-bottom: 0;
}
[pose="cry"] .mouth {
align-self: flex-start;
}
hey-houston:hover .face {
transform: translate(calc(var(--x) * 5%), calc(var(--y) * 25%));
}
hey-houston.active {
margin: -1rem 0 -1rem 0;
transform: scale(0.5);
}
.loading .face {
--delay: 175ms;
transform: translate(0, -25%);
}
.loading :is(.eye, .mouth) {
all: initial;
aspect-ratio: 1;
background: white;
margin: 17.5% auto;
width: calc(var(--border-width) * 2);
border-radius: calc(var(--border-width) / 4);
animation: floating 1s cubic-bezier(0.76, 0, 0.24, 1) infinite,
fade 1s ease-in-out infinite;
}
.loading :is(.eye:first-child) {
animation-delay: 0;
}
.loading :is(.mouth) {
animation-delay: calc(var(--delay) * 1);
}
.loading :is(.eye:last-child) {
animation-delay: calc(var(--delay) * 2);
}
.eye,
.mouth {
position: relative;
aspect-ratio: 1;
background: currentColor;
margin: 17.5%;
}
[data-shape^="circle"] {
border-radius: 50%;
}
[data-shape="heart"] {
background: none;
background-image: url("data:image/svg+xml,%3Csvg width='27' height='24' viewBox='0 0 27 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M26.3955 7.60322C26.3955 3.7173 23.246 0.568848 19.3611 0.568848C17.0029 0.568848 14.9219 1.73245 13.6455 3.51147C12.3692 1.73245 10.2871 0.568848 7.92988 0.568848C4.045 0.568848 0.895508 3.7173 0.895508 7.60322C0.895508 8.15244 0.964807 8.68822 1.08479 9.20124C2.06221 15.2696 8.80905 21.674 13.6455 23.4313C18.4809 21.674 25.2298 15.2696 26.2042 9.20331C26.3252 8.68822 26.3955 8.15244 26.3955 7.60322Z' fill='white'/%3E%3C/svg%3E%0A");
background-size: 100% 100%;
transform: scale(1.25);
}
[data-shape^="circle-stroke"] {
background: none;
border: calc(var(--border-width) * 0.67) solid currentColor;
}
[data-shape^="bar"] {
aspect-ratio: 80 / 24;
border-radius: calc(var(--border-width) / 2);
}
[data-shape^="square"] {
border-radius: calc(var(--border-width) / 2);
transform: scale(0.9);
}
[data-shape$="small"] {
transform: scale(0.55);
}
[data-shape^="half"] {
aspect-ratio: 2 / 1;
background: none;
border: calc(var(--border-width) * 0.67) solid currentColor;
}
[data-shape^="half-up"] {
border-bottom-left-radius: 999px;
border-bottom-right-radius: 999px;
border-top: 0;
align-self: flex-end;
}
[data-shape^="half-down"] {
border-top-left-radius: 999px;
border-top-right-radius: 999px;
border-bottom: 0;
align-self: flex-start;
}
[data-shape$="top"] {
align-self: flex-start;
}
[data-shape$="bottom"] {
align-self: flex-end;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment