State machine do Rive: inputs, triggers e humores
Por equipe Charmotion · Atualizado em

Uma state machine do Rive é um grafo dentro de um arquivo .riv que decide qual animação toca e quando. Os estados guardam animações, as transições os conectam e as condições nas transições leem valores que o seu código define. Hoje o Rive recomenda Data Binding (view models) para esses valores; os inputs antigos de número, booleano e trigger continuam funcionando.
Principais pontos
- Os estados guardam animações; transições com condições decidem quando passar de um para outro.
- Os inputs são de três tipos: número, booleano e trigger.
- Use números ou booleanos para loops persistentes e triggers para reações únicas.
- Os inputs foram descontinuados em favor do Data Binding, mas os arquivos existentes continuam funcionando.
O que é uma state machine do Rive?
A state machine (máquina de estados) é a camada de lógica de um arquivo Rive. Ela fica acima das animações da timeline e responde a uma pergunta a cada frame: o que deve estar tocando agora?
- Os estados geralmente guardam uma única animação, como um loop idle (loop de repouso), ou uma mescla de várias.
- As transições são setas entre estados. Cada uma pode ter uma duração, o que faz o Rive mesclar a animação que sai com a que entra em vez de cortar.
- Condições nas transições leem valores de fora da animação, como "mood igual a 5" ou "success foi disparado".
- Estados especiais: Entry roda primeiro, Any State permite que uma transição dispare de qualquer estado em que a máquina esteja no momento, e Exit encerra uma camada.
- Camadas (layers) permitem que vários grafos de estados rodem ao mesmo tempo, por exemplo o movimento do corpo em uma camada e o piscar dos olhos em outra.
Seu app nunca toca animações pelo nome. Ele altera valores, e a state machine reage. Assim, a lógica da animação fica dentro do arquivo, onde o designer pode ajustá-la sem mudar o código.
State machines também podem se estabilizar (settle): quando o runtime detecta que nada mais vai mudar, ele para de avançar, o que economiza processamento em estados finais estáticos.
O que são inputs de número, booleano e trigger?
Inputs são a forma original de o código se comunicar com uma state machine. Existem três tipos:
| Tipo | Armazena | Uso típico |
|---|---|---|
| Number | Um número decimal (float) que você define e lê | Escolher entre muitos estados, níveis, progresso |
| Boolean | true ou false | Um estado ligado/desligado, como hovered ou muted |
| Trigger | Um evento momentâneo que você dispara | Reações únicas: success, error, toque |
Trigger ou booleano é a dúvida mais comum. Um booleano continua true até você defini-lo como false, então serve para condições que duram. Um trigger é consumido pela transição que o lê, então dispara uma vez e se redefine sozinho. Use um trigger quando, do contrário, você definiria um booleano como true e logo em seguida de volta para false.
Um input de número é a forma mais limpa de escolher entre muitos loops mutuamente exclusivos. Um único número mood com valores de 0 a 9 substitui dez booleanos que você teria que manter consistentes por conta própria.
Na web, a API legada retorna os inputs a partir de stateMachineInputs(). Triggers têm fire(); números e booleanos têm uma propriedade value:
import { Rive } from "@rive-app/webgl2";
const r = new Rive({
src: "/character.riv",
canvas: document.querySelector("canvas"),
stateMachine: "CharacterStateMachine",
autoplay: true,
onLoad: () => {
r.resizeDrawingSurfaceToCanvas();
const inputs = r.stateMachineInputs("CharacterStateMachine");
const mood = inputs.find((i) => i.name === "mood");
const success = inputs.find((i) => i.name === "success");
mood.value = 5; // loading loop
success.fire(); // one-shot reaction
},
});
Consulte os inputs dentro de onLoad; antes de o arquivo carregar, eles não existem. Repare na opção no singular stateMachine, que substituiu stateMachines no web runtime v2.41.0.
Qual a diferença entre estados em loop e triggers de reação única?
A maioria dos personagens interativos precisa de dois tipos de movimento:
- Loops representam uma condição contínua: idle, loading, listening, sleeping. Eles devem tocar enquanto a condição for verdadeira, por isso são selecionados por um valor persistente (um número ou booleano).
- Reações únicas representam um evento: um pagamento foi aprovado, um upload falhou, o usuário disse sim. Elas tocam uma vez e depois devem voltar para o loop atual, por isso são disparadas por triggers.
A ligação usual é uma transição de Any State para cada reação única, condicionada ao seu trigger, e uma transição de saída no fim da reação que volta ao loop correspondente ao valor numérico atual. Feito assim, seu código pode definir o loop e disparar reações de forma independente, sem precisar acompanhar o que está tocando.

