Rive 완벽 가이드 — 인터랙티브 벡터 애니메이션

Rive 완벽 가이드 — 인터랙티브 벡터 애니메이션

이 글의 핵심

Rive는 벡터 그래픽과 애니메이션을 하나의 런타임에서 재생·제어할 수 있게 하는 도구입니다. 이 글에서는 에디터 워크플로, 상태 머신 기반 인터랙션, 웹·React·Flutter 통합, 런타임 API, 성능 튜닝, Lottie와의 선택 기준을 다룹니다.

이 글의 핵심

Rive는 벡터 에셋을 제작하고, 상태 머신(State Machine)으로 런타임에 제어 가능한 인터랙티브 애니메이션을 만드는 플랫폼입니다. After Effects에서 JSON으로 내보내 재생하는 Lottie와 달리, Rive는 에디터·런타임·상태 모델이 일체로 설계되어 있어 UI·캐릭터·마이크로 인터랙션에 특히 잘 맞습니다.

이 가이드에서는 다음을 순서대로 다룹니다.

  1. Rive의 핵심 개념(아트보드, 객체 계층, 애니메이션 파이프라인)
  2. Rive Editor에서의 실무 워크플로
  3. State Machine과 입력(Boolean, Number, Trigger 등)으로 만드는 인터랙션
  4. 웹(Canvas/WebGL), React, Flutter 통합 패턴
  5. 런타임 API로 재생·입력·이벤트 제어
  6. 성능 최적화 체크리스트
  7. Lottie vs Rive 선택 기준

1. Rive를 쓰는 이유

웹·모바일 UI에서 애니메이션은 브랜드 인지도와 사용성을 동시에 높입니다. 다만 영상처럼 한 방향으로만 재생되는 에셋은 버튼 호버, 토글, 로딩 상태, 온보딩 튜토리얼처럼 상태가 자주 바뀌는 화면에 넣기 어렵습니다. Rive는 같은 파일(.riv) 안에 그래픽과 논리(상태 전이)를 함께 담아, 개발자가 코드에서 입력만 바꿔도 디자이너가 의도한 전환이 재현되도록 설계되어 있습니다.

적합한 사례: 대시보드 위젯, 온보딩 일러스트, 게임성 있는 로딩·성공 피드백, 커스텀 토글·슬라이더, 캐릭터 리깅이 들어간 마스코트.

덜 적합한 사례: 사진·비디오 기반 모션 그래픽 전체를 대체하는 용도, 이미 Lottie 파이프라인에 완전히 고정된 팀(마이그레이션 비용이 큰 경우).


2. 핵심 개념

2.1 아트보드(Artboard)와 캔버스

아트보드는 작업 단위의 루트입니다. 해상도·프레임은 아트보드에 묶이며, 런타임에서는 보통 한 번에 하나의 아트보드를 선택해 재생합니다. 여러 화면 변형(라이트/다크, A/B)을 한 파일에 넣을 때는 아트보드를 나누거나, 상태 머신으로 같은 아트보드 안에서 전환하는 방식 중 하나를 선택합니다.

2.2 벡터 셰이프와 계층

Rive는 벡터 기반입니다. 경로, 페인트, 그라디언트, 마스크 등이 계층 트리로 관리됩니다. 뼈대(Bones)가중치(Weights)로 캐릭터 리깅을 할 수 있어, 단순 UI 아이콘부터 관절이 있는 일러스트까지 같은 도구로 다룰 수 있습니다.

2.3 애니메이션(Animations)

타임라인 애니메이션은 키프레임으로 프로퍼티(위치, 회전, 색, 모프 등)를 기록합니다. 런타임에서는 단순 재생·루프·믹스가 가능합니다. 인터랙션의 주 상태 전이까지 타임라인만으로 처리하려면 조합이 기하급수로 늘어나기 쉬우므로, 실무에서는 상태 머신과 역할을 나누는 것이 일반적입니다.

2.4 상태 머신(State Machine)

상태 머신은 이름 그대로 상태(State)전이(Transition)로 동작을 정의합니다. 각 상태는 하나 이상의 애니메이션 클립(또는 믹스)과 연결되고, 입력(Input)—예: hover, pressed, progress—에 따라 어떤 전이가 발동할지 규칙으로 기술합니다.

런타임에서는 디자이너가 노출해 둔 입력 이름에 맞춰 앱 코드에서 값을 설정합니다. 이 계약이 명확하면 디자인 변경이 코드에 미치는 영향을 최소화할 수 있습니다.

