# Rive Generator

> 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.

- Skill: `stevysmith/rive-generator` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add stevysmith/rive-generator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/stevysmith/rive-generator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: stevysmith (https://skillmd.com/u/stevysmith)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/stevysmith/rive-generator

---


# Rive Generator Skill

Generate Rive animations programmatically using TypeScript.

## Installation

First, install the npm package:

```bash
npm install @stevysmith/rive-generator
```

## Quick Start

```typescript
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

```bash
# With TypeScript (Node 22+)
node --experimental-strip-types generate.ts

# Or compile first
npx tsc generate.ts && node generate.js
```

## API 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

```typescript
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 black
```

## PropertyKey

```typescript
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

1. **Use a single Node container** - All shapes must be children of ONE Node under the Artboard.

2. **Gradient shapes must be LAST** - Add shapes with gradients after solid color shapes.

3. **DO NOT use CubicVertex** - Use `addVertex()` only. Approximate curves with many straight vertices.

4. **DO NOT use cornerRadius** - Use plain rectangles or PointsPath for rounded corners.

5. **First shape position bug** - Add a tiny transparent dummy shape first:
   ```typescript
   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

```typescript
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](https://rive.app) - Import to view/edit
- [rive.app/preview](https://rive.app/preview) - Quick online preview
- Your app using `@rive-app/canvas` or `@rive-app/react-canvas`

