feat(rosto): atividades (momentos dele) e seis gestos novos

Atividades: a tela se divide, o rosto vai para a esquerda e encolhe, e
à direita um bonequinho do Carinha (silhueta na cor dos olhos) faz algo:
ler (vira a página), cantar (microfone e notas), jogar bola
(embaixadinha), videogame (TV com joguinho), pintar (cavalete que ganha
pinceladas) e malhar (halteres e suor). Os olhos grandes acompanham:
leem as linhas, seguem a bola, olham a TV. Camada própria atrás dos
olhos, vale para todos os rostos; em pé (retrato) a cena vai para baixo.

- Comando {tipo: "atividade", valor: nome|parar}; toque na tela, dormir
  e E-Stop encerram; o celular informa a atividade na telemetria.
- Modo vida escolhe pelo humor (feliz canta e joga bola, tranquilo lê
  e pinta, entediado joga videogame), nunca de madrugada, e não
  interrompe uma atividade em andamento.
- Gestos novos: rir, comemorar, tímido, confuso, bocejar e tonto; o
  humor e o modo vida também os usam.
- Painel: favoritos vão até 20 e o bravo volta junto com os novos;
  botões de atividade no Ao vivo, no Ctrl+K e tópico no guia.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-06 21:12:14 -03:00
co-authored by Claude Opus 5.5
parent 48fd51e377
commit d7a17b5683
13 changed files with 895 additions and 36 deletions
+16 -2
View File
@@ -54,7 +54,10 @@ FORMATOS = ["padrao", "redondo", "pilula", "quadrado", "largo"]
GESTOS = ["piscar", "piscar2", "olhar_esq", "olhar_dir", "olhar_baixo", "feliz",
"surpreso", "bravo", "coracao", "triste", "piscadinha", "alegre",
"dormir", "acordar", "aleatorio", "parar",
"esconder", "espiar", "acenar", "pensar", "musica"]
"esconder", "espiar", "acenar", "pensar", "musica",
"rir", "bocejar", "confuso", "tonto", "timido", "comemorar"]
# Atividades (momentos dele): o bonequinho faz algo embaixo dos olhos (rosto-motor.js).
ATIVIDADES = ["ler", "cantar", "bola", "videogame", "pintar", "malhar"]
# Ordens internas que o rosto entende mas não viram botão.
ORDENS_INTERNAS = {"calma"}
@@ -187,6 +190,11 @@ def ordem_de_comando(tipo, valor):
if nome not in GESTOS and nome not in ORDENS_INTERNAS:
raise ValueError("Gesto desconhecido: " + nome)
return nome
if tipo == "atividade":
nome = str(valor or "").strip().lower()
if nome not in ATIVIDADES and nome != "parar":
raise ValueError("Atividade desconhecida: " + nome)
return "atividade " + nome
if tipo == "rosto":
nome = str(valor or "").strip().lower()
if nome not in ROSTOS:
@@ -247,7 +255,8 @@ class Handler(SimpleHTTPRequestHandler):
with TRAVA:
aparencia = dict(APARENCIA)
dados = dict(versao=versao(), seq=EVENTOS.seq, autenticacao=bool(getattr(s, "token", None)),
estop=dict(ESTOP), aparencia=aparencia, gestos=GESTOS, rostos=ROSTOS, formatos=FORMATOS)
estop=dict(ESTOP), aparencia=aparencia, gestos=GESTOS, rostos=ROSTOS, formatos=FORMATOS,
atividades=ATIVIDADES)
if hasattr(s, "controle"):
dados.update(app=s.controle.resumo(host), app_config=s.controle.config.copy())
if hasattr(s, "servos"):
@@ -504,6 +513,11 @@ def main():
vida.treinamento = servidor.treinamento
vida.celular_dormindo = celular_dormindo
vida.celular_online = lambda: servidor.controle.resumo()['online']
def celular_atividade():
resumo = servidor.controle.resumo()
return resumo['estado'].get('atividade') if resumo['online'] else None
vida.celular_atividade = celular_atividade
vida.alguem_perto = alguem_perto
vida.madrugada = lambda agora: madrugada(servidor.controle.config, agora)
# E-Stop parado, ou modo presença com ninguém em casa (dormindo em silêncio): não faz nada