Dois detalhes importam na prática. Primeiro, dê às transições entre loops uma duração de mesclagem curta, para que as mudanças de humor fiquem suaves em vez de saltarem. Segundo, decida se uma mudança de loop deve interromper uma reação única. Normalmente não deve: se uma requisição termina e você dispara success e volta o mood para idle no mesmo frame, você ainda quer que a reação success toque por completo.
Os inputs de state machine do Rive foram descontinuados?
Sim. O Rive descontinuou os inputs de state machine, e a escuta de eventos em runtime, em favor do data binding. A documentação de runtime agora abre as páginas de inputs com um aviso de descontinuação: use data binding em projetos novos e planeje migrar os existentes.
Descontinuado não quer dizer quebrado. O guia de migração do Rive afirma que você não precisa atualizar arquivos existentes e que inputs e eventos continuarão funcionando normalmente. O suporte, porém, varia conforme o runtime:
- Web, React, Android e Flutter: as APIs de input continuam funcionando.
- Apple: os inputs funcionam apenas no runtime legado da Apple. O novo runtime da Apple suporta somente data binding.
- React Native: o runtime Nitro registra avisos para os métodos de input na v0.5 e os remove na v0.6.
Para migrar um arquivo, abra-o no editor do Rive, escolha Convert Inputs to View Models no menu principal (o ícone de três linhas) e depois atualize seu código para definir valores no view model em vez dos inputs.
O que é data binding no Rive?
O data binding conecta um view model, um conjunto tipado de propriedades definido no editor, a qualquer coisa no arquivo: condições da state machine, textos, cores, posições. Seu código obtém uma instância do view model e define suas propriedades.
Em comparação com os inputs, as propriedades de view model suportam mais tipos. Os inputs se limitam a números, booleanos e triggers; os view models acrescentam strings, enums, cores, view models aninhados, listas, imagens e artboards. As propriedades também podem ser observadas, então a animação consegue devolver valores ao seu código.
Na web, o equivalente ao exemplo com inputs fica assim:
const r = new Rive({
src: "/character.riv",
canvas: document.querySelector("canvas"),
stateMachine: "CharacterStateMachine",
autoplay: true,
autoBind: true,
onLoad: () => {
const vmi = r.viewModelInstance;
vmi.number("mood").value = 5;
vmi.trigger("success").trigger();
vmi.number("mood").on((event) => console.log(event));
},
});
Com autoBind: true, o runtime cria e vincula a instância padrão do view model para você. Os nomes de propriedade aqui pressupõem um arquivo cujo view model tenha as propriedades mood e success. Um arquivo que só tem inputs não tem view model, então este código não encontraria nada; use a API de inputs nesses arquivos.
Como o input mood do Charmotion se relaciona com os estados?
Os arquivos do Charmotion seguem o padrão de loop mais trigger descrito acima, com um input de número e seis triggers em uma state machine chamada CharacterStateMachine.
mood | Loop | mood | Loop |
|---|---|---|---|
| 0 | idle | 5 | loading |
| 1 | happy | 6 | listening |
| 2 | wave | 7 | talking |
| 3 | thinking | 8 | sleeping |
| 4 | sad | 9 | attention |
As mudanças de humor fazem uma mesclagem de 220 ms. Os triggers success, error, yes, no, enter e exit tocam cada um uma reação única e depois voltam ao mood definido. exit deixa o personagem oculto até que enter seja disparado. Mudanças de humor nunca interrompem uma reação única. Uma segunda máquina, LaunchStateMachine, toca uma intro de abertura uma vez e depois fica em idle.
Todo arquivo do Charmotion vem pronto para as duas formas: escolha CharacterViewModelMachine com autoBind: true e defina viewModelInstance.number("mood") ou dispare viewModelInstance.trigger("success") para usar Data Binding, ou escolha a CharacterStateMachine padrão e use a API de inputs acima. As duas máquinas têm os mesmos 10 loops e 6 reações únicas.
Perguntas frequentes
Como trocar de animação com uma state machine do Rive?
Altere o valor que as transições da state machine estão observando. Defina um input de número ou booleano, ou uma propriedade de view model, e a transição correspondente leva ao novo estado. Você não chama animações pelo nome; as condições de transição do arquivo decidem o que toca quando um valor muda.
Qual a diferença entre um trigger e um booleano no Rive?
Um trigger dispara uma vez e se redefine depois que uma transição o consome, por isso serve para eventos únicos como success ou toque. Um booleano mantém o valor até você mudá-lo, por isso serve para condições que duram, como hovered ou muted. Use triggers para eventos e booleanos para estados.
Preciso migrar meus arquivos Rive para data binding?
Não, pelo menos não agora. O Rive afirma que arquivos existentes com inputs continuam funcionando. Migre quando precisar do novo runtime da Apple, do React Native Nitro v0.6+ ou de tipos de propriedade mais ricos. O comando Convert Inputs to View Models do editor cuida da parte do arquivo; depois você atualiza o código do runtime.
Por que meu código não encontra um input da state machine?
Geralmente porque o arquivo ainda não terminou de carregar ou porque algum nome não corresponde exatamente. Consulte os inputs no callback onLoad, confira se passou o nome correto da state machine e compare os nomes dos inputs caractere por caractere, incluindo maiúsculas, minúsculas e espaços. Arquivos convertidos para view models não expõem mais inputs.