Ir al contenido
charmotion

Animación de personajes en watchOS y visionOS

Por el equipo de Charmotion · Actualizado el

Ilustración de portada de la guía de iOS y Swift: animación de personajes en watchOS y visionOS, con personajes de demostración de Charmotion

Ni Rive ni Lottie son compatibles oficialmente con watchOS: rive-ios declara iOS, visionOS, tvOS, macOS y Mac Catalyst, y lottie-spm declara iOS, macOS, tvOS y visionOS. En el Apple Watch, anima con PhaseAnimator o KeyframeAnimator de SwiftUI (watchOS 10+) o reproduce fotogramas prerrenderizados. En visionOS, ambos funcionan en una ventana normal de SwiftUI.

Puntos clave

  • Package.swift de rive-ios: iOS 14, visionOS 1, tvOS 16, macOS 13.1, Mac Catalyst 14. Sin watchOS.
  • El Package.swift de lottie-spm incluye iOS, macOS, tvOS y visionOS. Sin watchOS.
  • En watchOS, usa los animadores de SwiftUI o una secuencia de fotogramas controlada por TimelineView.
  • En visionOS, una mascota 2D va en una ventana u ornament de SwiftUI; RealityKit es para modelos 3D.
  • Exporta los fotogramas desde el video con fondo transparente del mismo personaje para que Watch, teléfono y Vision Pro coincidan.

¿Rive es compatible con watchOS?

No oficialmente. Las plataformas del Package.swift de rive-ios son:

platforms: [.iOS("14.0"), .visionOS("1.0"), .tvOS("16.0"), .macOS("13.1"), .macCatalyst("14.0")]

Swift Package Manager no enlazará el paquete en un target de watchOS porque watchOS no está en esa lista. Algún resumen de la página de migración de Rive para Apple ha dado a entender en ocasiones que el nuevo runtime es compatible con watchOS, pero lo que Xcode aplica es el manifiesto publicado, así que planifica como si Rive no estuviera disponible en el Watch. Vuelve a revisar el manifiesto cuando actualices el paquete, ya que las listas de plataformas pueden cambiar entre versiones.

Lo mismo aplica al runtime heredado de Rive: ambos runtimes se distribuyen en un solo paquete con un único conjunto de plataformas. Si tu app de iPhone y tu app de Watch comparten un paquete Swift de componentes de interfaz, deja las vistas que usan Rive en un módulo del que solo dependan los targets de iOS (y visionOS); de lo contrario, la compilación del Watch no podrá resolver la dependencia.

¿Lottie es compatible con watchOS?

No. El manifiesto de lottie-spm, que Airbnb recomienda para Swift Package Manager, declara iOS, macOS, tvOS y visionOS. No hay ninguna entrada para watchOS.

OpcióniOSvisionOSwatchOS
RiveRuntime (rive-ios)14.0+1.0+No declarado
Lottie (lottie-spm)YesYesNo declarado
SwiftUI PhaseAnimator / KeyframeAnimator17.0+1.0+10.0+
Secuencia de fotogramas con TimelineView de SwiftUIYesYesYes
AVKit VideoPlayerYesYesYes

Para conocer las versiones mínimas exactas de Lottie, lee la línea platforms de la versión que fijes.

Existen forks antiguos y ports de la comunidad de Lottie para watchOS, pero no son el paquete de Airbnb y su mantenimiento es irregular. Para una app que piensas seguir actualizando, las opciones nativas de las filas inferiores son la elección de menor riesgo: vienen con el sistema, respetan los ajustes de accesibilidad y no requieren ninguna dependencia extra en el target del Watch.

¿Qué puedo usar en el Apple Watch en su lugar?

Tres opciones, de la más ligera a la más pesada:

  1. Animadores de SwiftUI sobre una imagen fija. phaseAnimator y keyframeAnimator están disponibles desde watchOS 10. Un rebote, una inclinación o un pulso sobre una sola pose no requieren más recursos que una imagen. Consulta PhaseAnimator vs KeyframeAnimator.
  2. Una secuencia de fotogramas. Exporta un loop corto como PNG numerados, añádelos al catálogo de recursos de la app del Watch y recórrelos con TimelineView. Así conservas el movimiento real del personaje (parpadeos, saludos) a costa del tamaño de la app.
  3. Video. El VideoPlayer de AVKit para SwiftUI está disponible en watchOS. Muestra los controles del reproductor y encaja mejor con un clip que el usuario elige ver que con una mascota ambiental.

Una vista con secuencia de fotogramas:

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)

Mantén los loops cortos y ligeros: la pantalla del Watch es diminuta y cada fotograma aumenta el tamaño de la app. Reproduce la secuencia en un momento concreto (un entrenamiento completado, un recordatorio) en lugar de dejarla en loop todo el día.

¿Cómo exporto fotogramas para watchOS desde mi set de animaciones?

Parte de una fuente con fondo transparente para que el personaje quede limpio sobre el fondo negro del Watch. Con ffmpeg y un WebM VP9 con canal alfa:

# 12 fps, 160 px wide, keep transparency
ffmpeg -c:v libvpx-vp9 -i wave.webm -vf "fps=12,scale=160:-1" wave_%02d.png

Luego arrastra los PNG al catálogo de recursos del target del Watch. Consejos:

  • Ajusta el tamaño a la pantalla. Exporta al tamaño en puntos más grande que muestres multiplicado por la escala de pantalla, no a la resolución de origen.
  • Recorta el loop. Un loop de dos segundos a 12 cuadros por segundo son 24 imágenes; suele bastar para un reposo (idle) o un saludo.
  • Elige una imagen fija para Reducir movimiento. El primer fotograma sirve también como pose estática.

