Pular para o conteúdo
charmotion

Mascote animado em formulário de login: como funcionam os logins estilo Teddy

Por equipe Charmotion · Atualizado em

Ilustração de capa do guia: Animação de mascote em formulário de login: como funcionam os logins no estilo do ursinho, com personagens de demonstração do Charmotion

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.
  • trigSuccess e trigFail (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árioEstado do mascoteComo
Carregamento da páginaenter, depois idleTrigger, depois mood 0
Foco no e-mail ou usuárioattention (ou listening)Mood 9 (ou 6)
DigitaçãothinkingMood 3, volta a attention após uma pausa
Foco na senhaum estado calmo ou uma animação personalizada de "cobrir os olhos"Mood 0, ou seu próprio booleano
EnviandoloadingMood 5
Login concluídosuccess, depois happyTrigger, depois mood 1
Senha incorretanoTrigger, permanece no formulário
Erro de rede ou de servidorerror, depois sadTrigger, 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 respeite prefers-reduced-motion mantendo uma pose estática.
  • Peso. O runtime web mais leve do Rive, canvas-lite 2.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

Guias relacionados