Character Animation on watchOS and visionOS
By the Charmotion team · Updated

Neither Rive nor Lottie officially supports watchOS: rive-ios declares iOS, visionOS, tvOS, macOS and Mac Catalyst, and lottie-spm declares iOS, macOS, tvOS and visionOS. On Apple Watch, animate with SwiftUI's PhaseAnimator or KeyframeAnimator (watchOS 10+) or play pre-rendered frames. On visionOS, both run in a regular SwiftUI window.
Key takeaways
- rive-ios Package.swift: iOS 14, visionOS 1, tvOS 16, macOS 13.1, Mac Catalyst 14. No watchOS.
- lottie-spm Package.swift lists iOS, macOS, tvOS and visionOS. No watchOS.
- On watchOS, use SwiftUI animators or a frame sequence driven by
TimelineView. - On visionOS, a 2D mascot belongs in a SwiftUI window or ornament; RealityKit is for 3D models.
- Export frames from the same character's transparent video so Watch, phone and Vision Pro match.
Does Rive support watchOS?
Not officially. The platforms in the rive-ios Package.swift are:
platforms: [.iOS("14.0"), .visionOS("1.0"), .tvOS("16.0"), .macOS("13.1"), .macCatalyst("14.0")]
Swift Package Manager will not link the package into a watchOS target because watchOS is not in that list. A summary of Rive's Apple migration page has at times implied watchOS support for the new runtime, but the shipped manifest is what Xcode enforces, so plan as if Rive is unavailable on the Watch. Check the manifest again when you update the package, since platform lists can change between releases.
The same applies to Rive's legacy runtime: both runtimes ship in one package with one set of platforms. If your iPhone app and Watch app share a Swift package of UI components, keep the Rive-backed views in a module that only the iOS (and visionOS) targets depend on, or the Watch build will fail to resolve the dependency.
Does Lottie support watchOS?
No. The lottie-spm manifest, which Airbnb recommends for Swift Package Manager, declares iOS, macOS, tvOS and visionOS. There is no watchOS entry.
| Option | iOS | visionOS | watchOS |
|---|---|---|---|
| RiveRuntime (rive-ios) | 14.0+ | 1.0+ | Not declared |
| Lottie (lottie-spm) | Yes | Yes | Not declared |
| SwiftUI PhaseAnimator / KeyframeAnimator | 17.0+ | 1.0+ | 10.0+ |
| SwiftUI TimelineView frame sequence | Yes | Yes | Yes |
| AVKit VideoPlayer | Yes | Yes | Yes |
For exact Lottie minimum versions, read the platforms line of the release you pin.
Older forks and community ports of Lottie for watchOS exist, but they are not the Airbnb package and their maintenance varies. For an app you plan to keep updating, the native options in the lower rows are the lower-risk choice: they ship with the OS, follow the system's accessibility settings, and need no extra dependency in the Watch target.
What can I use on Apple Watch instead?
Three options, from lightest to heaviest:
- SwiftUI animators on a still image.
phaseAnimatorandkeyframeAnimatorare available from watchOS 10. A bounce, tilt or pulse on a single pose costs no assets beyond one image. See PhaseAnimator vs KeyframeAnimator. - A frame sequence. Export a short loop as numbered PNGs, add them to the Watch app's asset catalog, and cycle through them with
TimelineView. This keeps the real character motion (blinks, waves) at the cost of app size. - Video. AVKit's SwiftUI
VideoPlayeris available on watchOS. It shows player chrome and suits a clip the user chooses to watch more than an ambient mascot.
A frame-sequence view:
import SwiftUI
struct FrameSequence: View {
let frames: [String] // ["wave_00", "wave_01", ...] in the asset catalog
var fps: Double = 12
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
if reduceMotion || frames.count < 2 {
Image(frames.first ?? "")
.resizable()
.scaledToFit()
} else {
TimelineView(.animation(minimumInterval: 1 / fps)) { context in
let tick = Int(context.date.timeIntervalSinceReferenceDate * fps)
Image(frames[tick % frames.count])
.resizable()
.scaledToFit()
}
}
}
}
// Usage
FrameSequence(frames: (0..<24).map { String(format: "wave_%02d", $0) })
.frame(width: 80, height: 80)
Keep loops short and small: the Watch screen is tiny, and every frame adds to the app. Play the sequence on a specific moment (a completed workout, a reminder) rather than looping all day.
How do I export frames for watchOS from my animation set?
Start from a transparent source so the character sits on the Watch's black background cleanly. With ffmpeg and a VP9 WebM with alpha:
# 12 fps, 160 px wide, keep transparency
ffmpeg -c:v libvpx-vp9 -i wave.webm -vf "fps=12,scale=160:-1" wave_%02d.png
Then drag the PNGs into the Watch target's asset catalog. Tips:
- Size for the display. Export at the largest point size you show times the screen scale, not at the source resolution.
- Trim the loop. A two-second loop at 12 fps is 24 images; that is often enough for an idle or a wave.
- Pick a still for Reduce Motion. The first frame doubles as the static pose.
Charmotion sets include transparent WebM and HEVC-alpha MOV files for every animation, alongside the .riv used on iPhone, so the Watch frames come from exactly the same motion as the phone app.
Does Rive run on visionOS?
Yes. visionOS 1.0 is in the rive-ios platform list, and Lottie's manifest includes visionOS too. On Vision Pro, a SwiftUI app shows its views in windows, so the same code you use on iPhone works:
import SwiftUI
import RiveRuntime
struct MascotWindow: View {
@StateObject private var model = CharacterModel() // loads the .riv and keeps the view model instance
var body: some View {
RiveUIViewRepresentable(rive: model.rive)
.frame(width: 320, height: 320)
.padding(32)
.glassBackgroundEffect()
.task { await model.load() }
}
}
CharacterModel here is the controller from Rive data binding in SwiftUI: it creates the Worker, File, view model instance and bound state machine. glassBackgroundEffect() is the visionOS glass material; leave it out on other platforms.
Test on device as well as the simulator. Rendering is Metal-based in both runtimes, and the visual weight of a flat character floating in a room is hard to judge on a Mac screen.
Should a 2D mascot live in a SwiftUI window or RealityKit on visionOS?
Keep a 2D character in SwiftUI. RealityKit and Reality Composer Pro are built for 3D content: models, materials and skeletal animation. A flat Rive or Lottie character placed in RealityKit gains nothing and loses the simple view-based API.
| Placement | Use for |
|---|---|
| Inside the main window | Onboarding, empty states, assistant avatar: same as iPhone |
| Ornament attached to a window | A small persistent helper next to your content |
| Separate small window | A companion the user can move around |
| RealityKit entity | Only if the character is a real 3D model |
Reduce Motion matters more in a headset, where motion fills more of the field of view. Read @Environment(\.accessibilityReduceMotion) (available on visionOS 1) and pause or swap to a still pose; see Reduce Motion in SwiftUI and UIKit.
Add a character animation to an Apple Watch app
- Pick the method. Use a SwiftUI animator on a still pose for simple motion, or a frame sequence for real character motion.
- Export frames. Run
ffmpeg -c:v libvpx-vp9 -i wave.webm -vf "fps=12,scale=160:-1" wave_%02d.pngon a transparent WebM. - Add to the Watch target. Drag the PNGs into the Watch app's asset catalog.
- Play them. Cycle the images with
TimelineView(.animation(minimumInterval:))at the export frame rate. - Handle Reduce Motion. Show the first frame as a still when
accessibilityReduceMotionis true.
Frequently asked questions
Can I share my iOS Rive view code with a watchOS target?
Not directly, because the RiveRuntime package does not declare watchOS and will not link into a Watch target. Wrap the mascot in your own view with platform conditionals: Rive on iOS and visionOS, a frame sequence or SwiftUI animator on watchOS, all fed by the same mood value.
Does a GIF play on Apple Watch?
SwiftUI's Image does not animate GIFs on any Apple platform. Decode the GIF's frames into images and cycle them, or better, export PNG frames from a transparent source and play them with TimelineView. That gives you control over frame rate, size and Reduce Motion.
Is Lottie available on visionOS?
Yes. The lottie-spm manifest declares visionOS alongside iOS, macOS and tvOS, so LottieView works in a visionOS SwiftUI window the same way it does on iPhone. Rive's package also declares visionOS 1.0, so both runtimes are options for a 2D character in a visionOS window or ornament.
Quick answers from this guide
Sources
- rive-ios Package.swift — Rive (GitHub)
- lottie-spm Package.swift — Airbnb (GitHub)
- PhaseAnimator — Apple
- TimelineView — Apple
- VideoPlayer (AVKit for SwiftUI) — Apple
- accessibilityReduceMotion — Apple
- Apple runtime (new and legacy) — Rive