fix(rosto): expressoes e reacoes mantem a cor escolhida

Surpreso, triste e dormindo usavam azuis fixos; agora usam tons da cor
escolhida (mais clara no susto, mais escura e apagada na tristeza e no
sono). Nas reacoes da biblioteca o ciano padrao vira a cor escolhida e o
azul-claro um tom claro dela, no celular e nas miniaturas do painel.
Bravo (vermelho) e coracao (rosa) continuam, pois fazem parte da emocao.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-06 03:26:45 -03:00
co-authored by Claude Opus 5.5
parent 2dab45604c
commit 98c9e8803e
4 changed files with 37 additions and 10 deletions
+10 -4
View File
@@ -98,6 +98,11 @@ const VERM = [255, 78, 78];
const ROSA = [255, 112, 176];
const AMARELO = [255, 218, 96];
const AZUL = [130, 170, 255];
// Tons derivados da cor escolhida no painel (CIANO é trocada pela cor escolhida em tempo real):
// "claro" para susto/surpresa, "escuro" para tristeza e sono. Nada de azul fixo.
const corClara = (k) => CIANO.map((v) => v + (255 - v) * (k === undefined ? 0.4 : k));
const corEscura = (k) => CIANO.map((v) => v * (k === undefined ? 0.62 : k));
function resolverCor(c) { return c === "claro" ? corClara() : c === "escuro" ? corEscura() : c === "escolhida" ? CIANO.slice() : c; }
const VERDE = [120, 255, 160];
const BRANCO = [245, 250, 255];
@@ -302,7 +307,7 @@ function sequencias() {
const olhar_baixo = [[{ dy: 11 }, 0.16], [{}, 0.45], [{ dy: 0 }, 0.2]];
const feliz = [[{ forma: "feliz", esc: 1.05, boca: "sorriso" }, 0.16], [{ esc: 1.16 }, 0.18],
[{ esc: 1.02 }, 0.16], [{ esc: 1.13 }, 0.16], [{ esc: 1.0 }, 0.2]];
const surpreso = [[{ forma: "aberto", esc: 1.3, ab: 1.12, dy: -8, cor: CIANO_E, boca: "aberta" }, 0.09],
const surpreso = [[{ forma: "aberto", esc: 1.3, ab: 1.12, dy: -8, cor: "claro", boca: "aberta" }, 0.09],
[{ dy: -10 }, 0.5],
[{ esc: 1.0, ab: 1.0, dy: 0, cor: CIANO }, 0.25]];
const bravo = [[{ forma: "bravo", cor: VERM, esc: 0.98, boca: "brava" }, 0.1],
@@ -311,7 +316,7 @@ function sequencias() {
const coracao = [[{ forma: "coracao", cor: ROSA, boca: "sorriso" }, 0.12], [{ esc: 1.18 }, 0.15],
[{ esc: 1.0 }, 0.15], [{ esc: 1.18 }, 0.15], [{ esc: 1.0 }, 0.15],
[{ forma: "aberto", cor: CIANO }, 0.3]];
const triste = [[{ forma: "triste", cor: AZUL, dy: 5, boca: "triste" }, 0.18], [{ dy: 7 }, 0.5],
const triste = [[{ forma: "triste", cor: "escuro", dy: 5, boca: "triste" }, 0.18], [{ dy: 7 }, 0.5],
[{ forma: "aberto", cor: CIANO, dy: 0 }, 0.3]];
const piscadinha = [[{ forma2: "dormir", esc: 1.04, boca: "sorriso" }, 0.12], [{ esc: 1.08 }, 0.5],
[{ forma2: "aberto", esc: 1.0 }, 0.18]];
@@ -344,6 +349,7 @@ function proximo() {
const [alvo, dur] = r.fila[0];
r.kf_ini = { ab: r.ab, ab2: r.ab2, esc: r.esc, dx: r.dx, dy: r.dy };
r.cor_ini = r.cor.slice();
if ("cor" in alvo) alvo.cor = resolverCor(alvo.cor); // "claro"/"escuro" viram tons da cor escolhida
if ("forma" in alvo) r.forma = alvo.forma;
if ("forma2" in alvo) r.forma2 = alvo.forma2;
if ("boca" in alvo) r.boca = alvo.boca;
@@ -378,7 +384,7 @@ function passo(dt) { // avanca a fila; true se ha gesto em
function repouso(t) { // pose calma: olha devagar, "respira"
if (r.dormindo) {
r.forma = "dormir"; r.forma2 = "dormir"; r.boca = "sono";
r.cor = lerpCor(AZUL, [40, 60, 120], 0.5 + 0.5 * Math.sin(t * 1.2));
r.cor = lerpCor(corEscura(0.75), corEscura(0.35), 0.5 + 0.5 * Math.sin(t * 1.2)); // respira na cor escolhida
r.ab = 0; r.ab2 = 0;
r.esc = 1.0 + 0.03 * Math.sin(t * 1.4);
r.dx = 0;
@@ -536,7 +542,7 @@ function pose(nome) {
for (const k of ["forma", "forma2", "boca", "esc", "dx", "dy", "ab", "ab2"]) {
if (k in alvo && alvo[k] !== undefined) r[k] = alvo[k];
}
if ("cor" in alvo) r.cor = alvo.cor.slice();
if ("cor" in alvo) r.cor = resolverCor(alvo.cor).slice();
congelado = true;
desenhar();
return true;
+10 -4
View File
@@ -98,6 +98,11 @@ const VERM = [255, 78, 78];
const ROSA = [255, 112, 176];
const AMARELO = [255, 218, 96];
const AZUL = [130, 170, 255];
// Tons derivados da cor escolhida no painel (CIANO é trocada pela cor escolhida em tempo real):
// "claro" para susto/surpresa, "escuro" para tristeza e sono. Nada de azul fixo.
const corClara = (k) => CIANO.map((v) => v + (255 - v) * (k === undefined ? 0.4 : k));
const corEscura = (k) => CIANO.map((v) => v * (k === undefined ? 0.62 : k));
function resolverCor(c) { return c === "claro" ? corClara() : c === "escuro" ? corEscura() : c === "escolhida" ? CIANO.slice() : c; }
const VERDE = [120, 255, 160];
const BRANCO = [245, 250, 255];
@@ -302,7 +307,7 @@ function sequencias() {
const olhar_baixo = [[{ dy: 11 }, 0.16], [{}, 0.45], [{ dy: 0 }, 0.2]];
const feliz = [[{ forma: "feliz", esc: 1.05, boca: "sorriso" }, 0.16], [{ esc: 1.16 }, 0.18],
[{ esc: 1.02 }, 0.16], [{ esc: 1.13 }, 0.16], [{ esc: 1.0 }, 0.2]];
const surpreso = [[{ forma: "aberto", esc: 1.3, ab: 1.12, dy: -8, cor: CIANO_E, boca: "aberta" }, 0.09],
const surpreso = [[{ forma: "aberto", esc: 1.3, ab: 1.12, dy: -8, cor: "claro", boca: "aberta" }, 0.09],
[{ dy: -10 }, 0.5],
[{ esc: 1.0, ab: 1.0, dy: 0, cor: CIANO }, 0.25]];
const bravo = [[{ forma: "bravo", cor: VERM, esc: 0.98, boca: "brava" }, 0.1],
@@ -311,7 +316,7 @@ function sequencias() {
const coracao = [[{ forma: "coracao", cor: ROSA, boca: "sorriso" }, 0.12], [{ esc: 1.18 }, 0.15],
[{ esc: 1.0 }, 0.15], [{ esc: 1.18 }, 0.15], [{ esc: 1.0 }, 0.15],
[{ forma: "aberto", cor: CIANO }, 0.3]];
const triste = [[{ forma: "triste", cor: AZUL, dy: 5, boca: "triste" }, 0.18], [{ dy: 7 }, 0.5],
const triste = [[{ forma: "triste", cor: "escuro", dy: 5, boca: "triste" }, 0.18], [{ dy: 7 }, 0.5],
[{ forma: "aberto", cor: CIANO, dy: 0 }, 0.3]];
const piscadinha = [[{ forma2: "dormir", esc: 1.04, boca: "sorriso" }, 0.12], [{ esc: 1.08 }, 0.5],
[{ forma2: "aberto", esc: 1.0 }, 0.18]];
@@ -344,6 +349,7 @@ function proximo() {
const [alvo, dur] = r.fila[0];
r.kf_ini = { ab: r.ab, ab2: r.ab2, esc: r.esc, dx: r.dx, dy: r.dy };
r.cor_ini = r.cor.slice();
if ("cor" in alvo) alvo.cor = resolverCor(alvo.cor); // "claro"/"escuro" viram tons da cor escolhida
if ("forma" in alvo) r.forma = alvo.forma;
if ("forma2" in alvo) r.forma2 = alvo.forma2;
if ("boca" in alvo) r.boca = alvo.boca;
@@ -378,7 +384,7 @@ function passo(dt) { // avanca a fila; true se ha gesto em
function repouso(t) { // pose calma: olha devagar, "respira"
if (r.dormindo) {
r.forma = "dormir"; r.forma2 = "dormir"; r.boca = "sono";
r.cor = lerpCor(AZUL, [40, 60, 120], 0.5 + 0.5 * Math.sin(t * 1.2));
r.cor = lerpCor(corEscura(0.75), corEscura(0.35), 0.5 + 0.5 * Math.sin(t * 1.2)); // respira na cor escolhida
r.ab = 0; r.ab2 = 0;
r.esc = 1.0 + 0.03 * Math.sin(t * 1.4);
r.dx = 0;
@@ -536,7 +542,7 @@ function pose(nome) {
for (const k of ["forma", "forma2", "boca", "esc", "dx", "dy", "ab", "ab2"]) {
if (k in alvo && alvo[k] !== undefined) r[k] = alvo[k];
}
if ("cor" in alvo) r.cor = alvo.cor.slice();
if ("cor" in alvo) r.cor = resolverCor(alvo.cor).slice();
congelado = true;
desenhar();
return true;
+9 -1
View File
@@ -1,4 +1,12 @@
(function(){
// Cores das receitas: o ciano padrão (#5cd6ff) vira a cor escolhida no painel e o azul-claro
// (#aaccff) um tom mais claro dela; rosa, amarelo e verde continuam (fazem parte da emoção).
function corDaReacao(hex){
const h=String(hex||'').toLowerCase(), base=(typeof CIANO!=='undefined'?CIANO:[92,214,255]);
if(h==='#5cd6ff')return base.slice();
if(h==='#aaccff')return base.map(v=>v+(255-v)*.45);
return [1,3,5].map(i=>parseInt(h.slice(i,i+2),16));
}
const icons={nenhum:'',estrela:'✦',coracao:'♥',musica:'♫',cafe:'☕',ideia:'💡'};
const badge=document.createElement('div');badge.id='reacaoSimbolo';badge.style.cssText='position:fixed;left:5%;top:6%;z-index:15;color:#5cd6ff;font:clamp(30px,7vw,64px) sans-serif;pointer-events:none;white-space:pre-wrap';document.body.append(badge);
let timer,last=null,fetching=false,animation;let particles=[];
@@ -42,7 +50,7 @@
for(const s of recipe.passos)if(!['aberto','feliz','surpreso','coracao','triste'].includes(s.olhos)||!['neutra','sorriso','aberta','triste'].includes(s.boca)||!/^#[0-9a-f]{6}$/i.test(s.cor)||!Number.isFinite(s.duracao)||s.duracao<.15||s.duracao>2||!Number.isFinite(s.dx)||Math.abs(s.dx)>25||!Number.isFinite(s.dy)||Math.abs(s.dy)>12||!Number.isFinite(s.escala)||s.escala<.8||s.escala>1.3)return;
clearTimeout(timer);clearVisual();window.eilik.soltar();trata('acordar');MIC.ultimoSom=performance.now()/1000;
visual(recipe);
r.fila=recipe.passos.map(s=>[{forma:s.olhos,forma2:null,boca:s.boca,cor:[1,3,5].map(i=>parseInt(s.cor.slice(i,i+2),16)),dx:s.dx,dy:s.dy,esc:s.escala,ab:1,ab2:1},s.duracao]);
r.fila=recipe.passos.map(s=>[{forma:s.olhos,forma2:null,boca:s.boca,cor:corDaReacao(s.cor),dx:s.dx,dy:s.dy,esc:s.escala,ab:1,ab2:1},s.duracao]);
r.fila.push([{forma:'aberto',forma2:null,boca:'neutra',cor:CIANO.slice(),dx:0,dy:0,esc:1,ab:1,ab2:1},.4]);proximo();
timer=setTimeout(clearVisual,Math.max(recipe.figurinha?6000:0,['musica','estrela','coracao'].includes(recipe.simbolo)?4500:['ideia','cafe'].includes(recipe.simbolo)?2500:0,recipe.passos.reduce((n,s)=>n+s.duracao,0)*1000+400));
}
+8 -1
View File
@@ -25,6 +25,13 @@
if (['musica', 'estrela', 'coracao'].includes(receita?.simbolo)) return { emoji: SIMBOLO_EMOJI[receita.simbolo] };
return null;
});
// Mesma regra do celular (reacoes-render.js): ciano padrão = cor escolhida; azul-claro = tom claro dela.
function corDaReacao(hex: string | undefined): number[] {
const h = (hex ?? '').toLowerCase(), base = estado.aparencia.cor;
if (!/^#[0-9a-f]{6}$/.test(h) || h === '#5cd6ff') return [...base];
if (h === '#aaccff') return base.map((v) => v + (255 - v) * 0.45);
return rgb(h);
}
const estilo = $derived(ROSTOS_INFO[estado.aparencia.rosto]?.novo ? estado.aparencia.rosto : 'vivo');
$effect(() => {
@@ -36,7 +43,7 @@
motor.retrato(tela, {
estilo,
formato: estado.aparencia.formato ?? 'padrao',
cor: /^#[0-9a-f]{6}$/i.test(passo?.cor ?? '') ? rgb(passo.cor) : estado.aparencia.cor,
cor: corDaReacao(passo?.cor),
forma: passo?.olhos ?? 'aberto',
icone: nosOlhos.icone,
desenho: nosOlhos.desenho ? $state.snapshot(nosOlhos.desenho) : null,