rive

安装量: 56
排名: #13284

安装

npx skills add https://github.com/bowtiedswan/rive-skills --skill rive
Rive Animation Platform Skill
This skill provides comprehensive knowledge for working with Rive, an interactive animation platform that enables creating and running interactive graphics across web, mobile, and game platforms.
Overview
Rive is a design and animation tool that produces lightweight, interactive graphics with a powerful runtime. Key capabilities:
Scripting
Write Luau scripts directly in the Rive Editor to extend functionality
State Machines
Create complex interactive animations with states and transitions
Data Binding
Connect animations to dynamic data via View Models
Cross-Platform Runtimes
Deploy to Web (React/Next.js), iOS, Android, Flutter, Unity, Unreal When to Use This Skill Use this skill when: Creating Rive scripts (Node, Layout, Converter, PathEffect protocols) Integrating Rive animations into React or Next.js applications Implementing scroll-based or parallax animations with Rive Working with Rive state machines and inputs at runtime Using Rive's drawing API for custom rendering Building interactive animations with pointer events Implementing data binding with View Models Quick Start React/Next.js Integration import { useRive } from '@rive-app/react-canvas' ; function MyAnimation ( ) { const { rive , RiveComponent } = useRive ( { src : '/animation.riv' , stateMachines : 'MainStateMachine' , autoplay : true , } ) ; return < RiveComponent style = { { width : 400 , height : 400 } } /> ; } Controlling State Machine Inputs const { rive , RiveComponent } = useRive ( { src : '/animation.riv' , stateMachines : 'State Machine 1' , } ) ; // Get and set inputs const scrollInput = rive ?. stateMachineInputs ( 'State Machine 1' ) ?. find ( i => i . name === 'scrollProgress' ) ; // Update on scroll (0-100 range example) scrollInput ?. value = scrollProgress * 100 ; Rive Scripting (Luau) Rive scripts use Luau (a Lua variant) and follow specific protocols. For detailed API reference, see @references/rive-scripting-api.md . Script Protocols Overview Protocol Purpose Key Functions Node Custom drawing/rendering init() , advance(seconds) , draw(renderer) Layout Custom layout behaviors measure() , resize(size) + Node functions Converter Data transformation convert(input) , reverseConvert(input) PathEffect Path modifications init() , update(pathData) , advance(seconds) Test Testing harnesses Unit testing scripts Node Script Template -- Define script data type with inputs type MyNode = { color : Input < Color

, speed : Input < number

, path : Path , paint : Paint , } function init ( self : MyNode ) : boolean self . path = Path . new ( ) self . paint = Paint . new ( ) self . paint . style = 'fill' return true end function advance ( self : MyNode , seconds : number ) : boolean -- Animation logic here, called every frame return true -- Return true to keep receiving advance calls end function update ( self : MyNode ) -- Called when any input changes end function draw ( self : MyNode , renderer : Renderer ) renderer : drawPath ( self . path , self . paint ) end return function ( ) : Node < MyNode

return { init = init , advance = advance , update = update , draw = draw , color = Color . rgba ( 255 , 255 , 255 , 255 ) , speed = 1.0 , path = late ( ) , paint = late ( ) , } end Layout Script Template type MyLayout = { spacing : Input < number

, } function measure ( self : MyLayout ) : Vec2D -- Return desired size (used when Fit type is Hug) return Vec2D . xy ( 200 , 100 ) end function resize ( self : MyLayout , size : Vec2D ) -- Called when layout receives new size print ( "New size:" , size . x , size . y ) end -- Include Node functions (init, advance, draw) as needed return function ( ) : Layout < MyLayout

return { measure = measure , resize = resize , spacing = 10 , } end Converter Script Template type NumberToString = { } function convert ( self : NumberToString , input : DataInputs ) : DataOutput local dv : DataValueString = DataValue . string ( ) if input : isNumber ( ) then dv . value = tostring ( ( input :: DataValueNumber ) . value ) else dv . value = "" end return dv end function reverseConvert ( self : NumberToString , input : DataOutput ) : DataInputs local dv : DataValueNumber = DataValue . number ( ) if input : isString ( ) then dv . value = tonumber ( ( input :: DataValueString ) . value ) or 0 end return dv end return function ( ) : Converter < NumberToString , DataValueNumber , DataValueString

return { convert = convert , reverseConvert = reverseConvert , } end PathEffect Script Template type WaveEffect = { amplitude : Input < number

, frequency : Input < number

, context : Context , } function init ( self : WaveEffect , context : Context ) : boolean self . context = context return true end function update ( self : WaveEffect , inPath : PathData ) : PathData local path = Path . new ( ) -- Transform path geometry here for i = 1 ,

