Skip to content
Native Animation
Sleep stages chart animation preview

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

npx nativeanimation add sleep-stages-chart
ChartSkiaGlass

Sleep stages chart

A sleep-stage chart with rolling totals and a linked inspection cursor, with configurable segments, start time, stage 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

A sleep-stage chart with rolling totals and a linked inspection cursor, with configurable segments, start time, stage colors, and fonts.

Why this one

Each block grows from its own left edge in chronological order. Rounded, continuous connectors describe the transitions between stages. Inspecting a time illuminates its stage, dims the others to 35%, and highlights the matching summary row. The result makes a night's structure easier to explore than flat bars with square corners.

How it works

  1. Filter invalid segments and normalize their durations into one time axis. The example covers 462 minutes, including two brief awakenings and 96 minutes of deep sleep.
  2. Animate reveal from 0 to 1 over 1,400 ms with the curve (0.23, 1, 0.32, 1). Every Skia block derives its width from that time; connectors draw as the reveal reaches them.
  3. Derive the rolling hours and minutes and the summary bars from the same reveal. Digits rest on whole numbers and move only near their carry.
  4. Compose a horizontal pan and a tap with Gesture Handler. cursorX controls normalized time; active controls the cursor's spring fade. A tap holds the cursor for one second.
  5. Derive the active stage, point, floating time label, and summary highlight on the UI thread. Summary buttons toggle a persistent stage selection.
  6. Measure the component with onLayout. The demo uses a continuous Skia score ring, the Aurora kit glyph, a nocturnal gradient, and 30 stationary stars. Autoplay reveals the night, sweeps the cursor from 1.5 to 2.8 seconds, and repeats every 4.8 seconds.

Install

Copy this folder into your project. The reusable component needs no catalog code, theme imports, or demo assets.

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

Versions used: Skia 2.14.0, expo-blur ~58.0.5, Gesture Handler ~3.3.0, Reanimated 4.7.1, and worklets 0.13.0. Wrap the app in GestureHandlerRootView. The demo additionally uses expo-linear-gradient and the host's loaded Geist, Geist Mono, and Instrument Serif fonts.

For web, load CanvasKit before importing this component through Skia's WithSkiaWeb or the host's equivalent lazy loader. Do not statically import a Skia screen into an application before CanvasKit is ready.

Usage

import { View } from 'react-native';
import { SleepStagesChart } from './sleep-stages-chart';

export function Night() {
  return (
    <View style={{ flex: 1, backgroundColor: '#0A0816', padding: 22 }}>
      <SleepStagesChart />
    </View>
  );
}
import { useRef } from 'react';
import { SleepStagesChart, type SleepStagesChartRef } from './sleep-stages-chart';

export function CustomNight() {
  const chart = useRef<SleepStagesChartRef>(null);
  return (
    <SleepStagesChart
      ref={chart}
      startMinute={1388}
      revealDuration={1400}
      stageColors={['#FDBA74', '#F472B6', '#A78BFA', '#6366F1']}
      segments={[
        { stage: 'Light', minutes: 25 },
        { stage: 'Deep', minutes: 40 },
        { stage: 'Light', minutes: 20 },
        { stage: 'REM', minutes: 15 },
      ]}
      onStageChange={(stage) => saveSelectedStage(stage)}
    />
  );
}

saveSelectedStage represents your own application callback. Supply font props after loading your preferred typefaces.

Props

PropTypeDefaultDescription
segmentsreadonly SleepSegment[]DEFAULT_SLEEP_SEGMENTSPositive, chronological durations in minutes; invalid entries are ignored.
startMinutenumber1388Minutes after midnight; displayed as U.S. 12-hour time.
stageColorsreadonly [string, string, string, string]Peach, pink, lavender, indigoColors for Awake, REM, Light, Deep.
revealDurationnumber1400Chronological entrance duration in milliseconds.
fontFamilystringSystemLabels and interface text.
monoFontFamilystringSystemRolling digits and time labels.
onStageChange(stage: SleepStage) => void—Runs on the JS thread after a chart gesture or summary selection.
accessibilityLabelstringExploration instructionsAccessible chart description.
styleStyleProp<ViewStyle>—Outer container overrides; the root defaults to flex: 1.
testIDstring—Automation identifier.

SleepStage is 'Awake' | 'REM' | 'Light' | 'Deep'. A SleepSegment contains stage and minutes.

Ref methods: replay(), inspect(position, duration?) (position 0–1, duration in milliseconds), and dismiss(). Reveal timing is independent of direct cursor manipulation, so interaction remains available during the entrance.

Compatibility

Designed for Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, and Skia 2.14.0. The stack is included in the project's Expo Go environment. Android blur uses BlurTargetView and dimezisBlurViewSdk31Plus; older Android versions retain a translucent fallback. The default surface is dark.

Supports iOS, Android, and web. Allow at least 392 pt of height for the default chart and summary; the demo adapts its layout to 320×694 and 390×844.

Accessibility

The chart has an adjustable role, a textual summary of all four stages, and increment/decrement actions to explore time. Every summary button has a descriptive label including duration and percentage and a 44 pt hit area. Tap inspection is an alternative to dragging. Decorative canvases and rolling digits do not replace the textual summary.

With reduced motion, the full chart and final totals appear immediately, the cursor has no spring or animated travel, and autoplay does not sweep or replay the entrance.

Icons: Lucide (ISC), copied from the project kit. Aurora is a demo identity from the project kit; it is not part of the reusable component.