Skip to content
Native Animation
Streak Flame Counter animation preview

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

npx nativeanimation add streak-flame-counter
Skia

Streak Flame Counter

A streak counter with an animated flame and weekly habit strip, with configurable streak, day labels, accent color, 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 streak counter with an animated flame and weekly habit strip, with configurable streak, day labels, accent color, and fonts.

How it works

  1. Skia draws a continuously deforming flame silhouette. A procedural shader combines two scales of moving noise with ribbons of heat inside the silhouette. Blurred paths and a radial halo add depth without rectangular glow overlays.
  2. One completion progress drives a small anticipation, a restrained flare, rising embers, the digit roll, and today's illuminated check. The interruptible completion spring uses explicit mass and near-critical damping.
  3. Each digit has its own measured window. Unchanged columns stay still; changed digits fade as they roll, including carries such as 19 → 20. React does not update per frame.
  4. The week shows completed days, today's outlined indicator, and future days. Today fills as the flame flares; the action crossfades to its completed label.
  5. onLayout selects a stacked or compact horizontal composition. Content can scroll at large accessibility text sizes. The host owns safe-area insets.

The demo waits for its first nonzero layout, holds the starting count for 1.2 seconds, then celebrates the change from 12 to 13 within the first 3 seconds. It repeats every 4.3 seconds with the same pause after reset. All seven weekday labels remain visible, including today's label. Tap its brand header to switch between dark and light treatments.

Install

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

On web, initialize CanvasKit before loading this component. No external images are required.

Usage

import StreakFlameCounter from './streak-flame-counter';

export function HabitScreen() {
  return <StreakFlameCounter streak={19} goalLabel="Practice for 15 minutes" />;
}
import { useRef } from 'react';
import StreakFlameCounter, { type StreakFlameCounterRef } from './streak-flame-counter';

export function DailyGoal() {
  const streakRef = useRef<StreakFlameCounterRef>(null);
  return (
    <StreakFlameCounter
      ref={streakRef}
      streak={28}
      colorScheme="light"
      accentColor="#E9813D"
      fontFamily="YourSansFont"
      mediumFontFamily="YourMediumFont"
      numberFontFamily="YourMonoFont"
      onComplete={() => saveDailyProgress()}
    />
  );
}

complete() adds one day and calls onComplete once after settling. Repeated calls are ignored until reset(). Reset interrupts the spring, cancels a pending completion callback, and restores the starting value. The host persists its actual streak separately.

Props

PropTypeDefaultPurpose
streaknumber12Starting whole-day count; clamped to 0–999999.
streakLabelstringday streakCounter unit.
goalLabelstringMake time for your daily goalSupporting habit description.
actionLabelstringComplete todayPrimary action.
completedLabelstringDone for todayCompleted action.
replayLabelstringReplayReset action and accessible label.
weekLabelstringTHIS WEEKWeekly section heading.
dayLabelsreadonly string[]Sun through SatUp to seven weekday labels in display order.
todayIndexnumber4Current day in that order.
colorSchemelight | dark | autodarkComplete theme, including text, surfaces, and borders.
backgroundColorstringTheme-derivedBackground override; use transparent to embed.
accentColorstring#FF8A42Flame, day fill, and action accent.
flameHighlightColorstring#FFF0BDHottest flame material.
textColor, mutedColorstringTheme-derivedMain and supporting text.
surfaceColor, borderColorstringTheme-derivedWeekly surface and border.
actionTextColorstring#211109Action text contrast.
fontFamily, mediumFontFamilystringSystem fontInterface font families.
numberFontFamilystringMedium/system fontTabular digit font; demo uses Geist Mono.
onComplete() => void—Called when completion settles.
accessibilityLabelstringAction labelPrimary accessible action label.
styleStyleProp<ViewStyle>—Root container styling.
testIDstring—Root ID; actions append -complete and -reset.

Compatibility

Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, and Skia 2.14.0. Uses the installed Expo Go modules. iOS, Android, and web are supported. The shader has a gradient fallback if compilation is unavailable.

Accessibility

Actions have button roles, accessible labels, and at least 48-point touch areas. A single accessible counter announces the completed count; decorative digit copies and flame are hidden. Reduced Motion freezes the flame, removes embers and spatial effects, and fades the count and weekday state over 180 ms. Text scaling remains enabled, with a scroll fallback for larger content.