inPath do local cmd = inPath [ i ] -- Process each PathCommand end return path end function advance ( self : WaveEffect , seconds : number ) : boolean -- Called each frame for animated effects return true end return function ( ) : PathEffect < WaveEffect

return { init = init , update = update , advance = advance , amplitude = 10 , frequency = 1 , context = late ( ) , } end Script Inputs Define inputs to expose configurable properties in the Rive Editor: type MyNode = { -- Basic inputs myNumber : Input < number

, myColor : Input < Color

, myString : string , -- Non-input, internal use only -- View Model inputs myViewModel : Input < Data . Character

, -- Artboard inputs (for dynamic instantiation) enemyTemplate : Input < Artboard < Data . Enemy

, } -- Access input values function init ( self : MyNode ) : boolean print ( "Number:" , self . myNumber ) print ( "Color:" , self . myColor ) print ( "ViewModel property:" , self . myViewModel . health . value ) return true end -- Listen for changes function init ( self : MyNode ) : boolean self . myNumber : addListener ( function ( ) print ( "myNumber changed!" ) end ) return true end -- Mark inputs assigned at runtime return function ( ) : Node < MyNode

return { init = init , myNumber = 0 , myColor = Color . rgba ( 255 , 255 , 255 , 255 ) , myString = "default" , myViewModel = late ( ) , -- Assigned via Editor enemyTemplate = late ( ) , } end Pointer Events Handle touch/mouse interactions: function pointerDown ( self : MyNode , event : PointerEvent ) print ( "Position:" , event . position . x , event . position . y ) print ( "Pointer ID:" , event . id ) -- For multi-touch event : hit ( ) -- Mark as handled end function pointerMove ( self : MyNode , event : PointerEvent ) -- Handle drag event : hit ( ) end function pointerUp ( self : MyNode , event : PointerEvent ) event : hit ( ) end function pointerExit ( self : MyNode , event : PointerEvent ) event : hit ( ) end return function ( ) : Node < MyNode

return { pointerDown = pointerDown , pointerMove = pointerMove , pointerUp = pointerUp , pointerExit = pointerExit , } end Dynamic Component Instantiation Create artboard instances at runtime: type Enemy = { artboard : Artboard < Data . Enemy

, position : Vec2D , } type GameScene = { enemyTemplate : Input < Artboard < Data . Enemy

, enemies : { Enemy } , } function createEnemy ( self : GameScene , x : number , y : number ) local enemy = self . enemyTemplate : instance ( ) local entry : Enemy = { artboard = enemy , position = Vec2D . xy ( x , y ) , } table . insert ( self . enemies , entry ) end function advance ( self : GameScene , seconds : number ) : boolean for _ , enemy in self . enemies do enemy . artboard : advance ( seconds ) end return true end function draw ( self : GameScene , renderer : Renderer ) for _ , enemy in self . enemies do renderer : save ( ) renderer : transform ( Mat2D . fromTranslate ( enemy . position . x , enemy . position . y ) ) enemy . artboard : draw ( renderer ) renderer : restore ( ) end end Data Binding Access View Model from scripts: function init ( self : MyNode , context : Context ) : boolean local vm = context : viewModel ( ) -- Get properties local score = vm : getNumber ( 'score' ) local name = vm : getString ( 'playerName' ) -- Set values if score then score . value = 100 end -- Listen for changes if score then score : addListener ( function ( ) print ( "Score changed to:" , score . value ) end ) end -- Access nested view models local settings = vm : getViewModel ( 'settings' ) local volume = settings : getNumber ( 'volume' ) return true end Drawing API For complete API reference, see @references/rive-scripting-api.md . Path Operations local path = Path . new ( ) -- Drawing commands path : moveTo ( Vec2D . xy ( 0 , 0 ) ) path : lineTo ( Vec2D . xy ( 100 , 0 ) ) path : quadTo ( Vec2D . xy ( 150 , 50 ) , Vec2D . xy ( 100 , 100 ) ) path : cubicTo ( Vec2D . xy ( 75 , 150 ) , Vec2D . xy ( 25 , 150 ) , Vec2D . xy ( 0 , 100 ) ) path : close ( ) -- Reset path for reuse path : reset ( ) -- Measure path local length = path : measure ( ) local contours = path : contours ( ) Paint Configuration local paint = Paint . new ( ) paint . style = 'fill' -- or 'stroke' paint . color = Color . rgba ( 255 , 128 , 0 , 255 ) paint . thickness = 3 -- For strokes paint . cap = 'round' -- 'butt', 'round', 'square' paint . join = 'round' -- 'miter', 'round', 'bevel' paint . blendMode = 'srcOver' -- Gradient fills paint . gradient = Gradient . linear ( Vec2D . xy ( 0 , 0 ) , Vec2D . xy ( 100 , 100 ) , { GradientStop . new ( 0 , Color . hex ( '#FF0000' ) ) , GradientStop . new ( 1 , Color . hex ( '#0000FF' ) ) } ) Renderer Operations function draw ( self : MyNode , renderer : Renderer ) renderer : save ( ) -- Transform renderer : transform ( Mat2D . fromScale ( 2 , 2 ) ) renderer : transform ( Mat2D . fromRotation ( math . pi / 4 ) ) renderer : transform ( Mat2D . fromTranslate ( 50 , 50 ) ) -- Draw path renderer : drawPath ( self . path , self . paint ) -- Draw image renderer : drawImage ( self . image , ImageSampler . linear , 'srcOver' , 1.0 ) -- Clipping renderer : clipPath ( self . clipPath ) renderer : restore ( ) end React/Next.js Runtime Reference For detailed runtime API, see @references/rive-react-runtime.md . Installation

Recommended

npm install @rive-app/react-canvas

Alternative options

npm install @rive-app/react-canvas-lite

Smaller, no Rive Text

npm install @rive-app/react-webgl

WebGL renderer

npm install @rive-app/react-webgl2

Rive Renderer (WebGL2)

useRive Hook
import
{
useRive
,
useStateMachineInput
}
from
'@rive-app/react-canvas'
;
function
Animation
(
)
{
const
{
rive
,
RiveComponent
}
=
useRive
(
{
src
:
'/animation.riv'
,
artboard
:
'MainArtboard'
,
stateMachines
:
'StateMachine1'
,
autoplay
:
true
,
layout
:
new
Layout
(
{
fit
:
Fit
.
Contain
,
alignment
:
Alignment
.
Center
,
}
)
,
}
)
;
// Playback control
const
play
=
(
)
=>
rive
?.
play
(
)
;
const
pause
=
(
)
=>
rive
?.
pause
(
)
;
const
stop
=
(
)
=>
rive
?.
stop
(
)
;
return
(
<
RiveComponent
style
=
{
{
width
:
'100%'
,
height
:
'100vh'
}
}
onMouseEnter
=
{
(
)
=>
rive
?.
play
(
)
}
/>
)
;
}
State Machine Inputs
function
InteractiveAnimation
(
)
{
const
{
rive
,
RiveComponent
}
=
useRive
(
{
src
:
'/interactive.riv'
,
stateMachines
:
'Controls'
,
autoplay
:
true
,
}
)
;
useEffect
(
(
)
=>
{
if
(
!
rive
)
return
;
const
inputs
=
rive
.
stateMachineInputs
(
'Controls'
)
;
// Number input
const
progress
=
inputs
?.
find
(
i
=>
i
.
name
===
'progress'
)
;
if
(
progress
)
progress
.
value
=
50
;
// Boolean input
const
isActive
=
inputs
?.
find
(
i
=>
i
.
name
===
'isActive'
)
;
if
(
isActive
)
isActive
.
value
=
true
;
// Trigger input
const
onClick
=
inputs
?.
find
(
i
=>
i
.
name
===
'onClick'
)
;
onClick
?.
fire
(
)
;
}
,
[
rive
]
)
;
return
<
RiveComponent
/>
;
}
Scroll-Based Animation
function
ScrollAnimation
(
)
{
const
{
rive
,
RiveComponent
}
=
useRive
(
{
src
:
'/scroll-animation.riv'
,
stateMachines
:
'ScrollMachine'
,
autoplay
:
true
,
}
)
;
const
containerRef
=
useRef
<
HTMLDivElement
>
(
null
)
;
useEffect
(
(
)
=>
{
if
(
!
rive
)
return
;
const
progressInput
=
rive
.
stateMachineInputs
(
'ScrollMachine'
)
?.
find
(
i
=>
i
.
name
===
'scrollProgress'
)
;
const
handleScroll
=
(
)
=>
{
if
(
!
containerRef
.
current
||
!
progressInput
)
return
;
const
rect
=
containerRef
.
current
.
getBoundingClientRect
(
)
;
const
windowHeight
=
window
.
innerHeight
;
// Calculate scroll progress (0-100)
const
progress
=
Math
.
max
(
0
,
Math
.
min
(
100
,
(
(
windowHeight
-
rect
.
top
)
/
(
windowHeight
+
rect
.
height
)
)
*
100
)
)
;
progressInput
.
value
=
progress
;
}
;
window
.
addEventListener
(
'scroll'
,
handleScroll
)
;
return
(
)
=>
window
.
removeEventListener
(
'scroll'
,
handleScroll
)
;
}
,
[
rive
]
)
;
return
(
<
div
ref
=
{
containerRef
}
style
=
{
{
height
:
'200vh'
}
}
>
<
div
style
=
{
{
position
:
'sticky'
,
top
:
0
,
height
:
'100vh'
}
}
>
<
RiveComponent
style
=
{
{
width
:
'100%'
,
height
:
'100%'
}
}
/>
</
div
>
</
div
>
)
;
}
Event Handling
function
AnimationWithEvents
(
)
{
const
{
rive
,
RiveComponent
}
=
useRive
(
{
src
:
'/events.riv'
,
stateMachines
:
'Main'
,
autoplay
:
true
,
}
)
;
useEffect
(
(
)
=>
{
if
(
!
rive
)
return
;
// Listen for Rive events
rive
.
on
(
'statechange'
,
(
event
)
=>
{
console
.
log
(
'State changed:'
,
event
.
data
)
;
}
)
;
rive
.
on
(
'riveevent'
,
(
event
)
=>
{
console
.
log
(
'Rive event:'
,
event
.
data
.
name
)
;
}
)
;
}
,
[
rive
]
)
;
return
<
RiveComponent
/>
;
}
Animation API Reference
Animation Object
local
anim
=
artboard
:
animation
(
'AnimationName'
)
-- Control
anim
:
advance
(
0.016
)
-- Advance by time in seconds
anim
:
setTime
(
1.5
)
-- Set time in seconds
anim
:
setTimeFrames
(
30
)
-- Set time in frames
anim
:
setTimePercentage
(
0.5
)
-- Set time as 0-1
-- Properties
local
duration
=
anim
.
duration
Artboard Object
local
artboard
=
self
.
myArtboard
:
instance
(
)
-- Properties
artboard
.
width
=
400
artboard
.
height
=
300
artboard
.
frameOrigin
=
true
-- Control
artboard
:
advance
(
seconds
)
artboard
:
draw
(
renderer
)
-- Access nodes and bounds
local
node
=
artboard
:
node
(
'NodeName'
)
local
minPt
,
maxPt
=
artboard
:
bounds
(
)
-- Pointer events
artboard
:
pointerDown
(
event
)
artboard
:
pointerUp
(
event
)
artboard
:
pointerMove
(
event
)
Best Practices
Performance
Reuse paths and paints
Create in
init()
, reuse in
draw()
Use fixed timestep
For consistent physics across devices
Minimize state machine inputs
Batch updates when possible
Lazy load .riv files
Especially for multiple animations
Code Organization
Separate concerns
Use different scripts for different behaviors
Use View Models
For complex state management
Type your scripts
Leverage Luau's type system
Scroll Animations
Use
scrollProgress
input
Map scroll position to 0-100 range
Debounce scroll handlers
Prevent performance issues
Use
sticky
positioning
For scroll-triggered scenes
Consider Intersection Observer
For triggering animations on visibility
Troubleshooting
Common Issues
Script not in list
Check Assets Panel and Problems Panel
Animation not playing
Verify
autoplay
and state machine name
Inputs not updating
Ensure input names match exactly
Performance issues
Check for excessive path resets or redraws Debug Tools -- In scripts print ( "Debug:" , value ) -- Check Problems Panel in Rive Editor -- Use Debug Panel for runtime inspection Additional Resources Official Docs: https://rive.app/docs React Runtime: https://github.com/rive-app/rive-react Community: https://community.rive.app Discord: https://discord.com/invite/FGjmaTr Reference Documentation For detailed API reference and guides, see: Scripting & Core @references/rive-scripting-api.md - Complete Luau scripting API Editor Features @references/rive-editor-fundamentals.md - Interface, artboards, shapes, components @references/rive-animation-mode.md - Timeline, keyframes, easing, animation mixing @references/rive-state-machine.md - States, inputs, transitions, listeners, layers @references/rive-constraints.md - IK, Distance, Transform, Follow Path constraints @references/rive-layouts.md - Flexbox-like layouts, N-Slicing, scrolling @references/rive-manipulating-shapes.md - Bones, meshes, clipping, joysticks @references/rive-text.md - Fonts, text runs, modifiers, styles @references/rive-events.md - Rive events, audio events, runtime listening @references/rive-data-binding.md - View Models, lists, runtime data binding Web Runtimes @references/rive-react-runtime.md - React/Next.js integration @references/rive-web-runtime.md - Vanilla JS, Canvas, WebGL, WASM Mobile Runtimes @references/rive-flutter-runtime.md - Flutter widgets and controllers @references/rive-mobile-runtimes.md - iOS (Swift), Android (Kotlin), React Native Game Engine Runtimes @references/rive-game-runtimes.md - Unity, Unreal Engine, Defold
返回排行榜