Trigger when: (1) User wants to create a Rive animation programmatically, (2) User mentions "generate .riv file" or "create Rive animation", (3) User wants to see a visual animation created from code, (4) Working with the rive-generator project. Generate .riv files programmatically using TypeScript. Creates static shapes and animations. Requires npm package @stevysmith/rive-generator.
Resources
1Install
npx skillscat add stevysmith/rive-skills/rive-generator Install via the SkillsCat registry.
Rive Generator Skill
Generate Rive animations programmatically using TypeScript.
Installation
First, install the npm package:
npm install @stevysmith/rive-generatorQuick Start
import { writeFileSync } from 'fs';
import { RiveFile, hex } from '@stevysmith/rive-generator';
const riv = new RiveFile();
// Create artboard
const artboard = riv.addArtboard({
name: 'My Animation',
width: 400,
height: 400,
});
// Add shape at center
const shape = riv.addShape(artboard, {
name: 'MyShape',
x: 200,
y: 200,
});
// Add path (ellipse or rectangle)
riv.addEllipse(shape, { width: 100, height: 100 });
// Add fill with color
const fill = riv.addFill(shape);
riv.addSolidColor(fill, hex('#3498db'));
// Export
writeFileSync('my-animation.riv', riv.export());Running
# With TypeScript (Node 22+)
node --experimental-strip-types generate.ts
# Or compile first
npx tsc generate.ts && node generate.jsAPI Reference
RiveFile
Main class for building .riv files.
| Method | Description |
|---|---|
addArtboard(options) |
Add an artboard (canvas) |
addNode(parent, options) |
Add a transform group |
addShape(parent, options) |
Add a shape container |
addEllipse(shape, options) |
Add an ellipse/circle |
addRectangle(shape, options) |
Add a rectangle |
addPointsPath(shape, options) |
Add a custom vector path |
addVertex(path, options) |
Add a straight vertex |
addFill(shape, options) |
Add a fill |
addStroke(shape, options) |
Add a stroke |
addSolidColor(paint, color) |
Set solid color |
addLinearGradient(paint, options) |
Add linear gradient |
addRadialGradient(paint, options) |
Add radial gradient |
addGradientStop(gradient, options) |
Add gradient color stop |
addLinearAnimation(artboard, options) |
Add an animation |
addKeyedObject(animation, targetId) |
Link animation to object |
addKeyedProperty(keyedObject, propertyKey) |
Specify property to animate |
addKeyFrameDouble(keyedProperty, options) |
Add a keyframe |
export() |
Returns Uint8Array of .riv binary |
Colors
import { hex, rgba } from '@stevysmith/rive-generator';
hex('#ff0000') // Red
hex('#3498db') // Nice blue
rgba(255, 0, 0, 255) // Red with full opacity
rgba(0, 0, 0, 128) // Semi-transparent blackPropertyKey
import { PropertyKey } from '@stevysmith/rive-generator';
PropertyKey.x // X position
PropertyKey.y // Y position
PropertyKey.scaleX // X scale
PropertyKey.scaleY // Y scale
PropertyKey.rotation // Rotation (radians)Important Constraints
Use a single Node container - All shapes must be children of ONE Node under the Artboard.
Gradient shapes must be LAST - Add shapes with gradients after solid color shapes.
DO NOT use CubicVertex - Use
addVertex()only. Approximate curves with many straight vertices.DO NOT use cornerRadius - Use plain rectangles or PointsPath for rounded corners.
First shape position bug - Add a tiny transparent dummy shape first:
const dummy = riv.addShape(container, { name: 'Dummy', x: 0, y: 0 }); riv.addRectangle(dummy, { width: 1, height: 1 }); const dummyFill = riv.addFill(dummy); riv.addSolidColor(dummyFill, hex('#00000000'));
Animation Example
import { RiveFile, hex, PropertyKey } from '@stevysmith/rive-generator';
import { writeFileSync } from 'fs';
const riv = new RiveFile();
const artboard = riv.addArtboard({ name: 'Pulse', width: 200, height: 200 });
const shape = riv.addShape(artboard, { name: 'Circle', x: 100, y: 100 });
riv.addEllipse(shape, { width: 50, height: 50 });
const fill = riv.addFill(shape);
riv.addSolidColor(fill, hex('#e74c3c'));
const anim = riv.addLinearAnimation(artboard, {
name: 'pulse',
fps: 60,
duration: 60,
loop: 'pingPong',
});
const keyed = riv.addKeyedObject(anim, shape);
const scaleX = riv.addKeyedProperty(keyed, PropertyKey.scaleX);
riv.addKeyFrameDouble(scaleX, { frame: 0, value: 1.0, interpolation: 'cubic' });
riv.addKeyFrameDouble(scaleX, { frame: 30, value: 1.2, interpolation: 'cubic' });
riv.addKeyFrameDouble(scaleX, { frame: 60, value: 1.0, interpolation: 'cubic' });
const scaleY = riv.addKeyedProperty(keyed, PropertyKey.scaleY);
riv.addKeyFrameDouble(scaleY, { frame: 0, value: 1.0, interpolation: 'cubic' });
riv.addKeyFrameDouble(scaleY, { frame: 30, value: 1.2, interpolation: 'cubic' });
riv.addKeyFrameDouble(scaleY, { frame: 60, value: 1.0, interpolation: 'cubic' });
writeFileSync('pulse.riv', riv.export());Viewing Generated .riv Files
- Rive Editor - Import to view/edit
- rive.app/preview - Quick online preview
- Your app using
@rive-app/canvasor@rive-app/react-canvas