ValueAnimator effects, per-frame procedural animation using custom ECS systems, and experimental panel shape morphing. An interactive drone sequence combines these techniques with hover effects, spatial audio synchronization, smooth target following, and grabbable object tracking.PanelAnimationFeature, which is experimental and requires @OptIn(SpatialSDKExperimentalAPI::class). This API may change in future SDK releases.Animated componentValueAnimator to 3D objects for hover, click, and continuous pulse effectsPanelAnimationFeatureAnimationsSample project in Android Studio, connect your Meta Quest device, and run the app. The sample loads a scene with a 3D button, drone model, target sphere, and UI panels.| File / Scene | What it demonstrates | Key concepts |
|---|---|---|
Main activity entry point, feature/component/system registration, GLXF scene loading | Panel shape animation via PanelAnimationFeature, ECS registration patterns | |
3D button hover and click visual feedback | ValueAnimator with color interpolation and overshoot effects | |
Drone animation sequence orchestration, target setup, follow mode toggle | glTF clip sequencing via Animated component, ValueAnimator scale effects, spatial audio sync | |
Per-frame drone rotation and tilt toward target | Custom SystemBase implementation, quaternion rotation, velocity-based tilt | |
Per-frame smooth position following via exponential decay | Frame-based procedural animation, Freya Holmer smoothing technique | |
GLXF scene object discovery and initialization | Reactive system that waits for named entities to load | |
panel/PanelAnimationPanel.kt | UI toggle for experimental panel shape animation | Jetpack Compose integration in panels |
droneScene.glxf | Scene with drone model containing four animation tracks, environment, buttons, panels | glTF animation track discovery, named entity references |
Followable component and changes the sphere to orange. Separately, the panel animation toggle morphs a panel between flat quad and curved cylinder shapes.SceneObject.mesh.getAnimationTracks() and builds a name-to-index map. DroneSceneController.kt plays clips in sequence by setting the Animated component with the track index:droneEnt.setComponent(Animated(
System.currentTimeMillis(),
playbackState = PlaybackState.PLAYING,
playbackType = PlaybackType.CLAMP, track = track))
Timer().schedule() with hardcoded durations. For looping animations like idle hover, the sample uses PlaybackType.LOOP. For more on glTF animation integration, see Animations and glTFs.ValueAnimator to 3D objects for smooth interpolation effects. In ButtonController.kt, the button uses ArgbEvaluator for color transitions and OvershootInterpolator for click depression. The drone target in DroneSceneController.kt applies overshoot for scale-up, then runs an infinite pulse animator. All animators call activity.runOnUiThread() to ensure execution on a Looper thread.DroneSystem.kt calculates rotation toward the target using Quaternion.lookRotationAroundY(), applies velocity-based tilt, and smooths rotation via Quaternion.slerp(). FollowerSystem.kt implements exponential decay position smoothing using Freya Holmer’s technique. Both extend SystemBase and override execute() to run each frame. For system architecture, see Entity Component System.PanelAnimationFeature:entity.setComponent(PanelQuadCylinderAnimation(
startTime = DataModel.getLocalDataModelTime(),
animationType = PanelQuadCylinderAnimationType.QUAD_TO_CYLINDER,
durationInMs = 500L,
targetRadius = Random.nextFloat() * 2f + 0.67f))
FollowerSystem with spring physics or add acceleration curves for different motion characteristics.DroneSceneController.PanelQuadCylinderAnimation parameters to experiment with different radii, durations, or create a cycling animation between multiple shapes.