Skip to content
Native Animation
Squircle Ring Steps animation preview

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

npx nativeanimation add squircle-ring-steps
Skia

Squircle Ring Steps

An activity dashboard with interactive concentric squircle rings, with configurable metrics, total, palette, 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 activity dashboard with interactive concentric squircle rings, with configurable metrics, total, palette, and fonts.

Why this one

The exponent-four superellipse follows the shape of a phone rather than repeating a circular activity chart. Each rounded endpoint lands with a small droplet and a blurred accent shadow. Selecting one ring thickens it while the others recede, making each metric readable on its own.

How it works

  1. onLayout measures the host. The chart is capped at 360 pt, and a scroll container keeps all controls reachable in small or landscape containers.
  2. The component samples each superellipse and resamples it by arc length. Skia draws one continuous fill path per ring, beginning at top center and moving clockwise. On web, local SVG images paint the exact track geometry underneath the transparent canvas immediately, independently of WebGL startup.
  3. One UI-thread clock drives all three fills and counters, with a 160 ms stagger and a 1,200 ms deceleration per ring.
  4. Fixed-width, tabular digit columns count in whole steps, snapping to exact line positions even during the fill. Each reel has an explicit ten-line height and a one-line clipping window. Punctuation has its own narrower width and hides with its preceding leading digit; the integer zero and fractional digits remain visible.
  5. Selection crossfades the summary, springs the stroke from 26 to 32 pt, and fades other rings to 35%. Tap the center or total to reset.
  6. A pan finds the closest arc-length sample and adjusts the selected goal. A small cap pulse marks each 10% boundary. Lower/Raise goal buttons and screen-reader actions provide alternatives to dragging.

Install

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

Copy this folder without demo/. Place the app under GestureHandlerRootView. Use the standard Skia web CanvasKit setup when targeting web. Fonts are supplied by the host; the component uses system fonts if omitted. No images, external requests, or additional font loading are required.

Usage

import SquircleRingSteps from './squircle-ring-steps';

<SquircleRingSteps
  total={2574}
  rings={[
    { label: 'Calories', value: 186, goal: 260, color: '#FF7A1A', icon: 'flame', unit: 'kcal' },
    { label: 'Distance', value: 1.2, goal: 2, color: '#3A3D44', icon: 'route', unit: 'mi', decimals: 1 },
    { label: 'Active', value: 32, goal: 45, color: '#2F6BFF', icon: 'timer', unit: 'min' },
  ]}
/>
const activity = useRef<SquircleRingStepsRef>(null);

<SquircleRingSteps
  ref={activity}
  total={dailySteps}
  rings={metrics}
  duration={1000}
  stagger={140}
  fontFamily="YourInterfaceFont"
  numberFontFamily="YourNumberFont"
  palette={{ background: '#101114', surface: '#1D1F24', ink: '#F7F7F5', muted: '#A5A7AE', track: '#303238', border: '#35373D' }}
  onSelect={index => saveSelection(index)}
  onGoalChange={(index, goal) => saveGoal(index, goal)}
/>

activity.current?.select(0);
activity.current?.select(-1);
activity.current?.replay();

Changing rings replays the fill and resets local goal adjustments. Keep the tuple identity stable between unrelated parent renders. Goal changes are local until the host commits them through its data. For readability, progress is limited to 1–97%; values should be finite and nonnegative, with goals greater than zero. Supply decimals from 0 to 2. The three ring widths are designed for three metrics.

Props

PropTypeDefaultPurpose
ringsreadonly three-item StepRing tuplerequiredLabel, value, goal, color, bundled icon, optional unit and decimal places.
totalnumberrequiredTotal steps.
title / totalLabelstringSteps taken / total stepsHeader and summary caption.
hintstringTap a ring to focus. Drag to set its goal.Visible guidance and chart accessibility label.
backLabel / settingsLabelstringBack / SettingsNavigation control labels.
selectionLabel / resetLabel / goalLabelstringSelect metric / Reset selection / goalAccessible selection, reset, and goal wording.
decreaseLabel / increaseLabelstringLower goal / Raise goalTouch alternatives to goal dragging.
brandReactNodenoneHost-provided brand tile and wordmark.
palettePartial of StepsPalettewarm light paletteBackground, surface, ink, muted, track, border, shadow. Supply the full palette for dark themes.
fontFamily / numberFontFamilystringsystemInterface and number typefaces.
duration / staggernumber1200 / 160Fill and cascade timings in milliseconds.
onSelect(index: number) => voidnoneSelection changes; -1 means total.
onGoalChange(index: number, goal: number) => voidnoneGoal update after dragging or a discrete adjustment.
onInteraction() => voidnoneHost can stop autoplay after a touch.
onBack / onSettings() => voidnoneOptional header controls; omitted controls are hidden.
style / testIDStyleProp / stringnone / squircle-ring-stepsRoot layout and stable control IDs.

Ref: replay() and select(index). Pass -1 to restore the total.

Compatibility

Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, Skia 2.14.0. Dependencies are available in Expo Go. iOS, Android, and web are intended targets. The component applies no safe-area insets: the host screen owns them. Content scrolls when the available height cannot fit the dashboard, including a 300×400 embedding.

Accessibility

Metric tiles and summary are labeled buttons. The chart supports adjustable actions and activation to cycle metrics. Goal buttons provide a touch alternative to the circular pan. Selection and committed goal changes are announced. Reduced motion replaces fill sweeps with a 200 ms fade, stops counting and cap pulses, and crossfades selection without vertical travel. Font scaling remains enabled.

Icons: Lucide (ISC). The demo uses Aurora from the internal brand kit and the host's loaded Geist and Geist Mono fonts; Geist 600 is not loaded by the current app. No third-party brand assets or reference text are included.

Implementation review

The summary uses 44 pt type with 1.2× line height; smaller labels stay in normal flow. The header reserves 96 pt at the upper right for the catalog close control. At 390×844 the chart is capped at 360 pt; at 320×694 it is 296 pt, with vertical scrolling if the remaining content does not fit. Small and landscape hosts scroll instead of overlapping controls. The fill finishes at 1,520 ms, with the first focused state at 1,900 ms in autoplay. Accent light uses a blurred copy of the actual path, never an opaque overlay block.