Ir al contenido
charmotion

Mascota animada para formularios de inicio de sesión: cómo funcionan los logins estilo Teddy

Por el equipo de Charmotion · Actualizado el

Ilustración de portada de la guía: Animación de mascota de marca para formularios de login: cómo funcionan los logins estilo osito, con personajes de demostración de Charmotion

Una mascota de formulario de login es un archivo de Rive cuya máquina de estados (state machine) controla el código de tu formulario. En el ejemplo del osito de Rive, un booleano hace que el oso mire el campo de usuario, un número dirige su mirada, otro booleano le tapa los ojos mientras se escribe la contraseña y unos triggers de éxito o fallo se reproducen tras enviar. Conecta el foco, la escritura y el resultado del login a esos inputs.

Puntos clave

  • El osito de Rive usa isChecking, numLook, isHandsUp, trigSuccess y trigFail.
  • Asigna el foco a attention, la escritura a thinking, la espera a loading y el resultado a success, no o error.
  • Aplica debounce a la escritura y nunca dejes que la animación retrase el login.
  • Nunca animes a partir del contenido ni de la longitud de la contraseña.
  • Taparse los ojos y seguir el cursor de texto requieren animaciones personalizadas creadas en el editor de Rive.

¿Cómo funciona la animación de login del osito de Rive?

La publicación "Animated login screen design" de Rive (marzo de 2022) construye el conocido login del osito y enumera los inputs de su máquina de estados:

  • isChecking (booleano): es true mientras el campo de usuario está activo, lo que hace que el oso pase de mirar en reposo a mirar el campo.
  • numLook (número): controla una mezcla entre mirar a la izquierda y a la derecha; "cuando el valor del input es 0, la mirada está a la izquierda; cuando el valor del input es 100, la mirada está a la derecha".
  • isHandsUp (booleano): "Teddy se tapa los ojos con las manos cuando el usuario escribe la contraseña", y las baja cuando es false.
  • trigSuccess y trigFail (triggers): reproducen una reacción después del login y luego vuelven a idle.

La publicación no muestra el código de la app. Cómo se calcula numLook depende de ti; una opción habitual es la posición del cursor de texto en el campo de usuario, escalada de 0 a 100.

La idea se puede generalizar: el formulario gestiona los eventos, el archivo de Rive gestiona el movimiento y unos pocos inputs con nombre los conectan. Rive también tiene listeners de puntero, configurados en el editor, que pueden hacer que un objeto siga el cursor dentro del canvas.

¿Qué eventos del formulario deben activar cada estado?

Evento del formularioEstado de la mascotaCómo
Carga de la páginaenter, luego idleTrigger, luego mood 0
Foco en email o usuarioattention (o listening)Mood 9 (o 6)
EscriturathinkingMood 3, vuelve a attention tras una pausa
Foco en la contraseñaun estado tranquilo, o una animación personalizada de "taparse los ojos"Mood 0, o tu propio booleano
EnviandoloadingMood 5
Sesión iniciadasuccess, luego happyTrigger, luego mood 1
Contraseña incorrectanoTrigger, sigue en el formulario
Error de red o del servidorerror, luego sadTrigger, luego mood 4

Los números de mood son la convención de los archivos de Charmotion (0 idle, 1 happy, 3 thinking, 4 sad, 5 loading, 6 listening, 9 attention); un archivo hecho a mano tendrá sus propios nombres. Haz que la reacción a una "contraseña incorrecta" sea suave: un movimiento de cabeza, no un fracaso dramático, porque la gente se equivoca al escribir todo el tiempo.

¿Cómo conecto los eventos del formulario a Rive en React?

Con Data Binding, carga el archivo con autoBind: true y usa los hooks del view model para el número de mood y cada trigger. Este componente es autónomo; reemplaza signIn por tu llamada de autenticación.

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>
  );
}

Notas: los setters son undefined hasta que el archivo termina de cargar, de ahí las llamadas con ?.. El campo de contraseña solo asigna un estado tranquilo al recibir el foco; nunca informa lo que se escribe. Con un archivo basado en inputs (como el del osito), usa useStateMachineInput para obtener cada input y asigna .value o llama a .fire(). Encontrarás más patrones en Rive en React y Next.js.

¿Cómo evito que la mascota del login estorbe?

  • El formulario va primero. Envía de inmediato; nunca esperes a que termine una animación para llamar a tu API de autenticación o redirigir.
  • Aplica debounce a la escritura. Asigna "thinking" al escribir y vuelve a un estado de reposo tras una pausa corta, como arriba. No dispares un trigger con cada tecla.
  • No reveles la contraseña. Que los ojos sigan la cantidad de caracteres es encantador en un campo de usuario; en un campo de contraseña le muestra a quien esté mirando cuánto mide la contraseña.
  • Accesibilidad. Marca la mascota con aria-hidden="true", mantén un texto de error real junto al campo y respeta prefers-reduced-motion mostrando una pose estática.
  • Peso. El runtime web más ligero de Rive, canvas-lite 2.44.0, pesaba unos 373 KB con brotli el 25 de octubre de 2026, y se carga una sola vez por sitio. Usa carga diferida (lazy loading) para que no ralentice el primer renderizado de tu página de inicio de sesión.

¿Qué no puede hacer una mascota de login generada?

Los dos gestos característicos del login del osito son animaciones personalizadas: las manos tapando los ojos y los ojos siguiendo el cursor de texto mediante un estado de mezcla. Un set de estados estándar no los incluye.

Los sets de Charmotion son un ejemplo. A partir de una imagen recibes los estados de la tabla de correspondencias (attention, thinking, loading, success, no, error y más) en un .riv conectado para Data Binding, con código React, en todos los planes de pago (desde $20/mes). No hay estado de "taparse los ojos" ni seguimiento de la mirada o del cursor. El .riv entregado es un archivo de runtime, no un proyecto editable, así que agregarlos implica crear esas animaciones en el editor de Rive a partir de tu propia ilustración o contratar a un animador de Rive para un trabajo a medida. Charmotion es automatizado y no agrega animaciones a un set; escribe a support@charmotion.app antes de comprar si necesitas algo específico.

Preguntas frecuentes

¿Una mascota de login ralentiza la página de inicio de sesión?

Agrega un runtime y un archivo. El runtime web canvas-lite 2.44.0 de Rive pesaba unos 373 KB comprimido con brotli el 25 de octubre de 2026 (una vez por sitio), y un archivo de personaje suele ocupar unas decenas de kilobytes. Usa carga diferida para la mascota después de que se renderice el formulario, así el formulario se puede usar primero.

¿La mascota del login debería taparse los ojos en el campo de contraseña?

Es un buen detalle si tu archivo tiene esa animación, y transmite privacidad. No lo simules siguiendo la longitud de la contraseña, porque eso revela información. Sin una animación personalizada, un estado de reposo tranquilo al enfocar la contraseña funciona bien.

¿Una mascota de Rive puede seguir el cursor del mouse?

Dentro de su canvas, sí, si el archivo está preparado para eso. El editor de Rive tiene listeners de puntero, y la acción Align Target hace que un objeto siga el puntero. Eso se configura en el editor; el código de runtime no puede agregarlo a un archivo que no lo tenga.

Fuentes

Guías relacionadas