2.5 입력(Input) 타입

자주 쓰는 입력 유형은 다음과 같습니다.

유형용도 예시
Boolean호버, 선택, 켜짐/꺼짐
Number진행률, 슬라이더, 스크롤 연동
Trigger한 번 실행되는 펄스(성공 체크 등)

Trigger는 내부적으로 “한 프레임/짧은 구간”에 맞춰 소비되는 패턴으로 쓰입니다. 연속 값이 필요하면 Number를 사용합니다.


3. Rive Editor 사용법

3.1 설치와 프로젝트

Rive데스크톱 에디터브라우저 에디터를 제공합니다. 계정을 만들고 팀·프로젝트를 나누면 버전 관리와 공유가 수월합니다. .riv는 바이너리 포맷이므로 Git에는 원본과 함께 “어떤 장면이 바뀌었는지”를 이슈나 릴리즈 노트로 남기는 것이 협업에 도움이 됩니다.

3.2 기본 워크플로

  1. 아트보드 크기와 이름을 정한다.
  2. 벡터로 셰이프를 그리거나 SVG를 가져온다.
  3. 타임라인 애니메이션으로 기본 모션(대기, 호버, 클릭 반응 등)을 만든다.
  4. State Machine을 추가하고, 상태와 전이를 연결한다.
  5. 입력을 정의하고 전이 조건에 연결한다.
  6. 런타임 미리보기로 브라우저에서 입력을 조작해 본다.

3.3 디자이너·개발자 합의 포인트

  • 입력 이름·타입을 문서화한다(예: isOpen, progress, onSuccess).
  • 아트보드 이름상태 머신 이름을 고정한다. 런타임에서 문자열로 조회하는 경우가 많다.
  • 불필요한 레이어과도한 클립 중첩을 줄여 런타임 비용을 낮춘다.

4. State Machine과 인터랙션

4.1 상태 설계

상태는 사용자에게 보이는 모드와 맞추는 것이 디버깅에 유리합니다. 예: idle, hover, pressed, loading, success, error. 전이에는 조건(입력 값), 이징, 믹스 딜레이 등을 걸 수 있습니다.

4.2 인터랙션 패턴

  • 버튼: hover Boolean + pressed Boolean, 또는 단일 상태 전이 체인.
  • 토글: isOn Boolean에 따라 두 상태를 오간다.
  • 프로그레스 링: Number 입력을 0~1로 매핑해 진행 애니메이션과 동기화.
  • 성공 피드백: Trigger complete를 발동시키고, 완료 클립이 끝나면 idle로 복귀.

4.3 코드와의 경계

상태 머신에 비즈니스 규칙 전부를 넣기보다, 표현과 피드백에 가깝게 유지하는 편이 낫습니다. 예를 들어 “결제 성공 여부”는 앱 상태에 두고, 성공 시에만 Trigger를 쏘는 식으로 단방향 데이터 흐름을 유지하면 테스트가 쉬워집니다.


5. 웹 통합 (Canvas / WebGL)

웹에서는 공식 런타임 패키지로 Canvas 또는 WebGL 백엔드를 선택합니다. GPU 가용성·필터·대상 디바이스에 따라 선택이 갈립니다. 일반적으로 복잡한 씬·많은 인스턴스에서는 WebGL이 유리한 경우가 많고, 단순 UI는 Canvas로도 충분한 경우가 많습니다.

5.1 패키지 설치

npm install @rive-app/canvas
# 또는
npm install @rive-app/webgl2

5.2 최소 예시 (Canvas)

아래는 .riv를 로드하고 요청 애니메이션 루프에서 advance를 호출하는 패턴입니다. 실제 프로젝트에서는 ResizeObserver로 캔버스 크기를 맞추고, devicePixelRatio를 고려하는 것이 좋습니다.

import { Rive, Layout, Fit, Alignment } from '@rive-app/canvas';

const canvas = document.getElementById('rive-canvas') as HTMLCanvasElement;

const rive = new Rive({
  canvas,
  src: '/animations/ui-toggle.riv',
  autoplay: true,
  layout: new Layout({
    fit: Fit.Contain,
    alignment: Alignment.Center,
  }),
  onLoad: () => {
    rive.resizeDrawingSurfaceToCanvas();
  },
});

