diff --git a/face/var/www/html/face.js b/face/var/www/html/face.js index f69c6c6..ee79d87 100644 --- a/face/var/www/html/face.js +++ b/face/var/www/html/face.js @@ -26,6 +26,7 @@ const eyeR = document.getElementById("eyeR"); const eyesGroup = document.getElementById("eyesGroup"); const mouth = document.getElementById("mouth"); + const mouthHi = document.getElementById("mouthHi"); // Touch overlay show let overlayTimer = null; @@ -46,6 +47,12 @@ el.setAttribute("stroke-linecap", "round"); } + function applyHighlightStyle(el) { + // Inlay/Highlight wie Vorlage (heller, ohne Stroke) + el.setAttribute("fill", "rgba(230,255,255,0.35)"); + el.setAttribute("stroke", "none"); + } + // Helpers: Ellipse path (absolute, clean) function ellipsePath(cx, cy, rx, ry) { return `M ${cx-rx},${cy} @@ -93,38 +100,90 @@ happy: { - // Eyes: thick, filled, closed (no "eyebrow" look), positioned lower - eyeL: `M 350,308 - Q 395,252 440,308 - Q 395,276 350,308 Z`, + // Augen: Außen-U minus Innen-U (evenodd) -> echtes "U-Modul" wie Vorlage + eyeL: `M 345,230 + Q 395,185 445,230 + L 445,312 + Q 395,285 345,312 + Z + M 368,240 + Q 395,214 422,240 + L 422,296 + Q 395,276 368,296 + Z`, - eyeR: `M 560,308 - Q 605,252 650,308 - Q 605,276 560,308 Z`, + eyeR: `M 555,230 + Q 605,185 655,230 + L 655,312 + Q 605,285 555,312 + Z + M 578,240 + Q 605,214 632,240 + L 632,296 + Q 605,276 578,296 + Z`, + // Mund: Banana-Band (Außen) wie Vorlage (kleiner, bis etwa Augenmitte) + mouth: `M 395,360 + Q 500,344 605,360 + Q 640,410 610,468 + Q 500,520 390,468 + Q 360,410 395,360 + Z`, - // Mouth: smaller + centered (about "up to mid-eye width") - mouth: `M 410,392 - Q 500,475 590,392 - Q 565,452 500,452 - Q 435,452 410,392 Z`, + // Mund-Highlight (Inlay): kleiner, etwas höher + mouthHi: `M 415,382 + Q 500,368 585,382 + Q 610,412 592,446 + Q 500,476 408,446 + Q 390,412 415,382 + Z`, - // Speaking visemes: same style family, not oversized + // Sprechen: gleiche Familie, nur etwas "tiefer" öffnen visemes: [ - `M 410,392 - Q 500,475 590,392 - Q 565,452 500,452 - Q 435,452 410,392 Z`, + `M 395,360 + Q 500,344 605,360 + Q 640,410 610,468 + Q 500,520 390,468 + Q 360,410 395,360 + Z`, - `M 402,384 - Q 500,492 598,384 - Q 570,466 500,466 - Q 430,466 402,384 Z`, + `M 388,354 + Q 500,336 612,354 + Q 652,414 618,484 + Q 500,546 382,484 + Q 348,414 388,354 + Z`, - `M 392,374 - Q 500,512 608,374 - Q 575,484 500,484 - Q 425,484 392,374 Z`, + `M 380,346 + Q 500,328 620,346 + Q 665,420 625,505 + Q 500,575 375,505 + Q 335,420 380,346 + Z`, + ], + + visemesHi: [ + `M 415,382 + Q 500,368 585,382 + Q 610,412 592,446 + Q 500,476 408,446 + Q 390,412 415,382 + Z`, + + `M 410,378 + Q 500,362 590,378 + Q 620,414 600,456 + Q 500,492 400,456 + Q 380,414 410,378 + Z`, + + `M 405,372 + Q 500,354 595,372 + Q 632,418 608,470 + Q 500,510 392,470 + Q 368,418 405,372 + Z`, ], allowLook: false, @@ -294,6 +353,12 @@ function render() { const cfg = ICONS[state.emotion] ?? ICONS.neutral; + // evenodd erlaubt "Aussparungen" (Innenpfade) in Augen/Mund + eyeL.setAttribute("fill-rule", "evenodd"); + eyeR.setAttribute("fill-rule", "evenodd"); + mouth.setAttribute("fill-rule", "evenodd"); + mouthHi.setAttribute("fill-rule", "evenodd");> + applyStyle(eyeL); applyStyle(eyeR); applyStyle(mouth); @@ -304,6 +369,16 @@ const mouthPath = (state.speaking && cfg.visemes) ? cfg.visemes[visemeIndex] : cfg.mouth; mouth.setAttribute("d", mouthPath); + // Highlight/Inlay + if (cfg.mouthHi) { + const mouthHiPath = (state.speaking && cfg.visemesHi) ? cfg.visemesHi[visemeIndex] : cfg.mouthHi; + mouthHi.style.display = ""; + applyHighlightStyle(mouthHi); + mouthHi.setAttribute("d", mouthHiPath); + } else { + mouthHi.style.display = "none"; + } + applyLook(); } diff --git a/face/var/www/html/index.html b/face/var/www/html/index.html index fea1fdd..0a23eb0 100755 --- a/face/var/www/html/index.html +++ b/face/var/www/html/index.html @@ -25,6 +25,7 @@ +