Como adicionar um mascote ao onboarding e aos estados vazios
Por equipe Charmotion · Atualizado em

Para adicionar um mascote ao onboarding e aos estados vazios, liste cada passo e cada tela vazia, atribua a cada um deles um humor em loop (welcome, listening, sleeping) ou uma reação única (success, error) e defina esse estado a partir dos eventos que seu app já tem. Deixe o texto e os botões fazerem o trabalho e permita que o usuário pule ou pause o movimento.
Principais pontos
- Mapeie telas para estados antes de animar: um humor por passo, um trigger por resultado.
- Controle o mascote com eventos que você já tem, como focus, submit, success e error.
- Estados vazios precisam de um loop calmo e de uma ação clara: o mascote define o tom, o botão faz o trabalho.
- Loops longos ao lado de conteúdo precisam de uma forma de pausar ou parar segundo o WCAG 2.2.2, e o movimento reduzido deve mostrar uma pose estática.
Já tem um personagem ou logo? Veja seu personagem em telas reais de app: telas de splash, onboarding, carregamento e estado vazio. É grátis, roda no navegador e não envia nada.
Onde um mascote ajuda e onde ele incomoda?
Um mascote ajuda em momentos que seriam vazios ou incertos: a primeira tela do onboarding, um formulário esperando preenchimento, uma lista ainda sem nada, a confirmação depois do primeiro sucesso. Ele incomoda quando atrapalha a tarefa.
Bons usos:
- Uma tela de boas-vindas em que o personagem cumprimenta o usuário uma vez.
- Um formulário de cadastro ou configuração em que ele "escuta" enquanto o usuário digita.
- O momento em que um passo dá certo ou falha, como uma reação curta.
- Listas, caixas de entrada e resultados de busca vazios, como um loop calmo ao lado de uma próxima ação clara.
Maus usos:
- Bloquear o botão de avançar até a animação terminar.
- Cobrir campos de formulário ou mensagens de erro.
- Substituir instruções pelas expressões do personagem. O texto ainda precisa explicar o que fazer.
- Movimento agitado em todas as telas. Use em poucos momentos de alto valor.
As diretrizes de inicialização da Apple trazem um ponto parecido: se você quer um momento de abertura com a marca, coloque-o no início do onboarding, e não na launch screen (tela de inicialização) (Apple HIG). Isso faz da primeira tela do onboarding o lugar natural para um cumprimento.
Qual reação do mascote combina com cada passo do onboarding?
Pense em cada passo como uma condição (um loop que roda enquanto ela for verdadeira) ou um evento (uma reação única que toca e volta). Este mapeamento cobre a maioria dos fluxos de onboarding:
| Passo ou evento | Estado | Tipo |
|---|---|---|
| Tela de boas-vindas aparece | enter, depois wave | trigger, depois loop |
| Usuário clica em um campo de texto | listening | loop |
| Formulário enviado, aguardando | thinking ou loading | loop |
| Passo concluído com sucesso | success, depois happy | trigger, depois loop |
| Erro de validação ou de rede | error, depois idle | trigger, depois loop |
| Escolha sim/não (notificações, rastreamento) | yes ou no | trigger |
| Usuário sai do onboarding | exit | trigger |

