82 lines
2.2 KiB
JavaScript
Executable File
82 lines
2.2 KiB
JavaScript
Executable File
const label = document.getElementById("label");
|
|
const eyes = Array.from(document.querySelectorAll(".eye"));
|
|
const mouthShape = document.querySelector(".mouth-shape");
|
|
|
|
let current = "neutral";
|
|
|
|
function setEmotion(name) {
|
|
const safe = String(name || "neutral")
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9_-]/g, "");
|
|
|
|
current = safe;
|
|
document.body.className = `emotion-${safe}`;
|
|
label.textContent = safe;
|
|
|
|
// Sonderfall: surprised -> O-Mund aktivieren
|
|
if (safe === "surprised") document.body.classList.add("has-omouth");
|
|
else document.body.classList.remove("has-omouth");
|
|
|
|
// sad -> frown pseudo aktivieren (eigene Klasse)
|
|
if (safe === "sad" || safe === "angry") mouthShape.classList.add("frown");
|
|
else mouthShape.classList.remove("frown");
|
|
}
|
|
|
|
/** Pupillen bewegen sich sanft, damit es "lebendig" wirkt */
|
|
function startPupilWander() {
|
|
const tick = () => {
|
|
// kleine zufällige Offsets in Pixel (auf großen Displays reicht das)
|
|
const x = Math.round((Math.random() * 2 - 1) * 10);
|
|
const y = Math.round((Math.random() * 2 - 1) * 8);
|
|
|
|
document.documentElement.style.setProperty("--pupil-x", `${x}px`);
|
|
document.documentElement.style.setProperty("--pupil-y", `${y}px`);
|
|
|
|
// alle 600-1400ms neu
|
|
const next = 600 + Math.random() * 800;
|
|
setTimeout(tick, next);
|
|
};
|
|
tick();
|
|
}
|
|
|
|
/** Blinzeln: in zufälligen Abständen, manchmal doppelt */
|
|
function blinkOnce() {
|
|
eyes.forEach(e => e.classList.add("blink"));
|
|
setTimeout(() => eyes.forEach(e => e.classList.remove("blink")), 120);
|
|
}
|
|
|
|
function startBlinking() {
|
|
const loop = () => {
|
|
// sleepy blinzelt öfter/langsamer, angry etwas "härter"
|
|
let base = 3500;
|
|
if (current === "sleepy") base = 2200;
|
|
if (current === "surprised") base = 4200;
|
|
|
|
const next = base + Math.random() * 2200;
|
|
setTimeout(() => {
|
|
blinkOnce();
|
|
|
|
// 15% chance auf Doppelt-Blink
|
|
if (Math.random() < 0.15) setTimeout(blinkOnce, 220);
|
|
|
|
loop();
|
|
}, next);
|
|
};
|
|
loop();
|
|
}
|
|
|
|
function connect() {
|
|
const es = new EventSource("/events");
|
|
es.addEventListener("emotion", (e) => setEmotion(e.data));
|
|
es.onmessage = (e) => setEmotion(e.data); // fallback
|
|
es.onerror = () => {
|
|
es.close();
|
|
setTimeout(connect, 1000);
|
|
};
|
|
}
|
|
|
|
connect();
|
|
startPupilWander();
|
|
startBlinking();
|
|
|