diff --git a/android/app/assets/carinha.html b/android/app/assets/carinha.html
index 13b7dd4..1bc7f57 100644
--- a/android/app/assets/carinha.html
+++ b/android/app/assets/carinha.html
@@ -453,7 +453,10 @@ function tracosDoRosto(esc) {
const tracos = [];
if (EXTRAS.boca) {
const forma = r.boca;
- tracos.push({ d: caminhoBoca(forma), largura: BOCA_L * 0.18, cheio: forma === "aberta" });
+ if (r.dormindo) { // dormindo na Matriz: "– _ –"
+ const cx = BOCA[0], cy = BOCA[1] + deslocamentoBoca() + BOCA_L * 0.08, l = BOCA_L * 0.32;
+ tracos.push({ d: 'M ' + (cx - l) + ',' + cy + ' L ' + (cx + l) + ',' + cy, largura: BOCA_L * 0.16 });
+ } else tracos.push({ d: caminhoBoca(forma), largura: BOCA_L * 0.18, cheio: forma === "aberta" });
}
if (EXTRAS.sobrancelhas && !r.dormindo) {
[E1, E2].forEach((c, i) => {
diff --git a/android/app/assets/rosto-motor.js b/android/app/assets/rosto-motor.js
index b0ddb43..be700a9 100644
--- a/android/app/assets/rosto-motor.js
+++ b/android/app/assets/rosto-motor.js
@@ -118,6 +118,11 @@
const h = est.h * p.ry * respira * abre * (1 - amassa * 0.6);
const x = p.cx - w / 2, y = p.cy - h / 2;
c.fillStyle = css(o.cor);
+ if (o.dormindo && !temConteudo) { // dormindo: "–" (olho fechado)
+ const esp = Math.max(2, p.ry * 0.2);
+ caixa(c, p.cx - w * 0.5, p.cy + h * 0.08 - esp / 2, w, esp, esp / 2); c.fill();
+ return;
+ }
if (e.coracao > 0.5) { coracao(c, p.cx, p.cy, Math.min(w, h) * 0.55 * respira); return; }
caixa(c, x, y, w, h, est.r * p.ry * respira);
c.fill();
@@ -227,6 +232,7 @@
if (traco.cheio) bctx.fill(caminho); else bctx.stroke(caminho);
}
desenharMaos(bctx, o, olhos, tela.height / d);
+ desenharZzz(bctx, o, olhos, 1.6); // em LEDs o Z precisa ser maior para ler
bctx.restore();
const px = bctx.getImageData(0, 0, colunas, linhas).data;
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, tela.width, tela.height);
@@ -266,10 +272,12 @@
} else if (estilo.lente) {
olhos.forEach((p, i) => olhoLente(ctx, o, p, estilo, estado[i]));
desenharMaos(ctx, o, olhos, tela.height);
+ desenharZzz(ctx, o, olhos);
} else {
cctx.clearRect(0, 0, camada.width, camada.height);
olhos.forEach((p, i) => olhoPlano(cctx, o, p, estilo, estado[i]));
desenharMaos(cctx, o, olhos, tela.height);
+ desenharZzz(cctx, o, olhos);
ctx.save();
if (estilo.brilho) { ctx.shadowColor = css(o.cor, 0.7); ctx.shadowBlur = Math.min(60, tela.height * 0.05); }
ctx.drawImage(camada, 0, 0);
@@ -388,6 +396,28 @@
}
}
+ // ------------------------------------------------------------------ Zzz
+ function desenharZzz(c, o, olhos, fator) {
+ fator = fator || 1;
+ if (!o.dormindo) return;
+ const d = olhos.slice().sort((a, b) => a.cx - b.cx)[1]; // olho da direita na tela
+ const x0 = d.cx + d.ry * 0.7, y0 = d.cy - d.ry * 0.55;
+ c.save();
+ c.strokeStyle = css(o.cor); c.lineCap = 'round'; c.lineJoin = 'round';
+ for (let i = 0; i < 3; i++) {
+ const k = ((o.t || 0) * 0.32 + i / 3) % 1; // cada Z num ponto do ciclo
+ const tam = d.ry * (0.28 + 0.3 * k) * fator;
+ const x = x0 + d.ry * 0.7 * k + Math.sin(k * Math.PI * 2) * d.ry * 0.08, y = y0 - d.ry * 1.7 * k;
+ c.globalAlpha = Math.min(1, k / 0.15) * (1 - k);
+ c.lineWidth = Math.max(1.5, tam * 0.2);
+ c.beginPath();
+ c.moveTo(x - tam / 2, y - tam / 2); c.lineTo(x + tam / 2, y - tam / 2);
+ c.lineTo(x - tam / 2, y + tam / 2); c.lineTo(x + tam / 2, y + tam / 2);
+ c.stroke();
+ }
+ c.restore();
+ }
+
// --------------------------------------------------------- faixa de baixo
// A parte de baixo da tela vira palco: legenda da conversa, pensando, equalizador e carga.
const faixa = { modo: null, texto: '', t0: null, dur: 0 };
diff --git a/carinha.html b/carinha.html
index 13b7dd4..1bc7f57 100644
--- a/carinha.html
+++ b/carinha.html
@@ -453,7 +453,10 @@ function tracosDoRosto(esc) {
const tracos = [];
if (EXTRAS.boca) {
const forma = r.boca;
- tracos.push({ d: caminhoBoca(forma), largura: BOCA_L * 0.18, cheio: forma === "aberta" });
+ if (r.dormindo) { // dormindo na Matriz: "– _ –"
+ const cx = BOCA[0], cy = BOCA[1] + deslocamentoBoca() + BOCA_L * 0.08, l = BOCA_L * 0.32;
+ tracos.push({ d: 'M ' + (cx - l) + ',' + cy + ' L ' + (cx + l) + ',' + cy, largura: BOCA_L * 0.16 });
+ } else tracos.push({ d: caminhoBoca(forma), largura: BOCA_L * 0.18, cheio: forma === "aberta" });
}
if (EXTRAS.sobrancelhas && !r.dormindo) {
[E1, E2].forEach((c, i) => {
diff --git a/rosto-motor.js b/rosto-motor.js
index b0ddb43..be700a9 100644
--- a/rosto-motor.js
+++ b/rosto-motor.js
@@ -118,6 +118,11 @@
const h = est.h * p.ry * respira * abre * (1 - amassa * 0.6);
const x = p.cx - w / 2, y = p.cy - h / 2;
c.fillStyle = css(o.cor);
+ if (o.dormindo && !temConteudo) { // dormindo: "–" (olho fechado)
+ const esp = Math.max(2, p.ry * 0.2);
+ caixa(c, p.cx - w * 0.5, p.cy + h * 0.08 - esp / 2, w, esp, esp / 2); c.fill();
+ return;
+ }
if (e.coracao > 0.5) { coracao(c, p.cx, p.cy, Math.min(w, h) * 0.55 * respira); return; }
caixa(c, x, y, w, h, est.r * p.ry * respira);
c.fill();
@@ -227,6 +232,7 @@
if (traco.cheio) bctx.fill(caminho); else bctx.stroke(caminho);
}
desenharMaos(bctx, o, olhos, tela.height / d);
+ desenharZzz(bctx, o, olhos, 1.6); // em LEDs o Z precisa ser maior para ler
bctx.restore();
const px = bctx.getImageData(0, 0, colunas, linhas).data;
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, tela.width, tela.height);
@@ -266,10 +272,12 @@
} else if (estilo.lente) {
olhos.forEach((p, i) => olhoLente(ctx, o, p, estilo, estado[i]));
desenharMaos(ctx, o, olhos, tela.height);
+ desenharZzz(ctx, o, olhos);
} else {
cctx.clearRect(0, 0, camada.width, camada.height);
olhos.forEach((p, i) => olhoPlano(cctx, o, p, estilo, estado[i]));
desenharMaos(cctx, o, olhos, tela.height);
+ desenharZzz(cctx, o, olhos);
ctx.save();
if (estilo.brilho) { ctx.shadowColor = css(o.cor, 0.7); ctx.shadowBlur = Math.min(60, tela.height * 0.05); }
ctx.drawImage(camada, 0, 0);
@@ -388,6 +396,28 @@
}
}
+ // ------------------------------------------------------------------ Zzz
+ function desenharZzz(c, o, olhos, fator) {
+ fator = fator || 1;
+ if (!o.dormindo) return;
+ const d = olhos.slice().sort((a, b) => a.cx - b.cx)[1]; // olho da direita na tela
+ const x0 = d.cx + d.ry * 0.7, y0 = d.cy - d.ry * 0.55;
+ c.save();
+ c.strokeStyle = css(o.cor); c.lineCap = 'round'; c.lineJoin = 'round';
+ for (let i = 0; i < 3; i++) {
+ const k = ((o.t || 0) * 0.32 + i / 3) % 1; // cada Z num ponto do ciclo
+ const tam = d.ry * (0.28 + 0.3 * k) * fator;
+ const x = x0 + d.ry * 0.7 * k + Math.sin(k * Math.PI * 2) * d.ry * 0.08, y = y0 - d.ry * 1.7 * k;
+ c.globalAlpha = Math.min(1, k / 0.15) * (1 - k);
+ c.lineWidth = Math.max(1.5, tam * 0.2);
+ c.beginPath();
+ c.moveTo(x - tam / 2, y - tam / 2); c.lineTo(x + tam / 2, y - tam / 2);
+ c.lineTo(x - tam / 2, y + tam / 2); c.lineTo(x + tam / 2, y + tam / 2);
+ c.stroke();
+ }
+ c.restore();
+ }
+
// --------------------------------------------------------- faixa de baixo
// A parte de baixo da tela vira palco: legenda da conversa, pensando, equalizador e carga.
const faixa = { modo: null, texto: '', t0: null, dur: 0 };