From 2dab45604c65efbff4f1e9fb42981c254dce79d1 Mon Sep 17 00:00:00 2001 From: julio Date: Tue, 6 Oct 2026 03:19:58 -0300 Subject: [PATCH] feat(rosto): dormindo com olhos fechados e Zzz subindo Dormindo, os rostos novos mostram os olhos como tracos (-) e tres Z de tamanhos diferentes saem do canto do olho direito, sobem crescendo e somem em ciclo. Na Matriz a boca vira '_' (- _ -) e os Z sao maiores, em LEDs. Co-Authored-By: Claude Opus 5.5 --- android/app/assets/carinha.html | 5 ++++- android/app/assets/rosto-motor.js | 30 ++++++++++++++++++++++++++++++ carinha.html | 5 ++++- rosto-motor.js | 30 ++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) 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 };