Los sets de Charmotion en los planes de pago incluyen archivos WebM y MOV HEVC con alfa transparentes para cada animación, junto con el .riv que se usa en iPhone, así que los fotogramas del Watch salen exactamente del mismo movimiento que la app del teléfono.

¿Cómo comparto una misma vista de la mascota de marca entre iPhone, Watch y Vision Pro?

Oculta la diferencia entre plataformas detrás de una sola vista que reciba la misma entrada en todas partes, por ejemplo el número de mood. La rama de iOS y visionOS usa Rive; la de watchOS usa fotogramas:

import SwiftUI
#if !os(watchOS)
import RiveRuntime
#endif

struct Mascot: View {
    let mood: Int

    var body: some View {
        #if os(watchOS)
        FrameSequence(frames: Self.frames(for: mood))
        #else
        RiveMascot(mood: mood)       // wraps RiveUIViewRepresentable and setValue(of:to:)
        #endif
    }

    #if os(watchOS)
    static func frames(for mood: Int) -> [String] {
        (0..<24).map { String(format: "mood%d_%02d", mood, $0) }
    }
    #endif
}

Agrega el paquete rive-ios solo a los targets de iOS y visionOS, y las imágenes de los fotogramas solo al target del Watch, para que ninguna plataforma cargue con los recursos de la otra. El código compartido (tu modelo, el enum de mood) sigue siendo neutral respecto a la plataforma.

¿Rive funciona en visionOS?

Sí. visionOS 1.0 está en la lista de plataformas de rive-ios, y el manifiesto de Lottie también incluye visionOS. En Vision Pro, una app de SwiftUI muestra sus vistas en ventanas, así que el mismo código que usas en iPhone funciona:

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() }
    }
}

Aquí, CharacterModel es el controlador de Data Binding de Rive en SwiftUI: crea el Worker, el File, la instancia del view model y la máquina de estados vinculada. glassBackgroundEffect() es el material de vidrio de visionOS; omítelo en otras plataformas.

Prueba en el dispositivo además del simulador. El renderizado se basa en Metal en ambos runtimes, y el peso visual de un personaje plano flotando en una habitación es difícil de juzgar en la pantalla de una Mac.

En visionOS, ¿una mascota 2D debe ir en una ventana de SwiftUI o en RealityKit?

Mantén un personaje 2D en SwiftUI. RealityKit y Reality Composer Pro están hechos para contenido 3D: modelos, materiales y animación esquelética. Un personaje plano de Rive o Lottie colocado en RealityKit no gana nada y pierde la API sencilla basada en vistas.

UbicaciónÚsala para
Dentro de la ventana principalOnboarding, estados vacíos, avatar del asistente: igual que en iPhone
Ornament adjunto a una ventanaUn pequeño ayudante permanente junto a tu contenido
Ventana pequeña independienteUn acompañante que el usuario puede mover
Entidad de RealityKitSolo si el personaje es un modelo 3D real

Reducir movimiento importa más en un visor, donde el movimiento ocupa más campo de visión. Lee @Environment(\.accessibilityReduceMotion) (disponible en visionOS 1) y pausa la animación o cámbiala por una pose fija; consulta Reducir movimiento en SwiftUI y UIKit.

Agrega una animación de personaje a una app de Apple Watch

  1. Elige el método. Usa un animador de SwiftUI sobre una pose fija para movimientos simples, o una secuencia de fotogramas para un movimiento de personaje real.
  2. Exporta los fotogramas. Ejecuta ffmpeg -c:v libvpx-vp9 -i wave.webm -vf "fps=12,scale=160:-1" wave_%02d.png sobre un WebM con fondo transparente.
  3. Agrégalos al target del Watch. Arrastra los PNG al catálogo de recursos de la app del Watch.
  4. Reprodúcelos. Recorre las imágenes con TimelineView(.animation(minimumInterval:)) a la tasa de cuadros por segundo de la exportación.
  5. Gestiona Reducir movimiento (Reduce Motion). Muestra el primer fotograma como imagen fija cuando accessibilityReduceMotion sea verdadero.

Preguntas frecuentes

¿Puedo compartir el código de mi vista Rive de iOS con un target de watchOS?

No directamente, porque el paquete RiveRuntime no declara watchOS y no se enlaza en un target del Watch. Envuelve la mascota en tu propia vista con condicionales de plataforma: Rive en iOS y visionOS, una secuencia de fotogramas o un animador de SwiftUI en watchOS, todo alimentado por el mismo valor de mood.

¿Un GIF se reproduce en Apple Watch?

El Image de SwiftUI no anima GIF en ninguna plataforma de Apple. Decodifica los fotogramas del GIF en imágenes y recórrelas o, mejor aún, exporta fotogramas PNG desde una fuente con fondo transparente y reprodúcelos con TimelineView. Así controlas los cuadros por segundo, el tamaño y Reducir movimiento.

¿Lottie está disponible en visionOS?

Sí. El manifiesto de lottie-spm declara visionOS junto con iOS, macOS y tvOS, así que LottieView funciona en una ventana de SwiftUI en visionOS igual que en iPhone. El paquete de Rive también declara visionOS 1.0, de modo que ambos runtimes son opciones para un personaje 2D en una ventana u ornamento de visionOS.

Respuestas rápidas de esta guía

Fuentes

Guías relacionadas