rlottie-wasm-vue-player
Version:
A Vue 3 component for the rlottie-wasm animation player
589 lines (490 loc) • 16.4 kB
Markdown
# Rlottie WASM Vue Player
A Vue 3 component for the rlottie-wasm animation player. This package allows you to play Lottie animations in your Vue applications using the rlottie WebAssembly module.
## Improved Usage Experience
With this package, you can enjoy a seamless and efficient experience when working with Lottie animations in your Vue applications. The key benefits include:
- **Zero configuration required** - All WASM and JS assets are automatically included
- **Simple import** - Just `import { RlottiePlayer } from 'rlottie-vue-player'` and you're ready to go
- Play, pause, stop, and seek Lottie animations
- Control playback speed
- Customize layer colors, opacity, position, scale, and rotation
- Responsive design
- Event handling for animation lifecycle
## Installation
```bash
npm install rlottie-wasm-vue-player
```
## Setup
### 1. Install the package
Install the package using npm or yarn:
```bash
npm install rlottie-wasm-vue-player
# or
yarn add rlottie-wasm-vue-player
```
That's it! No need to manually copy any files. All required WASM and JS assets are automatically included in the package.
### 2. Import and use the component
No additional script loading is required. All necessary WASM and JS files are automatically loaded when you import the component.
## Usage
### Register as a Vue plugin (global component)
```js
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import RlottieVuePlayer from 'rlottie-wasm-vue-player';
const app = createApp(App);
// Register the plugin with optional configuration
app.use(RlottieVuePlayer, {
// Optional: custom path to WASM assets if you need to override the default
// wasmPath: '/custom-path'
});
app.mount('#app');
```
### Use as a local component
```js
// YourComponent.vue
import { RlottiePlayer } from 'rlottie-wasm-vue-player';
export default {
components: {
RlottiePlayer
}
};
```
### Basic Example
```vue
<template>
<RlottiePlayer :src="BirthdayCake" :autoplay="true" :loop="true" :speed="1" />
</template>
<script setup>
import { RlottiePlayer } from 'rlottie-wasm-vue-player';
import BirthdayCake from 'somewhere/BirthdayCakeColorful.json';
</script>
```
### Comprehensive Example of Usage Pattern
```vue
<template>
<div class="lottie-demo">
<h1>Lottie Animation Player Demo</h1>
<!-- Animation Player -->
<section class="player-section">
<div class="player-display">
<RlottiePlayer
ref="player"
:src="animationData"
:width="displaySize.width"
:height="displaySize.height"
:autoplay="playbackSettings.autoplay"
:loop="playbackSettings.loop"
:speed="playbackSettings.speed"
:layers="layerCustomizations"
@load="onAnimationLoaded"
@play="isPlaying = true"
@pause="isPlaying = false"
@stop="isPlaying = false"
@error="onAnimationError"
@complete="onAnimationComplete"
/>
</div>
<!-- Basic Playback Controls -->
<div class="control-panel">
<h2>Playback Controls</h2>
<div class="control-buttons">
<button class="control-btn" @click="playAnimation" :disabled="isPlaying">Play</button>
<button class="control-btn" @click="pauseAnimation" :disabled="!isPlaying">Pause</button>
<button class="control-btn" @click="stopAnimation">Stop</button>
</div>
<div class="progress-control">
<label>
<span>Progress: {{ progressValue }}%</span>
<input type="range" min="0" max="100" v-model.number="progressValue" @input="seekToPosition" />
</label>
</div>
<div class="speed-control">
<label>
<span>Speed: {{ playbackSettings.speed }}x</span>
<input type="range" min="0.1" max="5" step="0.1" v-model.number="playbackSettings.speed" />
</label>
</div>
<div class="playback-options">
<label>
<input type="checkbox" v-model="playbackSettings.autoplay" />
Autoplay
</label>
<label>
<input type="checkbox" v-model="playbackSettings.loop" />
Loop
</label>
</div>
</div>
</section>
<!-- Animation Source Controls -->
<section class="source-section">
<h2>Animation Source</h2>
<div class="source-controls">
<button class="source-btn" @click="loadSampleAnimation">Load Sample Animation</button>
</div>
<div class="paste-json">
<h4>Or paste animation JSON:</h4>
<textarea
v-model="jsonInput"
placeholder="Paste Lottie JSON here..."
rows="5"
></textarea>
<button @click="loadFromJsonInput">Load JSON</button>
</div>
</section>
<!-- Layer Customization -->
<section class="customization-section" v-if="targetLayerPath">
<h2>Layer Customization</h2>
<div class="layer-path-input">
<label>
Layer Path:
<input
type="text"
v-model="targetLayerPath"
placeholder="e.g. Shape Layer 1"
/>
</label>
</div>
<div class="customization-panels">
<!-- Color Controls -->
<div class="customization-panel">
<h3>Color</h3>
<div class="color-controls">
<label>
R: <input type="range" min="0" max="255" v-model.number="colorSettings.r" @input="updateLayerColor" />
<span>{{ colorSettings.r }}</span>
</label>
<label>
G: <input type="range" min="0" max="255" v-model.number="colorSettings.g" @input="updateLayerColor" />
<span>{{ colorSettings.g }}</span>
</label>
<label>
B: <input type="range" min="0" max="255" v-model.number="colorSettings.b" @input="updateLayerColor" />
<span>{{ colorSettings.b }}</span>
</label>
</div>
</div>
<!-- Opacity Controls -->
<div class="customization-panel">
<h3>Opacity</h3>
<label>
<input
type="range"
v-model.number="opacityValue"
min="0"
max="1"
step="0.1"
@input="updateLayerOpacity"
/>
<span>{{ opacityValue }}</span>
</label>
</div>
<!-- Stroke Width Controls -->
<div class="customization-panel">
<h3>Stroke Width</h3>
<label>
<input
type="range"
v-model.number="strokeWidthValue"
min="1"
max="20"
@input="updateStrokeWidth"
/>
<span>{{ strokeWidthValue }}</span>
</label>
</div>
<!-- Position Controls -->
<div class="customization-panel">
<h3>Position</h3>
<div class="position-controls">
<label>
X: <input type="number" v-model.number="positionValues.x" @change="updatePosition" />
</label>
<label>
Y: <input type="number" v-model.number="positionValues.y" @change="updatePosition" />
</label>
</div>
</div>
<!-- Scale Controls -->
<div class="customization-panel">
<h3>Scale</h3>
<div class="scale-controls">
<label>
Width: <input type="number" v-model.number="scaleValues.width" step="0.1" @change="updateScale" />
</label>
<label>
Height: <input type="number" v-model.number="scaleValues.height" step="0.1" @change="updateScale" />
</label>
</div>
</div>
<!-- Rotation Controls -->
<div class="customization-panel">
<h3>Rotation</h3>
<label>
<input
type="range"
v-model.number="rotationValue"
min="0"
max="360"
@input="updateRotation"
/>
<span>{{ rotationValue }}°</span>
</label>
</div>
</div>
</section>
<!-- Animation Properties -->
<section class="properties-section" v-if="animationProperties">
<h2>Animation Properties</h2>
<pre>{{ JSON.stringify(animationProperties, null, 2) }}</pre>
</section>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { RlottiePlayer } from 'rlottie-wasm-vue-player';
import BirthdayCakeLottieJSON from 'src/lotties/BirthdayCakeColorful.json';
// ------------------------
// Player Configuration
// ------------------------
// Reference to the player component instance
const player = ref(null);
// Animation data source
const animationData = ref('');
const jsonInput = ref(BirthdayCakeLottieJSON);
// Display dimensions
const displaySize = reactive({
width: 300,
height: 300
});
// Playback settings
const playbackSettings = reactive({
autoplay: true,
loop: true,
speed: 1
});
// Playback state
const isPlaying = ref(false);
const progressValue = ref(0);
// Animation metadata
const animationProperties = ref(null);
// ------------------------
// Layer Customization
// ------------------------
// Target layer to customize
const targetLayerPath = ref(''); // e.g., 'Shape Layer 1'
// Color settings
const colorSettings = reactive({
r: 255,
g: 0,
b: 0
});
// Other customization values
const opacityValue = ref(1);
const strokeWidthValue = ref(5);
const positionValues = reactive({ x: 0, y: 0 });
const scaleValues = reactive({ width: 1, height: 1 });
const rotationValue = ref(0);
// Collection of all layer customizations
const layerCustomizations = ref({});
// ------------------------
// Playback Control Methods
// ------------------------
// Start animation playback
const playAnimation = () => {
if (player.value) {
player.value.play();
}
};
// Pause animation playback
const pauseAnimation = () => {
if (player.value) {
player.value.pause();
}
};
// Stop animation and reset to first frame
const stopAnimation = () => {
if (player.value) {
player.value.stop();
}
};
// Seek to a specific position in the animation
const seekToPosition = () => {
if (player.value) {
player.value.seek(progressValue.value);
}
};
// ------------------------
// Animation Loading
// ------------------------
// Load a sample animation from a URL
const loadSampleAnimation = () => {
animationData.value = '/sample.json';
targetLayerPath.value = 'Shape Layer 1'; // Default layer path for the sample
};
// Load animation from JSON input (string or object)
const loadFromJsonInput = () => {
if (typeof jsonInput.value === 'string') {
try {
// Parse string input into object
animationData.value = JSON.parse(jsonInput.value);
} catch (e) {
alert('Invalid JSON string: ' + e.message);
animationData.value = null;
}
} else if (typeof jsonInput.value === 'object' && jsonInput.value !== null) {
// Use direct object reference
animationData.value = jsonInput.value;
} else {
alert('JSON input is empty or invalid.');
animationData.value = null;
}
};
// ------------------------
// Event Handlers
// ------------------------
// Called when animation is successfully loaded
const onAnimationLoaded = (data) => {
console.log('Animation loaded successfully:', data);
updateAnimationProperties();
};
// Called when animation fails to load
const onAnimationError = (error) => {
console.error('Animation error:', error);
alert('Failed to load animation: ' + (error.message || error));
};
// Called when animation playback completes (only if loop is false)
const onAnimationComplete = () => {
console.log('Animation playback complete');
isPlaying.value = false;
};
// ------------------------
// Animation Properties
// ------------------------
// Fetch and update animation properties from the player
const updateAnimationProperties = () => {
if (player.value) {
animationProperties.value = player.value.getProperties();
}
};
// ------------------------
// Layer Customization Methods
// ------------------------
// Update layer color
const updateLayerColor = () => {
updateLayer({
color: { r: colorSettings.r, g: colorSettings.g, b: colorSettings.b }
});
};
// Update layer opacity
const updateLayerOpacity = () => {
updateLayer({
opacity: opacityValue.value
});
};
// Update stroke width
const updateStrokeWidth = () => {
updateLayer({
strokeWidth: strokeWidthValue.value
});
};
// Update layer position
const updatePosition = () => {
updateLayer({
position: { x: positionValues.x, y: positionValues.y }
});
};
// Update layer scale
const updateScale = () => {
updateLayer({
scale: { width: scaleValues.width, height: scaleValues.height }
});
};
// Update layer rotation
const updateRotation = () => {
updateLayer({
rotation: rotationValue.value
});
};
// Helper method to update layer customizations
const updateLayer = (properties) => {
if (!targetLayerPath.value) return;
const path = targetLayerPath.value;
const currentLayerProps = layerCustomizations.value[path] || {};
layerCustomizations.value = {
...layerCustomizations.value,
[path]: {
...currentLayerProps,
...properties
}
};
};
// ------------------------
// Lifecycle Hooks
// ------------------------
onMounted(() => {
// Load the imported BirthdayCakeLottieJSON by default
if (jsonInput.value) {
animationData.value = jsonInput.value;
} else {
console.warn('Default Lottie JSON is not available.');
}
});
</script>
```
## Component Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `src` | String, Object | - | Animation source - stringified JSON or URL to JSON file |
| `width` | Number, String | 300 | Width of the player |
| `height` | Number, String | 300 | Height of the player |
| `autoplay` | Boolean | false | Whether to autoplay the animation |
| `loop` | Boolean | true | Whether to loop the animation |
| `speed` | Number | 1 | Playback speed (1 is normal speed) |
| `background` | String | 'transparent' | Background color |
| `layers` | Object | {} | Layer customizations (see below) |
| `canvasId` | String | null | Optional custom canvas ID |
| `assetPath` | String | '' | Optional: Custom path to asset files (not required with default usage) |
## Layer Customization
The `layers` prop accepts an object with the following format:
```js
{
"keypath": {
color: { r: 255, g: 0, b: 0 },
opacity: 0.5,
strokeWidth: 2,
position: { x: 10, y: 20 },
scale: { width: 1.2, height: 0.8 },
rotation: 45
}
}
```
Where `keypath` is the path to the layer in the Lottie animation (e.g., "Shape Layer 1").
## Component Methods
| Method | Description |
|--------|-------------|
| `play()` | Starts or resumes animation playback |
| `pause()` | Pauses animation playback |
| `stop()` | Stops animation and resets to the first frame |
| `seek(percentage)` | Seeks to a specific frame based on percentage (0-100) |
| `getProperties()` | Returns properties of the current animation |
## Global API
The package also exposes a global API on `window.RlottieVuePlayer` with the following methods:
| Method | Description |
|--------|-------------|
| `loadAnimation(jsonData)` | Loads Lottie animation data (stringified JSON) |
| `play()` | Starts or resumes animation playback |
| `pause()` | Pauses animation playback |
| `stop()` | Stops animation and resets to the first frame |
| `seek(percentage)` | Seeks to a specific frame based on percentage (0-100) |
| `getAnimationProperties()` | Returns properties of the current animation |
| `setPlaySpeed(speed)` | Sets the playback speed |
| `resize(width, height)` | Informs the player of the canvas dimensions |
| `setLayerColor(keypath, r, g, b)` | Sets the fill and stroke color of a layer |
| `setLayerOpacity(keypath, opacity)` | Sets the fill and stroke opacity of a layer (0-1) |
| `setStrokeWidth(keypath, width)` | Sets the stroke width of a layer |
| `setPosition(keypath, x, y)` | Sets the position of a layer |
| `setScale(keypath, width, height)` | Sets the scale of a layer |
| `setRotation(keypath, degree)` | Sets the rotation of a layer |
## License
MIT