// 뷰가 사라질 때
// rive.cleanup();

설명: Rive 생성자에 캔버스와 에셋 URL을 넘깁니다. onLoad에서 드로잉 서피스를 캔버스에 맞추면 레티나 디스플레이에서 흐림을 줄일 수 있습니다. 컴포넌트 언마운트 시 cleanup으로 리스너·루프를 정리해야 메모리 누수를 방지합니다.


6. React 통합

React에서는 @rive-app/react-canvas(또는 WebGL 변형)로 선언적으로 감쌉니다. 상태 머신 입력은 ref 또는 콜백으로 런타임 인스턴스에 접근해 갱신합니다.

6.1 설치

npm install @rive-app/react-canvas

6.2 컴포넌트 예시

import { useState } from 'react';
import { useRive, useStateMachineInput } from '@rive-app/react-canvas';

type RiveToggleProps = {
  src: string;
  stateMachineName?: string;
};

export function RiveToggle({ src, stateMachineName = 'State Machine 1' }: RiveToggleProps) {
  const [on, setOn] = useState(false);

  const { RiveComponent, rive } = useRive({
    src,
    stateMachines: stateMachineName,
    autoplay: true,
  });

  const isOnInput = useStateMachineInput(rive, stateMachineName, 'isOn', on);

  const toggle = () => {
    const next = !on;
    setOn(next);
    if (isOnInput) {
      isOnInput.value = next;
    }
  };

  return (
    <button type="button" onClick={toggle} aria-pressed={on}>
      <RiveComponent style={{ width: 320, height: 180 }} />
    </button>
  );
}

설명: useRive로 캔버스를 렌더링하는 RiveComponent를 얻습니다. useStateMachineInput상태 머신 이름입력 이름이 에디터와 일치해야 합니다. React state와 Rive 입력을 동기화할 때는 “한쪽이 단일 진실 공급원”이 되도록 정하고, 이중 갱신을 피합니다.

6.3 Next.js 등 SSR 환경

Rive는 브라우저 API에 의존하므로 클라이언트 전용으로 로드하는 것이 안전합니다. dynamic(..., { ssr: false }) 패턴이나 클라이언트 컴포넌트 경계를 사용합니다.


7. Flutter 통합

Flutter에서는 공식 패키지 rive를 사용합니다. RiveAnimation 위젯 또는 RiveWidgetController로 상태 머신 입력을 제어합니다.

7.1 의존성

dependencies:
  rive: ^0.13.0

버전은 pub.dev의 rive에서 최신 호환 범위를 확인하세요.

7.2 예시 개념 코드

pubspec.yaml에 에셋 경로를 등록한 뒤, RiveAnimation.asset으로 로드하고 onInit에서 상태 머신을 붙입니다.

import 'package:flutter/material.dart';
import 'package:rive/rive.dart';

class RiveDemo extends StatefulWidget {
  const RiveDemo({super.key});

  @override
  State<RiveDemo> createState() => _RiveDemoState();
}

class _RiveDemoState extends State<RiveDemo> {
  StateMachineController? _controller;
  SMIBool? _hover;

  void _onRiveInit(Artboard artboard) {
    final controller =
        StateMachineController.fromArtboard(artboard, 'State Machine 1');
    if (controller == null) return;
    artboard.addController(controller);
    _hover = controller.findInput<bool>('hover') as SMIBool?;
    _controller = controller;
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) => _hover?.value = true,
      onTapUp: (_) => _hover?.value = false,
      child: RiveAnimation.asset(
        'assets/ui.riv',
        onInit: _onRiveInit,
        fit: BoxFit.contain,
      ),
    );
  }
}

설명: StateMachineController.fromArtboard로 에디터에서 지정한 상태 머신 이름을 연결합니다. findInput<bool> 등으로 입력 핸들을 얻어 값을 바꿉니다. 패키지 버전에 따라 헬퍼 이름이 조금 다를 수 있으므로, 사용 중인 rive 버전의 공식 문서를 함께 확인하십시오. 위젯이 dispose될 때 컨트롤러를 dispose하지 않으면 리소스가 남을 수 있습니다.


8. 런타임 API

플랫폼별 이름은 다르지만 개념은 공통입니다.

