feat(rosto): motor de palpebras, 4 rostos novos, formato do olho e tela Rosto

- rosto-motor.js: emocoes como posicao de palpebra (cima, inclinacao, baixo)
  com transicao suave; respiracao, sacadas e piscada que achata o olho
- rostos novos Carinha Viva, Bloco, Matriz (LEDs) e Lente (iris/pupila);
  os classicos continuam; emoji/figurinha nos olhos seguem no SVG
- formato do olho (padrao, redondo, pilula, quadrado, largo) para Viva,
  Bloco e Matriz; salvo na aparencia e enviado como ordem "formato X"
- toque na tela do S10: cutucar = susto e risada, deslizar = carinho,
  tocar dormindo acorda
- painel: tela Rosto (celular em destaque, cartoes de rosto, formatos,
  cores, testar emocoes so na previa ou no celular, lista do que ja esta
  pronto); Ao vivo leva a ela; paleta ganha rostos e formatos
- corrige /comando rosto que nao salvava a aparencia

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-06 01:33:56 -03:00
co-authored by Claude Opus 5.5
parent b6b8e2efd5
commit 972dd8dd66
18 changed files with 1054 additions and 95 deletions
+16
View File
@@ -53,6 +53,22 @@ export const favoritos = new Favoritos();
export const gesto = (nome: string) => tentar(() => postar('/comando', { tipo: 'gesto', valor: nome }));
export const rosto = (nome: string) => tentar(() => postar('/comando', { tipo: 'rosto', valor: nome }));
export const cor = (rgb: [number, number, number]) => tentar(() => postar('/comando', { tipo: 'cor', valor: rgb }));
export const formato = (nome: string) => tentar(() => postar('/comando', { tipo: 'formato', valor: nome }));
/** Rostos: os novos usam o motor de pálpebras (rosto-motor.js) e aceitam formato de olho. */
export const ROSTOS_INFO: Record<string, { nome: string; descricao: string; novo: boolean; formato: boolean }> = {
vivo: { nome: 'Carinha Viva', descricao: 'O rosto de sempre com pálpebras, brilho e micro-movimentos.', novo: true, formato: true },
bloco: { nome: 'Bloco', descricao: 'Olhos quadrados que se recortam, estilo robô de mesa.', novo: true, formato: true },
matriz: { nome: 'Matriz', descricao: 'Painel de LEDs retrô; cada olho é feito de pontos.', novo: true, formato: true },
lente: { nome: 'Lente', descricao: 'Íris e pupila que dilata, pálpebras de metal.', novo: true, formato: false },
carinha: { nome: 'Clássico', descricao: 'O desenho original, com boca.', novo: false, formato: false },
miudo: { nome: 'Miúdo', descricao: 'Clássico com olhos menores.', novo: false, formato: false },
eilik: { nome: 'Eilik', descricao: 'Clássico sem boca.', novo: false, formato: false },
};
export const FORMATOS_INFO: Record<string, string> = {
padrao: 'Padrão', redondo: 'Redondo', pilula: 'Pílula', quadrado: 'Quadrado', largo: 'Largo',
};
export const nomeRosto = (id: string) => ROSTOS_INFO[id]?.nome ?? id;
export const recarregarCelular = () =>
tentar(async () => {
const r = await postar<{ mensagem: string }>('/comando', { tipo: 'recarregar' });