Skip to content

Conversation

@Brooooooklyn
Copy link
Owner

@Brooooooklyn Brooooooklyn commented Dec 19, 2025

Summary

Add support for loading and rendering Lottie animations using Skia's Skottie module.

Features

  • Load animations from JSON data (loadFromData) or file path (loadFromFile)
  • Embedded base64 images - Support for Lottie files with inline data:image/...;base64,... assets
  • Embedded font glyphs - Prioritize embedded vector glyph paths over system fonts via kPreferEmbeddedFonts
  • Animation control - Seek by frame (seekFrame) or time (seek)
  • Render to Canvas2D - Draw animation frames with configurable destination rect
  • Metadata access - Duration, FPS, frame count, dimensions, version

API

import { LottieAnimation } from '@napi-rs/canvas'

// Load from file
const animation = LottieAnimation.loadFromFile('animation.json')

// Or load from JSON string (with optional resource path for external assets)
const animation = LottieAnimation.loadFromData(jsonString, { resourcePath: '/path/to/assets' })

// Animation properties
animation.duration  // seconds
animation.fps       // frames per second
animation.frames    // total frame count
animation.width     // animation width
animation.height    // animation height
animation.version   // Lottie format version

// Playback control
animation.seekFrame(frameNumber)
animation.seek(timeInSeconds)

// Render to canvas
animation.render(ctx)  // render at original size
animation.render(ctx, { x: 0, y: 0, width: 800, height: 600 })  // render with dest rect

Example: Encode Lottie to MP4

See example/lottie-to-video.ts for a complete example using @napi-rs/webcodecs to encode a Lottie animation to MP4 video.

import { createCanvas, LottieAnimation } from '@napi-rs/canvas'
import { VideoEncoder, VideoFrame, Mp4Muxer } from '@napi-rs/webcodecs'

const animation = LottieAnimation.loadFromFile('animation.lottie')
const canvas = createCanvas(animation.width, animation.height)
const ctx = canvas.getContext('2d')

for (let frame = 0; frame < animation.frames; frame++) {
  animation.seekFrame(frame)
  animation.render(ctx)
  // encode frame...
}

Test plan

  • Load Lottie from JSON file
  • Load Lottie from JSON string with resource path
  • Render embedded base64 images
  • Render embedded font glyphs (text layers)
  • Extract .lottie (dotLottie) ZIP format at runtime
  • Encode animation to MP4 video

🤖 Generated with Claude Code

@Brooooooklyn Brooooooklyn changed the title feat feat: support Lottie API Dec 19, 2025
Add support for loading and rendering Lottie animations using Skia's Skottie module.

Features:
- Load animations from JSON data or file path
- Support for embedded base64 images via DataURIResourceProviderProxy
- Support for embedded font glyphs via kPreferEmbeddedFonts flag
- Animation playback control: seek by frame or time
- Render to Canvas2D context with configurable destination rect
- Access animation metadata: duration, fps, frames, dimensions, version

Example usage with @napi-rs/webcodecs to encode Lottie to MP4 video.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Brooooooklyn Brooooooklyn marked this pull request as ready for review December 19, 2025 10:33
Copilot AI review requested due to automatic review settings December 19, 2025 10:33
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive Lottie animation support to @napi-rs/canvas using Skia's Skottie module. The implementation enables loading, rendering, and controlling Lottie animations from JSON files or data.

Key Changes:

  • Added Skottie module integration with support for embedded base64 images and font glyphs
  • Implemented animation loading from files and JSON data with configurable resource paths
  • Exposed animation properties (duration, fps, frames, dimensions) and playback controls
  • Included video encoding example using @napi-rs/webcodecs

Reviewed changes

Copilot reviewed 12 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/sk.rs Added FFI bindings for Skottie C API and Rust wrapper with SkottieAnimation struct
src/lottie.rs Implemented NAPI bindings for JavaScript API with load methods and render function
src/lib.rs Exported new lottie module
skia-c/skia_c.hpp Added C API function declarations for Skottie operations
skia-c/skia_c.cpp Implemented C wrapper functions with base64 image and embedded font support
scripts/build-skia.js Enabled Skottie module in Skia build configuration
scripts/release-skia-binary.mjs Added Skottie-related libraries to release script
package.json Added @napi-rs/webcodecs and @oxc-node/cli dev dependencies
yarn.lock Updated lockfile with new dependency entries
index.d.ts Added TypeScript definitions for LottieAnimation class and related interfaces
index.js Exported LottieAnimation from main module
README.md Added comprehensive documentation with usage examples
example/lottie-to-video.ts Provided complete example of encoding Lottie to MP4 video
example/flat-lottie.json Added sample Lottie animation file with embedded assets
.gitignore Added output files from example to ignore list

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

import { readFileSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'


Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an extra empty line after the imports. Remove this blank line for consistency with the codebase formatting.

Suggested change

Copilot uses AI. Check for mistakes.

/// Load animation from file path
#[napi(factory, js_name = "loadFromFile")]
pub fn load_from_file(path: String, _options: Option<LottieAnimationOptions>) -> Result<Self> {
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _options parameter is unused in this function. The loadFromFile method should either use the options parameter (for consistency with loadFromData) or remove it from the function signature. If the parameter is kept, it should be passed to the underlying implementation or documented why it's not used.

Suggested change
pub fn load_from_file(path: String, _options: Option<LottieAnimationOptions>) -> Result<Self> {
pub fn load_from_file(path: String, options: Option<LottieAnimationOptions>) -> Result<Self> {
// Derive the resource path from options for API consistency with `loadFromData`.
// Currently, `SkottieAnimation::from_file` does not accept a resource path, so this
// is not passed through, but the parameter is retained for future compatibility.
let _resource_path = options
.as_ref()
.and_then(|o| o.resource_path.as_deref());

Copilot uses AI. Check for mistakes.
@Brooooooklyn Brooooooklyn merged commit ca1f5f5 into main Dec 19, 2025
85 of 87 checks passed
@Brooooooklyn Brooooooklyn deleted the lottie branch December 19, 2025 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants