Skip to content
Native Animation
Arc scrub player animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add arc-scrub-player
Skia

Arc scrub player

An arc scrubber with a responsive audio aura and configurable track copy, labels, colors, and fonts.

$9 for this animation

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

About this animation

An arc scrubber with a responsive audio aura and configurable track copy, labels, colors, and fonts.

Why this one

The progress arc embraces the artwork instead of separating it into a linear bar. Scrubbing pulls the aura toward the handle; playback breathes and pausing freezes the breath at 55% colored light. No people, downloaded artwork, or overlay blocks are needed.

How it works

  1. One shared seconds value drives the continuous semicircle, handle, clock, and pull direction.
  2. A pan projects the finger onto the lower semicircle. A tap seeks to the same projected angle.
  3. A spherical Skia shader combines a luminous core, counter-rotating aurora ribbons, and an outer halo. A full breath takes 8 seconds (4 in, 4 out), scaling from 0.96 to 1.04. Dragging accelerates the aurora. Pausing freezes breathing and preserves the palette at 55% brightness.
  4. Seek springs are interruptible and use explicit mass with near-critical damping. Separate shared values handle button pressure.
  5. React receives only changed integer seconds and playback state; digit columns settle on exact digits with independently sized separators.
  6. The demo starts playing, scrubs to the 60% chapter at 2 seconds, pauses at 3.5 seconds for 1.5 seconds, resumes at 5 seconds, and skips forward at 6.2 seconds. Any touch stops the 10-second loop.

Install

npx expo install @shopify/react-native-skia expo-blur react-native-gesture-handler react-native-reanimated react-native-worklets

Wrap your application in GestureHandlerRootView. Configure Reanimated/worklets for your SDK. For web, initialize CanvasKit before importing this component (Expo's Skia web setup / WithSkiaWeb). Icons: Lucide (ISC); copied paths are included in icons.ts.

Usage

import { ArcScrubPlayer } from './arc-scrub-player';

<ArcScrubPlayer duration={638} title="Guided session" />;
const player = useRef<ArcScrubPlayerRef>(null);

<ArcScrubPlayer
  ref={player}
  duration={638}
  title="Find your quiet center"
  subtitle="A guided pause for a softer day."
  fontFamily="Geist_500Medium"
  monoFontFamily="GeistMono_400Regular"
  onSeek={seconds => audioEngine.seek(seconds)}
  onPlayPause={playing => audioEngine.setPlaying(playing)}
  theme={{ amber: '#FFD092', coral: '#E49B86', lilac: '#B6A4DA' }}
/>;
// Imperative controls: player.current?.seek(180), .play(), .pause().

This component simulates time and voice energy; it does not play or analyze audio. Supply position and playing from your audio engine to synchronize external changes. Callbacks report user and imperative requests, not clock ticks. Seeking does not force paused playback to resume.

Props

PropTypeDefaultPurpose
durationnumber638Total seconds; minimum 1
positionnumber173 internallyExternal time updates, clamped
onSeek(seconds: number) => void—Seek request, once per completed gesture/action
playingbooleantrue internallyExternal play/pause updates
onPlayPause(playing: boolean) => void—Playback request
titlestringGuided sessionHeadline
subtitlestringA little room to breathe.Supporting copy
themePartial<ArcScrubPlayerTheme>warm paletteBackground, glow, text, muted, track, progress, control, controlInk, glass, border, amber, coral, lilac, shadow, shadowFade, controlShadow
fontFamilystringsystemInterface font
monoFontFamilystringsystemClock font
labelsPartial label mapEnglish labelsplay, pause, backward, forward, seek, skip, breatheIn, breatheOut, paused, remaining
formatTime(seconds: number) => stringMM:SSClock and announcement formatting
onInteraction() => void—Finger interaction notification
styleStyleProp<ViewStyle>—Root style override
testIDstringarc-scrub-playerStable control prefix

Ref: seek(seconds), play(), pause(), and scrubTo(seconds) (demonstrates the gesture pull).

Compatibility

Targets Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, worklets 0.13.0, and Skia 2.14.0. Uses SDK-compatible installed packages; no additional dependency installation was performed. Expo Go supports this stack. Supports iOS, Android, and web.

The root fills its host and measures it with onLayout. Artwork is constrained by both width and height, with a 440 pt width cap. Small hosts and large text can scroll. The embedding screen owns safe-area insets. The demo reserves the upper right for the catalog close button. Artwork is procedural, so there is no bitmap density constraint.

Accessibility

The arc is adjustable with increment/decrement actions, a current-time value, and a tap alternative to dragging. Buttons expose localized roles and labels; seek/play/pause changes are announced. Controls measure 52 or 64 pt. Reduced motion freezes grain and breathing, disables pull and rolling motion, and dims/restores colored light with a 200 ms fade.

Visual design

The edge-to-edge warm night field breathes with the session. The demo header and footer float over it. A 6 pt gradient arc uses an 18% track, four chapter dots, and a glowing handle that expands while dragging. A time tooltip follows the handle; the main elapsed clock uses large rolling tabular digits with a smaller remaining-time label. Glass skip controls contain centered numerals. The central play/pause symbol interpolates matching contours resampled from the original Lucide shapes.

No audio asset is included: connect the existing callbacks to an audio engine for sound. No generated artwork is required.