ThorVG for Swift is a lightweight wrapper around the ThorVG C++ API, providing native support for vector graphics in Swift applications. This package currently only supports rendering Lottie animations and is actively evolving to include more features.
ThorVG Version: v0.14.7 (commit e3a6bf)
Supported Platforms: iOS 13.0+, macOS 10.15+
To integrate ThorVGSwift into your Swift project, use Swift Package Manager. Simply add the following line to the dependencies section of your Package.swift file:
dependencies: [
// ...
.package(url: "https://github.com/thorvg/thorvg.swift", from: "0.1.0")
]This Swift wrapper currently only supports rendering Lottie animations. As the package evolves, additional support for more content types will be added.
ThorVGSwift provides two levels of API:
- Low-Level API: Direct access to the rendering engine for frame-by-frame control
- High-Level Views API: Ready-to-use SwiftUI and UIKit views with playback controls
The low-level API closely follows the structure of the original ThorVG API, enabling rendering of Lottie frames to a buffer. This is useful when you need fine-grained control over frame rendering.
To start, create a Lottie instance using a desired local file path.
let url = Bundle.main.url(forResource: "test", withExtension: "json")
let lottie = try Lottie(path: url.path)If you only have the string data of the Lottie, you can use the alternate String initialiser.
let lottie = try Lottie(string: "...")Next, initialise a buffer for ThorVG to draw Lottie frame data into.
let size = CGSize(width: 1024, height: 1024)
let buffer = [UInt32](repeating: 0, count: Int(size.width * size.height))From here, initialise a LottieRenderer instance to handle the rendering of individual Lottie frames.
let renderer = LottieRenderer(
lottie,
size: size,
buffer: &buffer,
stride: Int(size.width),
pixelFormat: .argb
)Note
You can use different pixel formats including .argb, .rgba, etc. (see the complete list here).
By default, the LottieRenderer runs on the main thread. If needed, you can create a custom Engine with multiple threads.
let engine = Engine(numberOfThreads: 4)
let renderer = LottieRenderer(
lottie,
engine: engine,
size: size,
buffer: &buffer,
stride: Int(size.width),
pixelFormat: .argb
)Once your LottieRenderer is set up, you can start rendering Lottie frames using the render function.
The render function takes three parameters:
frameIndex: the index of the frame to rendercontentRect: the area of the Lottie content to renderrotation(optional): the rotation angle to apply to the renderered frame
let contentRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
try renderer.render(frameIndex: 0, contentRect: contentRect, rotation: 0.0)And voilà! Your buffer is now filled with the rendered Lottie frame data.
Tip
To render all of the frames in a Lottie animation, you can iterate through the numberOfFrames property of the Lottie class.
For most use cases, ThorVGSwift provides convenient view components that handle rendering, playback, and animation lifecycle automatically. All animation state is managed through the LottieViewModel, which you create externally and pass to the view.
import SwiftUI
import ThorVGSwift
struct ContentView: View {
@StateObject private var viewModel: LottieViewModel
init() {
let lottie = try! Lottie(path: "animation.json")
let config = LottieConfiguration(loopMode: .loop, speed: 1.0)
// Size is optional - defaults to animation's intrinsic size
_viewModel = StateObject(wrappedValue: LottieViewModel(
lottie: lottie,
configuration: config
))
}
var body: some View {
LottieView(viewModel: viewModel)
.onAppear { viewModel.play() }
.onChange(of: viewModel.error) { _, error in
if let error = error {
print("Animation error: \(error)")
}
}
}
}import UIKit
import ThorVGSwift
class ViewController: UIViewController {
private var viewModel: LottieViewModel!
private var lottieView: LottieUIKitView!
override func viewDidLoad() {
super.viewDidLoad()
let lottie = try! Lottie(path: "animation.json")
let config = LottieConfiguration(loopMode: .loop, speed: 1.0)
// Size is optional - defaults to animation's intrinsic size
viewModel = LottieViewModel(
lottie: lottie,
configuration: config
)
lottieView = LottieUIKitView(viewModel: viewModel)
// Observe animation errors
lottieView.onError = { error in
print("Animation error: \(error)")
}
view.addSubview(lottieView)
// Add constraints...
viewModel.play()
}
}The high-level Views API provides:
- ✅ ViewModel-Based State: All animation state managed through
LottieViewModel - ✅ Flexible Sizing: Optional
sizeparameter - defaults to animation's intrinsic dimensions - ✅ Playback Control: Loop modes (playOnce, loop, repeat, autoReverse) and speed adjustment
- ✅ Content Modes: Aspect fit and aspect fill scaling options
- ✅ Progress Tracking: Monitor playback progress and state via published properties
- ✅ Error Handling: Built-in error reporting through Combine publishers
- ✅ Manual Controls: Play, pause, stop, and seek to specific frames or progress
- ✅ Performance Optimized: Reusable CGContext and efficient buffer management
- ✅ Sample App: Interactive iOS app demonstrating all features
Note: Try the ThorVGSampleApp - a standalone iOS app with all examples! Just open
ThorVGSampleApp/ThorVGSampleApp.xcodeprojand run. Learn more →
📖 View Complete Views API Documentation →
The full documentation includes:
- Detailed API reference for
LottieView,LottieUIKitView, andLottieViewModel - Configuration options and best practices
- Complete usage examples and integration patterns
- Testing strategies and troubleshooting guides
Simply add the package dependency to your Package.swift - releases include pre-built XCFramework binaries and require no additional build steps.
dependencies: [
.package(url: "https://github.com/thorvg/thorvg.swift", from: "0.1.0")
]Contributors need to build the XCFramework locally, as it's not included in the repository (only in release tags).
- Xcode with command-line tools installed
- Meson and Ninja build tools:
brew install meson ninja
Before building the Swift package, generate the ThorVG XCFramework:
# Clone with submodules
git clone --recursive https://github.com/thorvg/thorvg.swift
cd thorvg.swift
# Build the XCFramework (required for local development)
./scripts/build_frameworks.shThe build script will:
- Automatically detect your Xcode installation and SDK paths
- Build ThorVG for macOS (arm64 + x86_64), iOS (arm64), and iOS Simulator (arm64)
- Create
ThorVG.xcframeworkcontaining all platform binaries - Generate a standalone macOS library in
lib/for local development
Build outputs:
ThorVG.xcframework/- Multi-platform framework (gitignored, only in releases)lib/libthorvg.a- Standalone macOS library (gitignored)
Once the XCFramework is built, you can build and test the Swift package:
swift build # Build the package
swift test # Run testsMaintainers can create releases with pre-built binaries:
# This builds the XCFramework and creates a release commit + tag
./scripts/release.sh 0.1.0See docs/CONTRIBUTING.md for complete release instructions and docs/RELEASE_POLICY.md for the full release policy.
Note
The build script uses ThorVG's native Meson build system instead of Swift Package Manager compiling C++ directly. This approach simplifies maintenance and ensures consistent builds across platforms.
Tip
If you're on an Intel Mac and want x86_64 simulator support, you can modify scripts/build_frameworks.sh to include both architectures for the simulator. By default, only arm64 is built for simulator (Intel Macs can use it via Rosetta 2).
Contributions are welcome! See docs/CONTRIBUTING.md for:
- Quick start guide
- How to build from source
- Making changes to Swift code
- Updating the XCFramework
- What to commit
- Build System - Comprehensive guide to how ThorVGSwift builds and packages ThorVG, including cross-compilation details, build options, and troubleshooting
- Release Policy - Versioning, release cadence, and procedures for maintainers
- Changelog - History of changes and releases
Feel free to open an issue or submit a pull request!
