Skip to content
Native Animation
Snow Settle Overlay animation preview

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

npx nativeanimation add snow-settle-overlay
HolidaySkia

Snow Settle Overlay

A snowfall overlay that settles on rounded surfaces and scatters on fast scroll, with configurable content, colors, density, and wind.

$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 snowfall overlay that settles on rounded surfaces and scatters on fast scroll, with configurable content, colors, density, and wind.

Why this one

Falling snow becomes part of the interface: measured card edges catch flakes, a sculpted snowcap grows from each collision, and scroll momentum breaks it into powder. Slow scrolling carries the snow along with the card.

How it works

  1. Wrap the screen with SnowSettleOverlay and each card with SnowSurface. Layout and scroll events trigger UI-thread measurements relative to the overlay.
  2. One fixed particle pool drives parallax snowfall, lateral drift, and an eight-second wind cycle. Arrays and particle records are reused.
  3. Each rounded edge owns a profile sampled every four points. Collisions add a smooth mound to neighboring columns, capped by maxPileHeight.
  4. Skia draws the cool undershadow, irregular cream snowcap, corner overhang, and fine upper highlight in one transparent, touch-through Canvas.
  5. useSnowScroll() measures scroll velocity. Above the threshold, snow releases into gravity-driven particles and its remaining profile clears in 300 ms. The shared budget limits emitted powder; a full pool skips additional emissions.
  6. Physics and drawing run in worklets, without React updates per frame. Registration also stays on the UI thread. The demo shares the same Canvas for all eight recipe illustrations.

Install

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

Use Expo SDK 58 and its compatible package versions. Reanimated needs the worklets Babel transform (configured by babel-preset-expo). Skia web needs CanvasKit loaded before rendering the component; see the Skia web setup.

Usage

The hook must run in a child of the overlay. Use Animated.ScrollView, not the React Native ScrollView, and leave removeClippedSubviews disabled so mounted surface measurements remain available.

import { View, Text } from 'react-native';
import Animated from 'react-native-reanimated';
import { SnowSettleOverlay, SnowSurface, useSnowScroll } from './snow-settle-overlay';

function Cards() {
  const onScroll = useSnowScroll();
  return (
    <Animated.ScrollView onScroll={onScroll} scrollEventThrottle={16}>
      <SnowSurface borderRadius={24} style={{ margin: 20 }}>
        <View style={{ padding: 24, borderRadius: 24, backgroundColor: '#173D31' }}>
          <Text style={{ color: '#F6EFE3' }}>Something warm to share</Text>
        </View>
      </SnowSurface>
    </Animated.ScrollView>
  );
}

export default function Screen() {
  return (
    <SnowSettleOverlay>
      <Cards />
    </SnowSettleOverlay>
  );
}

Custom personality and external controls:

const snow = useRef<SnowSettleOverlayRef>(null);

<SnowSettleOverlay
  ref={snow}
  density={55}
  maxParticles={180}
  wind={-12}
  maxPileHeight={7}
  shakeVelocity={1100}
  shakeOnDoubleTap
  colors={{ flake: '#FFFFFF', pile: '#F8FBFF', shadow: '#8EAEC8', highlight: '#FFFFFF' }}
>
  <Cards />
</SnowSettleOverlay>

// Call from your own accessible button or seasonal settings.
snow.current?.shake();
snow.current?.reset();

Import useRef from React and type SnowSettleOverlayRef from the piece for the controls example.

Props

PropTypeDefaultPurpose
childrenReactNoderequiredYour screen.
densitynumber70Falling flakes; limited by the pool size.
windnumber9Signed lateral drift in pt/s.
maxPileHeightnumber9Maximum snowcap height in points.
colorsPartial<SnowColors>cool white paletteFlake, pile, shadow, and highlight colors.
enabledbooleantrueEnables snowfall, accumulation, and snow drawing.
shakeVelocitynumber900Scroll release threshold in pt/s.
shakeOnDoubleTapbooleanfalseEnables a stationary double-tap shortcut.
maxParticlesnumber220Total pool size, clamped to 0–220. Reserve slots above density for powder.
surfaceArtworkreadonly { id: string; content: ReactNode }[]absentOptional decorative Skia nodes in surface-local coordinates. No text or images are built into the reusable overlay.
styleStyleProp<ViewStyle>flex: 1Container layout.
testIDstringsnow-settle-overlayRoot identifier.

SnowSurface accepts children, optional unique id, borderRadius (22), style, and testID. Match its radius to the card. Put margins on the wrapper and padding on the inner card, so its measured top matches the visible card edge. Changing dimensions resizes the height profile; unmounting removes the surface.

The ref exposes shake() and reset(). These remain available when the optional double tap is disabled. useSnowScroll() returns the animated handler directly.

Integration and limits

The overlay fills its parent, including a small embedded container, and clips to that rectangle. The host screen supplies safe-area insets. Use one vertical scroll view per overlay, with its viewport matching the overlay; keep a scrolling header inside that view, as in the demo. Independently clipped nested scroll views, virtualized/recycled cells, rotated cards, and continuously animated card transforms need application-specific registration/clip handling. Measurements refresh after layout, resizing, and every delivered scroll, rather than continuously measuring static cards.

All colors are replaceable. The component contains no fonts, brand, copy, external assets, network requests, or theme imports. The demo alone loads the catalog typography and an invented recipe brand. surfaceArtwork is a decorative artwork slot: it remains visible with snowfall disabled and is hidden from assistive technology. Place meaningful content in the native card children.

Compatibility

Target versions: Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, react-native-worklets 0.13.0, and Skia 2.14.0. These libraries are included in the matching Expo Go release. No extra native dependency is required.

iOS, Android, and web are implementation targets.

Accessibility

The snow layer ignores all pointer events and is hidden from VoiceOver and TalkBack. Card content remains accessible. The system's reduced-motion setting (including changes while mounted) stops physics and hides all snow; enabled={false} does the same. No snowfall or accumulation is used as a status indicator. Double tap is optional and does not claim the responder; an accessible host button calling shake() offers the same action. The demo provides a 48-point button and stops automatic scrolling under reduced motion.