8.1 로드와 재생

  • 파일 로드: URL 또는 바이트 버퍼에서 .riv 파싱.
  • 아트보드 선택: 한 파일에 여러 아트보드가 있을 때 이름으로 선택.
  • 애니메이션 재생: 단순 클립 재생은 play 계열 API.
  • 상태 머신: stateMachineName으로 인스턴스를 만든 뒤 입력 핸들을 획득.

8.2 입력 조작

  • Boolean/Number: .value 또는 동등한 setter로 갱신.
  • Trigger: fire() 또는 값을 true로 잠깐 올렸다 내리는 패턴(런타임 버전에 따름).

8.3 이벤트

일부 런타임은 애니메이션 이벤트(사운드 큐, 앱 로직 트리거)를 지원합니다. 에디터에서 이벤트를 쏘고, 앱에서 구독하는 방식으로 애니메이션과 사운드·햅틱을 동기화할 수 있습니다.

8.4 레이아웃

Fit, Alignment비율 유지·크롭·확대를 제어합니다. 반응형 UI에서는 캔버스/위젯 크기 변경 시 resizeDrawingSurfaceToCanvas(웹) 등으로 드로잉 버퍼를 맞춥니다.


9. 성능 최적화

9.1 에셋 측면

  • 레이어·클립 수를 줄이고, 보이지 않는 객체는 숨김 처리합니다.
  • 과도한 블러·클립 마스크는 GPU 부담이 큽니다. 모바일 저사양 기기를 타깃이면 단순화합니다.
  • 텍스트를 벡터로만 억지로 쓰기보다, 필요 시 이미지·시스템 폰트와 병행하는 전략도 검토합니다.

9.2 런타임 측면

  • 화면 밖으로 스크롤된 Rive는 일시 정지하거나 DOM에서 분리합니다.
  • 동시 인스턴스 수를 제한하고, 리스트에서는 가상 스크롤과 함께 재사용합니다.
  • WebGLCanvas 중 프로파일링해 선택합니다(장면 복잡도·기기별 차이).

9.3 메모리·수명

  • SPA에서 라우트 전환 시 cleanup/dispose를 호출합니다.
  • 대용량 .riv지연 로드하고, 필요 시 코덱/버전을 에디터와 맞춥니다.

10. Lottie vs Rive

구분LottieRive
출발점After Effects 워크플로 중심전용 에디터 + 런타임 일체
상태·입력제한적(바디모션·표현에 의존)상태 머신·입력이 1급
파일JSON(텍스트).riv(바이너리)
강점모션 디자이너 풀 넓음, 단순 재생 가벼움인터랙티브 UI·게임성 피드백
주의복잡한 AE 이펙트는 지원 제한팀 학습·파이프라인 전환 비용

선택 가이드: “재생만 하면 된다”면 Lottie가 단순합니다. “사용자 입력과 상태가 애니메이션과 강하게 엮인다”면 Rive가 구조적으로 유리합니다. 둘 다 쓰는 것도 가능하며, 역할을 나누는 기준(마케팅 루프는 Lottie, 핵심 UI 마이크로 인터랙션은 Rive)을 팀 규약으로 정하면 혼선이 줄어듭니다.


11. 트러블슈팅

  • 입력이 반응하지 않음: 상태 머신 이름·입력 철자가 코드와 완전히 동일한지 확인합니다. 공백·대소문자까지 포함합니다.
  • 캔버스가 비어 보임: 로드 URL이 잘못되었거나, 캔버스 크기가 0입니다. 개발자 도구 네트워크 탭에서 .riv 요청 상태를 확인합니다.
  • 흐릿하게 보임: DPR을 반영한 리사이즈가 빠졌을 수 있습니다. resizeDrawingSurfaceToCanvas 호출 여부를 점검합니다.
  • 메모리 증가: 라우트 이동 후 이전 인스턴스가 정리되지 않았을 수 있습니다. cleanup/dispose를 연결합니다.

12. 정리

Rive는 벡터 그래픽 + 애니메이션 + 상태 머신을 한 파일로 묶어, 디자이너와 개발자가 입력 계약만으로 협업할 수 있게 합니다. 웹·React·Flutter 모두 공식 런타임이 제공되므로, 에디터에서 상태와 이름을 엄격히 관리하고, 앱 쪽에서는 입력 동기화·수명 관리·성능(인스턴스 수·일시정지)만 신경 쓰면 프로덕션에 도입하기 충분합니다. Lottie와 경쟁 관계라기보다 요구사항이 다른 인접 도구로 이해하고 선택하는 것이 좋습니다.


참고