Skip to content
Native Animation
Ring Check-in Stats animation preview

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

npx nativeanimation add ring-checkin-stats

Ring Check-in Stats

A mood arc that becomes an activity dashboard with rising pixel columns, with configurable mood labels, step data, 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

A mood arc that becomes an activity dashboard with rising pixel columns, with configurable mood labels, step data, palette, and fonts.

Why this one

An arc gives the thumb precise, one-point control instead of a row of faces or a straight slider. A translucent temperature tint makes the photograph respond to mood. Confirmation keeps the same number on screen as it flies into a saved check-in chip, connecting reflection with activity instead of cutting between screens. Pixel columns build from the ground up and regroup when the period changes.

How it works

  1. onLayout measures the host container. The dial uses the smaller of the available width and height; dashboard content scrolls in short containers.
  2. An exclusive Gesture Handler pan/tap controls one continuous mood shared value. Release projects velocity into an integer spring target. Text rollers, the arc marker, temperature, and fading mood labels derive from that value.
  3. Each numeric column rolls only at its carry. Leading positions collapse, and commas have their own width and baseline. No React state updates run per frame.
  4. Confirmation animates a shared transition over 560 ms. The photograph moves upward while the same mood number shrinks into a coral chip. The dashboard fades and rises behind it.
  5. Pixels reveal bottom to top, one column at a time, with a 25 ms cadence. The activity total counts over 1.4 seconds. A second shared value rearranges persistent pixels for Week/Month.
  6. The demo starts at 52, moves to 64, confirms at 1.55 seconds, selects Month at 5.25 seconds and Week at 7.35 seconds, then resets at 10 seconds. Any touch stops its loop.

Install

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

Use a GestureHandlerRootView above this component and configure Reanimated/worklets for your Expo project. Web requires Skia's CanvasKit setup and a lazy Skia-aware host; load CanvasKit before evaluating this module. This folder imports no catalog or theme code. Icons: Lucide (ISC); glyph paths are bundled in icons.ts.

Usage

import { RingCheckinStats } from './ring-checkin-stats';

const steps = {
  week: {
    total: 11374,
    days: [{ label: 'Mon', value: 11230 }, { label: 'Tue', value: 10240 }],
  },
  month: {
    total: 48216,
    days: [{ label: 'Week 1', value: 41230 }, { label: 'Week 2', value: 48216 }],
  },
};

<RingCheckinStats
  image={require('./ring.jpg')}
  steps={steps}
  onConfirm={saveMood}
/>
const checkin = useRef<RingCheckinStatsRef>(null);

<RingCheckinStats
  ref={checkin}
  image={require('./ring.jpg')}
  steps={steps}
  question={['How does today feel?', 'Take a moment.']}
  labels={{ detail: 'My ring', saved: 'Today’s check-in' }}
  palette={{ background: '#201B19', surface: '#302825', ink: '#FFF5EF', muted: '#C8B8AF', border: '#493A33', pale: '#6D3F30' }}
  pixelDelay={20}
  transitionDuration={500}
  testID="daily-mood"
/>

// Call from an event handler or effect.
checkin.current?.setValue(64);
checkin.current?.confirm();

Props

PropTypeDefaultPurpose
imageImageSourcePropTypeRequiredPortrait photo, preferably local.
steps{ week: StepPeriod; month: StepPeriod }RequiredIndependent totals and labeled column values; first 31 columns shown. Month may use weekly groups.
question[string, string]Morning questionTwo question lines.
moodLabels{ max: number; label: string }[]30 Tense / 50 Okay / 70 Relaxed / 100 EnergizedAscending inclusive mood ranges.
valuenumber52External mood changes; bounded to 0–100. Omit for internal control.
onChange(n: number) => void—Rounded mood updates on the JS thread.
onConfirm(n: number) => void—Confirmed mood. Skip also confirms the current mood.
labelsPartial label objectNeutral English labelsskip, detail, stats, week, month, steps, saved, back, confirm, dial, decrease, increase, again.
brandReactNode—Optional top-left identity. Aurora belongs to the demo only.
palettePartial<RingCheckinPalette>Coral/lightbackground, surface, ink, muted, accent, pale, photoInk, cool, warm, shade, border. Override together for dark themes.
fontFamilystringSystemBody and controls.
lightFontFamilystringSystemQuestion and mood number.
strongFontFamilystringSystemSecond question line and steps.
formatNumber(n: number) => stringUS localeChart annotations and announcements. Animated totals use US grouping.
pixelDelaynumber25Reveal cadence, milliseconds per square.
transitionDurationnumber560Confirmation motion duration in milliseconds.
onInteraction() => void—Stops host automation after touch.
styleStyleProp<ViewStyle>—Host container styling.
testIDstringring-checkin-statsStable root and control suffixes.

Ref: setValue(n), confirm(), setPeriod('week' | 'month'), reset().

Compatibility

Built against Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, worklets 0.13.0 and Skia 2.14.0. These native modules are included in the matching Expo Go runtime. Supports iOS, Android, and web.

The root fills its parent. Intended for a full-screen check-in or an embedded container, including 300×400; the host owns safe-area insets. The dashboard scrolls on short screens. The top-right 56 pt remains free of controls. The supplied 768×1344 artwork is demo-only and is below full-screen @3x density; supply a larger original for production. The demo uses the available loaded Geist Medium face for its strong type.

Accessibility

The dial is adjustable with increment/decrement actions and named tap/pan alternatives. Tapping the arc selects a point; the back button reduces the value by one. Buttons have at least 48×48 hit areas and stable test IDs. Confirmation and period selection announce their results. The chart exposes its data as readable labels; off-screen panels are hidden from accessibility.

Reduced motion removes the photo flight, number flight, pixel lift and regrouping arcs. Panels and labels fade over 200 ms, pixels fade together, and period layouts switch during a crossfade. Font scaling remains enabled.