Mantenha as reações curtas para que terminem antes de o usuário seguir em frente, e nunca espere uma reação acabar para avançar. Para o catálogo completo de estados e tempos, veja estados de animação de mascote.
O Charmotion gera esses estados a partir de um mascote enviado: dez loops selecionados por um número mood (0 idle, 1 happy, 2 wave, 3 thinking, 4 sad, 5 loading, 6 listening, 7 talking, 8 sleeping, 9 attention) e seis triggers (success, error, yes, no, enter, exit), tudo em um único .riv com código para web, React e SwiftUI em todos os planos pagos.
Como mostrar um mascote em um estado vazio?
Um estado vazio tem três partes: o que está faltando, por quê e o que fazer em seguida. O mascote fica acima ou ao lado delas, nunca no lugar delas.
<section class="empty">
<canvas id="mascot" width="160" height="160" aria-hidden="true"></canvas>
<h2>No projects yet</h2>
<p>Projects you create or are invited to will show up here.</p>
<button>Create a project</button>
</section>
Escolha um loop calmo: sleeping ou idle combinam com "nada aqui ainda", enquanto attention combina com "tem algo novo esperando". Estados vazios diferentes podem usar humores diferentes com o mesmo arquivo, por exemplo sleeping para uma caixa de entrada vazia e thinking para uma busca sem resultados.
Como o estado vazio pode ficar na tela por muito tempo, atenção à regra de acessibilidade para movimento prolongado. O WCAG 2.2 SC 2.2.2 exige uma forma de pausar, parar ou ocultar movimento automático que dure mais de cinco segundos ao lado de outro conteúdo (W3C). Opções práticas: tocar o loop algumas vezes e depois pausar em um frame estático, adicionar um pequeno botão de pausa, ou manter o loop bem sutil e pará-lo totalmente com movimento reduzido.
Como disparar reações de sucesso e erro a partir do código do app?
Defina o mood quando uma condição começa e dispare um trigger quando um evento acontece. O código do mascote deve escutar o estado do seu app, não ser dono dele. Em React com Rive Data Binding, um componente pode receber o passo e o último resultado como props:
import { useEffect } from "react";
import { useRive, useViewModelInstanceNumber, useViewModelInstanceTrigger } from "@rive-app/react-webgl2";
export function Mascot({ mood, result }: { mood: number; result: { kind: "success" | "error"; id: number } | null }) {
const { rive, RiveComponent } = useRive({
src: "/character.riv",
stateMachine: "CharacterViewModelMachine",
autoplay: true,
autoBind: true,
});
const vmi = rive?.viewModelInstance;
const { setValue: setMood } = useViewModelInstanceNumber("mood", vmi);
const { trigger: success } = useViewModelInstanceTrigger("success", vmi);
const { trigger: error } = useViewModelInstanceTrigger("error", vmi);
useEffect(() => { setMood(mood); }, [mood, setMood]);
useEffect(() => {
if (result?.kind === "success") success();
if (result?.kind === "error") error();
}, [result?.id]);
return <RiveComponent aria-hidden="true" style={{ width: 160, height: 160 }} />;
}
Passar um resultado com um id incremental permite que a mesma reação seja disparada duas vezes seguidas, por exemplo em duas tentativas que falharam. Os nomes dos hooks vêm do runtime React do Rive (Rive); na web pura, o equivalente é r.viewModelInstance.number("mood").value = 6 e .trigger("success").trigger().
Como conectar no SwiftUI, Compose e Flutter?
O padrão é idêntico em todas as plataformas: mantenha uma instância do Rive por tela e chame set-mood ou fire-trigger a partir dos eventos do seu view model. Com a API legada de inputs:
SwiftUI (runtime legado da Apple, RiveViewModel):
@StateObject private var mascot = RiveViewModel(fileName: "character",
stateMachineName: "CharacterStateMachine")
mascot.view().frame(width: 160, height: 160).accessibilityHidden(true)
// on focus
mascot.setInput("mood", value: 6.0)
// on success
mascot.triggerInput("success")
Android (RiveAnimationView legado, também utilizável no Compose via AndroidView):
riveView.setNumberState("CharacterStateMachine", "mood", 6f)
riveView.fireState("CharacterStateMachine", "success")
Flutter:
final sm = controller.stateMachine;
sm.number("mood")?.value = 6;
sm.trigger("success")?.fire();
Essas chamadas vêm da documentação legada de inputs do Rive para Apple, Android e Flutter. Hoje o Rive recomenda Data Binding para projetos novos, e o novo runtime da Apple só aceita Data Binding. Para movimento reduzido, leia accessibilityReduceMotion no SwiftUI e a configuração de sistema equivalente nas outras plataformas, e mostre uma imagem estática no lugar da animação.
Como saber se o mascote está ajudando?
Trate o mascote como qualquer outra mudança no onboarding e meça o resultado. Sinais úteis:
- Taxa de conclusão de cada passo do onboarding, antes e depois.
- Tempo por passo. Se ele aumentar, uma animação pode estar deixando as pessoas mais lentas ou tirando a atenção do formulário.
- Conversão no estado vazio: com que frequência os usuários clicam na ação principal de uma tela vazia.
- Feedback qualitativo de algumas sessões de teste de usabilidade, observando se as pessoas ficam esperando pelo personagem.
Mantenha o mascote opcional no código: se o arquivo não carregar ou o movimento reduzido estiver ativado, a tela precisa continuar legível e funcionando perfeitamente com uma imagem estática ou sem imagem nenhuma. Esse fallback também mantém a primeira abertura rápida em conexões lentas.
Para a transição da splash screen para o onboarding, veja o guia de animação de abertura e splash screen.
Como adicionar um mascote ao onboarding e aos estados vazios
- Liste os momentos. Anote cada passo do onboarding, cada tela vazia e os eventos entre eles: foco, envio, sucesso, erro, pular.
- Defina os estados. Dê a cada condição um humor em loop e a cada evento um trigger, por exemplo listening no foco e success ao concluir um passo.
- Adicione uma instância por tela. Posicione o canvas ou a view do mascote ao lado do conteúdo, oculto para leitores de tela e com dimensões fixas.
- Conecte seus eventos. Defina o humor e dispare os triggers a partir do estado já existente do view model ou do componente, sem nunca bloquear a navegação por causa de uma animação.
- Respeite as configurações de movimento. Pause os loops longos de estado vazio depois de alguns ciclos ou ofereça um controle de pausa, e mostre uma pose estática com movimento reduzido.
- Meça. Compare a conclusão dos passos, o tempo por passo e os cliques no estado vazio antes e depois.
Perguntas frequentes
O mascote do onboarding deve falar?
Só se a fala acrescentar algo que o texto não consegue. Um loop de fala (talking) é útil em fluxos de voz ou de assistente. Em um onboarding típico, um texto curto com uma reação é mais claro, funciona com leitores de tela e dispensa o trabalho de sincronia labial. De qualquer forma, mantenha todas as instruções em texto real.
Qual humor combina com um estado vazio?
Um humor calmo. Sleeping ou idle combinam com "ainda não há nada aqui"; attention combina com "tem algo novo esperando por você". Use junto com um título, uma explicação de uma linha e um botão principal, e pause o loop depois de alguns ciclos para que ele não rode indefinidamente.
Preciso de um arquivo separado para cada passo do onboarding?
Não. Uma state machine do Rive guarda todos os estados em um único arquivo, e você alterna entre eles com um número para os loops e triggers para as reações. Assim o download fica pequeno, o personagem fica consistente entre as telas e as transições entre estados ficam suaves, porque estão todas no mesmo arquivo.
E se o mascote não carregar?
A tela deve continuar funcionando. Reserve o espaço, mostre uma imagem estática ou nada, e mantenha todas as instruções e ações em texto e botões comuns. Trate a animação como um complemento, nunca como uma dependência, e teste a tela uma vez com o arquivo bloqueado para confirmar.
Respostas rápidas deste guia
Fontes
- Launching, Apple Human Interface Guidelines
- Understanding SC 2.2.2: Pause, Stop, Hide, W3C WAI
- React runtime, Rive
- Data binding (web runtime), Rive
- Inputs (Apple runtime, legacy), Rive
- Inputs (Android runtime, legacy), Rive
- Inputs (Flutter runtime, legacy), Rive
- accessibilityReduceMotion, Apple Developer Documentation