Mascote animado em formulário de login: como funcionam os logins estilo Teddy
Por equipe Charmotion · Atualizado em

Um mascote de formulário de login é um arquivo Rive cuja state machine é controlada pelo código do seu formulário. No exemplo do ursinho do Rive, um booleano faz o urso olhar para o campo de usuário, um número direciona o olhar, outro booleano cobre os olhos durante a digitação da senha, e triggers de sucesso ou falha tocam depois do envio. Conecte o foco, a digitação e o resultado do login a esses inputs.
Principais pontos
- O ursinho do Rive usa isChecking, numLook, isHandsUp, trigSuccess e trigFail.
- Associe o foco a attention, a digitação a thinking, a espera a loading e o resultado a success, no ou error.
- Aplique debounce na digitação e nunca deixe a animação atrasar o login em si.
- Nunca anime com base no conteúdo ou no tamanho da senha.
- Cobrir os olhos e seguir o cursor de texto exigem animações personalizadas criadas no editor do Rive.
Como funciona a animação de login do ursinho do Rive?
O post "Animated login screen design" do Rive (março de 2022) cria o famoso login do ursinho e lista os inputs da state machine:
isChecking(booleano): verdadeiro enquanto o campo de usuário está ativo, o que faz o urso passar do olhar em repouso para olhar o campo.numLook(número): controla uma mistura entre olhar para a esquerda e para a direita; "quando o valor do input é 0, o olhar fica à esquerda; quando o valor do input é 100, o olhar fica à direita."isHandsUp(booleano): "O ursinho cobre os olhos com as mãos quando o usuário digita a senha" e as abaixa quando o valor é falso.trigSuccessetrigFail(triggers): tocam uma reação depois do login e depois voltam ao idle.
O post não mostra o código do app. Como numLook é calculado fica a seu critério; uma escolha comum é a posição do cursor no campo de usuário, convertida para a escala de 0 a 100.
A ideia vale de forma geral: o formulário cuida dos eventos, o arquivo Rive cuida do movimento, e alguns inputs nomeados conectam os dois. O Rive também tem listeners de ponteiro, configurados no editor, que fazem um objeto seguir o cursor dentro do canvas.
Quais eventos do formulário devem disparar quais estados?
| Evento do formulário | Estado do mascote | Como |
|---|---|---|
| Carregamento da página | enter, depois idle | Trigger, depois mood 0 |
| Foco no e-mail ou usuário | attention (ou listening) | Mood 9 (ou 6) |
| Digitação | thinking | Mood 3, volta a attention após uma pausa |
| Foco na senha | um estado calmo ou uma animação personalizada de "cobrir os olhos" | Mood 0, ou seu próprio booleano |
| Enviando | loading | Mood 5 |
| Login concluído | success, depois happy | Trigger, depois mood 1 |
| Senha incorreta | no | Trigger, permanece no formulário |
| Erro de rede ou de servidor | error, depois sad | Trigger, depois mood 4 |
Os números de mood seguem a convenção dos arquivos do Charmotion (0 idle, 1 happy, 3 thinking, 4 sad, 5 loading, 6 listening, 9 attention); um arquivo feito à mão terá seus próprios nomes. Mantenha o "senha incorreta" suave: um balançar de cabeça, não um fracasso dramático, porque as pessoas erram a digitação o tempo todo.
Como conectar eventos do formulário ao Rive no React?
Com Data Binding, carregue o arquivo com autoBind: true e use os hooks do view model para o número mood e para cada trigger. Este componente é independente; substitua signIn pela sua chamada de autenticação.
import { useRef } from "react";
import {
useRive,
useViewModelInstanceNumber,
useViewModelInstanceTrigger,
} from "@rive-app/react-canvas";
const MOOD = { idle: 0, happy: 1, thinking: 3, sad: 4, loading: 5, attention: 9 };
export function LoginForm({ signIn }: { signIn: (e: string, p: string) => Promise<"ok" | "wrong" | "error"> }) {
const { rive, RiveComponent } = useRive({
src: "/mascot.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: no } = useViewModelInstanceTrigger("no", vmi);
const { trigger: error } = useViewModelInstanceTrigger("error", vmi);
const typing = useRef<number>();
const onType = () => {
setMood?.(MOOD.thinking);
window.clearTimeout(typing.current);
typing.current = window.setTimeout(() => setMood?.(MOOD.attention), 800);
};
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const f = new FormData(e.currentTarget);
setMood?.(MOOD.loading);
const result = await signIn(String(f.get("email")), String(f.get("password")));
if (result === "ok") { success?.(); setMood?.(MOOD.happy); }
else if (result === "wrong") { no?.(); setMood?.(MOOD.idle); }
else { error?.(); setMood?.(MOOD.sad); }
};
return (
<form onSubmit={onSubmit}>
<div style={{ width: 160, height: 160 }} aria-hidden="true"><RiveComponent /></div>
<input name="email" type="email" autoComplete="email"
onFocus={() => setMood?.(MOOD.attention)} onInput={onType}
onBlur={() => setMood?.(MOOD.idle)} />
<input name="password" type="password" autoComplete="current-password"
onFocus={() => setMood?.(MOOD.idle)} />
<button type="submit">Sign in</button>
</form>
);
}
Observações: os setters ficam undefined até o arquivo carregar, por isso as chamadas com ?.. O campo de senha só define um estado calmo no foco; ele nunca informa o que é digitado. Com um arquivo baseado em inputs (como o do ursinho), use useStateMachineInput para obter cada input e defina .value ou chame .fire(). Mais padrões estão em Rive no React e no Next.js.
Como evitar que o mascote de login atrapalhe?
- O formulário vem primeiro. Envie imediatamente; nunca espere uma animação terminar antes de chamar sua API de autenticação ou redirecionar.
- Aplique debounce na digitação. Defina "thinking" enquanto a pessoa digita e volte a um estado de repouso após uma pausa curta, como acima. Não dispare um trigger a cada tecla.
- Não vaze a senha. Acompanhar com os olhos pela contagem de caracteres é charmoso em um campo de usuário; em um campo de senha, isso mostra a quem estiver olhando o tamanho da senha.
- Acessibilidade. Marque o mascote com
aria-hidden="true", mantenha um texto de erro real ao lado do campo e respeiteprefers-reduced-motionmantendo uma pose estática. - Peso. O runtime web mais leve do Rive,
canvas-lite2.44.0, mediu cerca de 373 KB com brotli em 25 de outubro de 2026 e é carregado uma vez por site. Use lazy loading (carregamento sob demanda) para que ele não atrase a primeira renderização da sua página de login.
O que um mascote de login gerado não consegue fazer?
Os dois movimentos marcantes do login do ursinho são animações personalizadas: as mãos cobrindo os olhos e os olhos seguindo o cursor de texto por meio de um estado de mistura. Um conjunto de estados padrão não inclui essas animações.
Os conjuntos do Charmotion são um exemplo. A partir de uma imagem, você recebe os estados da tabela de correspondência (attention, thinking, loading, success, no, error e outros) em um .riv conectado para Data Binding, com código React, em todos os planos pagos (a partir de US$ 20/mês). Não há estado de "cobrir os olhos" nem rastreamento dos olhos ou do cursor. O .riv entregue é um arquivo de runtime, não um projeto editável, então adicioná-los significa criar essas animações no editor do Rive a partir da sua própria arte ou contratar um animador de Rive para um trabalho personalizado. O Charmotion é automatizado e não adiciona animações a um conjunto; escreva para support@charmotion.app antes de comprar se você precisa de algo específico.
Perguntas frequentes
Um mascote de login deixa a página de login mais lenta?
Ele adiciona um runtime e um arquivo. O runtime web canvas-lite 2.44.0 do Rive mediu cerca de 373 KB com compressão brotli em 25 de outubro de 2026 (uma vez por site), e um arquivo de personagem costuma ter dezenas de kilobytes. Use lazy loading no mascote depois que o formulário renderizar, para que o formulário fique utilizável primeiro.
O mascote de login deve cobrir os olhos no campo de senha?
É um toque simpático se o seu arquivo tiver essa animação, e transmite privacidade. Não simule isso rastreando o tamanho da senha, o que revela informações. Sem uma animação personalizada, um estado idle calmo no foco da senha funciona bem.
Um mascote Rive pode seguir o cursor do mouse?
Dentro do canvas, sim, se o arquivo for feito para isso. O editor do Rive tem listeners de ponteiro, e a ação Align Target faz um objeto seguir o ponteiro. Isso precisa ser configurado no editor; não é algo que o código de runtime consiga adicionar a um arquivo que não tenha esse recurso.
Fontes
- Animated login screen design, Rive Blog
- Listeners, Rive
- Data binding (React runtime), Rive
- Runtime sizes, Rive
- prefers-reduced-motion, MDN Web Docs