npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-continuous-corners

v2.0.0

Published

iOS-style continuous corner radius for React Native - Cross-platform support for both iOS and Android | iOS 风格连续圆角 - 支持 iOS 和 Android 双平台

Readme

📐 React Native Continuous Corners

iOS-style Continuous Corners - Cross-platform support for iOS and Android

iOS-style continuous corner radius for React Native - Cross-platform support for both iOS and Android

npm version React Native Expo TypeScript License: MIT

🎯 Perfect Cross-platform Continuous Corner Solution

In React Native, Android does not natively support continuous corners for images (iOS's CALayer.cornerCurve = .continuous). Even with borderCurve="continuous", image corners on Android fall back to standard circular arcs, causing visual inconsistencies between iOS and Android.

This library solves the problem perfectly!

  • iOS: Uses native borderCurve='continuous' (zero overhead)
  • Android: Uses Skia Canvas inverted path corner filling (GPU accelerated)

Achieves perfectly consistent continuous corner effects for images on both Android and iOS.

💡 Solution

A high-performance React Native component that brings iOS continuous corner radius to both platforms. Uses native iOS borderCurve and Skia Canvas on Android for perfect cross-platform visual consistency with GPU acceleration.

✨ Features

📷 Image Component (ContinuousCornerImageRect) 🆕 Recommended

  • 🖼️ Rectangular Image Continuous Corners: Dynamic width/height image component (Discovery cards, photo galleries, etc.)
  • 🍎 iOS Native: Uses native borderCurve='continuous' (zero overhead)
  • 🤖 Android Perfect: Uses Skia inverted path corner filling (Solution B)
  • 🎬 Animation Support: Supports SharedValue animations (width, height, corner radius)

📷 Image Component (ContinuousCornerImage) - Backward Compatible

  • 🖼️ Square Image Continuous Corners: Fixed-size square image component
  • 🤖 Android Perfect Support: Uses Skia to implement iOS-style continuous corners on Android
  • 🍎 iOS Native Effect: True iOS-style continuous corner radius

📦 Container Component (ContinuousCornerContainer) 🆕

  • 🎴 Full Card Continuous Corners: Supports complex containers with photos + text + buttons
  • 🍎 iOS Zero Overhead: iOS automatically uses native borderCurve='continuous'
  • 🤖 Android Perfect Support: Uses Skia Canvas clipping, visually identical effect
  • 🃏 Use Cases: Tinder cards, Explore activity cards, user profile cards, etc.

🚀 General Features

  • 📱 Cross-platform Consistency: Identical visual effects on Android and iOS, no differences
  • 🚀 High Performance: GPU-accelerated rendering, 60fps+ smooth animations
  • 🎬 Animation Support: Seamless React Native Reanimated integration for dynamic corner animations
  • 🎨 Customizable: Adjustable corner smoothing (0.0 = standard, 0.6 = iOS continuous, 1.0 = maximum smoothness)
  • 📦 Easy to Use: Install via npm, no copy-paste required
  • 💪 TypeScript: Full type safety support

🔍 Preview

| Standard Border Radius | iOS Continuous Corner | |------------------------|----------------------| | Standard | Continuous |

⚡ Comparison: Why Do You Need This Library?

| Solution | Android Image Corners | iOS Image Corners | Performance | Notes | |----------|----------------------|-------------------|-------------|-------| | react-native-continuous-corners | ✅ Perfect support | ✅ Native support | ⭐⭐⭐⭐⭐ | Cross-platform solution! iOS native + Android GPU accelerated | | React Native borderCurve: 'continuous' | ❌ Images fall back to circular | ✅ Smooth (containers only) | ⭐⭐⭐⭐⭐ | ⚠️ iOS only, containers only. Images not supported on Android | | react-native-fast-squircle | ❌ Cannot clip images | ⚠️ Unstable | ⭐⭐⭐ | Android rendering limitations, does not support images | | Image + borderRadius | ❌ Standard corners only | ❌ Standard corners only | ⭐⭐⭐⭐⭐ | No continuous corner effect |

🎮 Try It Out

Want to see it in action? Check out the Example App - a complete Expo project with 3 interactive tests:

  • ✅ Static corner radius demonstration
  • ✅ Smoothing comparison (0.0 vs 0.6 vs 1.0)
  • ✅ Animated corner radius (Timing & Spring animations)
cd example-app
npm install
npx expo start

📱 View Example App README

📦 Installation

1. Install the package

# Using npm
npm install react-native-continuous-corners @shopify/react-native-skia react-native-reanimated react-native-worklets

# Using yarn
yarn add react-native-continuous-corners @shopify/react-native-skia react-native-reanimated react-native-worklets

# Using Expo (Recommended)
npx expo install react-native-continuous-corners @shopify/react-native-skia react-native-reanimated react-native-worklets

2. Configure Babel

Add react-native-reanimated/plugin to your babel.config.js:

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'], // or 'module:metro-react-native-babel-preset'
    plugins: [
      'react-native-reanimated/plugin', // ⚠️ Must be last!
    ],
  };
};

3. Clear cache and restart

# For Expo
npx expo start -c

# For React Native CLI
npx react-native start --reset-cache

🚀 Quick Start

📷 Rectangular Image Component (Recommended)

import { ContinuousCornerImageRect } from 'react-native-continuous-corners';

function DiscoveryCard() {
  return (
    <ContinuousCornerImageRect
      source="https://example.com/photo.jpg"
      width={screenWidth - 40}
      height={500}
      cornerRadius={24}
      cornerSmoothing={0.6}
      fit="cover"
      containerBackgroundColor="transparent"
    />
  );
}

🎬 Animation Support (Rectangular Images)

import { ContinuousCornerImageRect } from 'react-native-continuous-corners';
import { useSharedValue, withTiming } from 'react-native-reanimated';

function AnimatedPhoto() {
  const cornerRadius = useSharedValue(24);
  const cardWidth = useSharedValue(screenWidth - 40);
  const cardHeight = useSharedValue(400);

  const handleExpand = () => {
    cornerRadius.value = withTiming(47, { duration: 600 });
    cardWidth.value = withTiming(screenWidth, { duration: 600 });
    cardHeight.value = withTiming(screenHeight, { duration: 600 });
  };

  return (
    <TouchableOpacity onPress={handleExpand}>
      <ContinuousCornerImageRect
        source="https://example.com/photo.jpg"
        width={cardWidth}
        height={cardHeight}
        cornerRadius={cornerRadius}
        cornerSmoothing={1.0}
      />
    </TouchableOpacity>
  );
}

📷 Square Image Component (Backward Compatible)

import { ContinuousCornerImage } from 'react-native-continuous-corners';

function App() {
  return (
    <ContinuousCornerImage
      source="https://example.com/image.jpg"
      size={200}
      cornerRadius={40}
      cornerSmoothing={0.6}
    />
  );
}

Animated Corner Radius

import { ContinuousCornerImageAnimated } from 'react-native-continuous-corners';
import { useSharedValue, withSpring } from 'react-native-reanimated';
import { TouchableOpacity } from 'react-native';

function AnimatedExample() {
  const cornerRadius = useSharedValue(20);

  const handlePress = () => {
    cornerRadius.value = withSpring(60);
  };

  return (
    <TouchableOpacity onPress={handlePress}>
      <ContinuousCornerImageAnimated
        source="https://example.com/image.jpg"
        size={200}
        cornerRadius={cornerRadius}
        cornerSmoothing={0.6}
      />
    </TouchableOpacity>
  );
}

Container Usage (Cards with Photos + Text) 🆕

import { ContinuousCornerContainer } from 'react-native-continuous-corners';

function ActivityCard() {
  return (
    <ContinuousCornerContainer
      width={350}
      height={500}
      cornerRadius={24}
      cornerSmoothing={0.6}
    >
      {/* Photo */}
      <Image source={{ uri: 'https://example.com/photo.jpg' }} style={{ width: 350, height: 300 }} />

      {/* Text */}
      <View style={{ padding: 16 }}>
        <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Weekend Hiking</Text>
        <Text style={{ fontSize: 16, color: '#666' }}>Join us for an adventure!</Text>
      </View>
    </ContinuousCornerContainer>
  );
}

📖 API Reference

ContinuousCornerImage (Static)

| Prop | Type | Default | Description | |------|------|---------|-------------| | source | string \| number | Required | Image URL or local resource (require('./image.png')) | | size | number | Required | Container size (width and height) | | cornerRadius | number | Required | Corner radius in pixels | | cornerSmoothing | number | 0.6 | Smoothing factor: 0.0 = standard circle, 0.6 = iOS continuous, 1.0 = maximum smoothing | | style | ViewStyle | undefined | Additional container styles | | fit | 'cover' \| 'contain' \| 'fill' \| ... | 'cover' | Image fitting mode (Skia ImageShader fit modes) |

SkiaContinuousCornerImageAnimated (Animated)

Same as above, but cornerRadius accepts a Reanimated SharedValue<number>:

| Prop | Type | Default | Description | |------|------|---------|-------------| | cornerRadius | SharedValue<number> | Required | Animated corner radius using Reanimated SharedValue |

All other props are identical to the static version.

ContinuousCornerContainer (Container - Static) 🆕

For entire containers with continuous corners (including photos, text, buttons, etc.):

| Prop | Type | Default | Description | |------|------|---------|-------------| | children | ReactNode | Required | Child components (photos, text, buttons, etc.) | | width | number | Required | Container width | | height | number | Required | Container height | | cornerRadius | number | Required | Corner radius in pixels | | cornerSmoothing | number | 0.6 | Smoothing factor: 0.0 = standard circle, 0.6 = iOS continuous, 1.0 = maximum smoothing | | style | ViewStyle | undefined | Additional container styles | | backgroundColor | string | 'transparent' | Container background color |

Platform differences:

  • iOS: Uses native borderCurve='continuous', zero performance overhead ✅
  • Android: Uses Skia Canvas clipping, solves Android's lack of continuous corner support 🤖

ContinuousCornerContainerAnimated (Container - Animated) 🆕

Animated version of the container, supports Reanimated animations for cornerRadius (recommended for iOS only).

🎨 Usage Examples

1. User Avatar with Continuous Corner

<SkiaContinuousCornerImage
  source={{ uri: user.avatar }}
  size={80}
  cornerRadius={20}
  cornerSmoothing={0.6}
  style={{ marginRight: 12 }}
/>

2. Photo Gallery with Smooth Corners

const photos = ['photo1.jpg', 'photo2.jpg', 'photo3.jpg'];

<View style={{ flexDirection: 'row' }}>
  {photos.map((photo, index) => (
    <SkiaContinuousCornerImage
      key={index}
      source={{ uri: photo }}
      size={120}
      cornerRadius={30}
      cornerSmoothing={0.6}
      style={{ marginRight: 8 }}
    />
  ))}
</View>

3. Interactive Card with Animated Corners

function InteractiveCard() {
  const radius = useSharedValue(20);
  const [isExpanded, setIsExpanded] = useState(false);

  const handleToggle = () => {
    radius.value = withTiming(isExpanded ? 20 : 60, {
      duration: 800,
      easing: Easing.bezier(0.25, 0.1, 0.25, 1), // iOS-style easing
    });
    setIsExpanded(!isExpanded);
  };

  return (
    <TouchableOpacity onPress={handleToggle}>
      <SkiaContinuousCornerImageAnimated
        source="https://example.com/card-image.jpg"
        size={300}
        cornerRadius={radius}
        cornerSmoothing={0.6}
      />
    </TouchableOpacity>
  );
}

4. Different Smoothing Values Comparison

const smoothingValues = [0.0, 0.3, 0.6, 1.0];

<View style={{ flexDirection: 'row' }}>
  {smoothingValues.map((smoothing) => (
    <View key={smoothing}>
      <SkiaContinuousCornerImage
        source="https://example.com/image.jpg"
        size={100}
        cornerRadius={25}
        cornerSmoothing={smoothing}
      />
      <Text>Smoothing: {smoothing}</Text>
    </View>
  ))}
</View>

5. Container with Card Content (Photos + Text + Buttons) 🆕

For complex scenarios like Explore cards (with photos, text, buttons, etc.):

import { ContinuousCornerContainer } from 'react-native-continuous-corners';

// Tinder-style activity card
function ActivityCard({ activity }) {
  return (
    <ContinuousCornerContainer
      width={screenWidth * 0.96}
      height={600}
      cornerRadius={24}
      cornerSmoothing={0.6}
      backgroundColor="#FFFFFF"
      style={{ margin: 8 }}
    >
      {/* 📷 Photo */}
      <Image
        source={{ uri: activity.coverImage }}
        style={{ width: '100%', height: 400 }}
      />

      {/* 📝 Activity Info */}
      <View style={{ padding: 16 }}>
        <Text style={{ fontSize: 24, fontWeight: 'bold' }}>
          {activity.title}
        </Text>
        <Text style={{ fontSize: 16, color: '#666', marginTop: 8 }}>
          {activity.subtitle}
        </Text>

        {/* 🏷️ Tags */}
        <View style={{ flexDirection: 'row', marginTop: 12 }}>
          <View style={styles.tag}>
            <Text>Hiking</Text>
          </View>
          <View style={styles.tag}>
            <Text>Outdoor</Text>
          </View>
        </View>

        {/* 🔘 Action Button */}
        <TouchableOpacity style={styles.button}>
          <Text>Join Activity</Text>
        </TouchableOpacity>
      </View>
    </ContinuousCornerContainer>
  );
}

Why do you need the container version?

  • Android native Image doesn't support continuous corners: Even with borderCurve='continuous', Android images fall back to standard circular corners
  • Cards contain multiple elements: Photos + text + buttons need continuous corners as a whole
  • iOS zero overhead: iOS automatically uses native borderCurve='continuous'
  • Android perfect support: Uses Skia Canvas clipping for completely consistent visual effects

🔬 Technical Details

Algorithm Explanation

This component uses pure cubic Bézier curves to approximate iOS continuous corner radius:

// Control point distance calculation
const controlPointRatio = 0.55228 + smoothness * 0.15;
const controlDistance = radius * controlPointRatio;

// Each corner is drawn with one cubic Bézier curve
path.cubicTo(cp1x, cp1y, cp2x, cp2y, endX, endY);

Why This Works:

  1. Standard Circle Approximation: 0.55228 is the magic number for approximating a circle with Bézier curves (4/3 * tan(π/8))
  2. iOS Continuous Enhancement: Adding smoothness * 0.15 extends the control points further, creating the characteristic "squircle" shape
  3. No Arc Calculations: Unlike react-native-fast-squircle which uses arcs + curves, this uses pure curves, avoiding complex trigonometry

Performance Characteristics

  • Rendering: GPU-accelerated via Skia Canvas
  • Animation: Runs on UI thread via Reanimated worklets
  • Memory: Minimal overhead, path is recomputed only when props change
  • Frame Rate: Maintains 60fps+ on modern devices

Comparison with Other Solutions

| Aspect | This Component | borderCurve: 'continuous' | react-native-fast-squircle | |--------|---------------|----------------------------|------------------------------| | Android Support | ✅ Perfect | ❌ Falls back to circular | ❌ Cannot clip images | | Animation | ✅ Smooth 60fps | ✅ Smooth (containers only) | ⚠️ Performance issues | | Images | ✅ Full support | ✅ Full support | ❌ Android limitation | | Customization | ✅ Adjustable smoothing | ❌ Fixed | ✅ Adjustable |

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

  1. Clone the repository
  2. Install dependencies: npm install
  3. Run the example app: npm start

Guidelines

  • Follow the existing code style
  • Add tests for new features
  • Update documentation as needed
  • Ensure TypeScript types are correct

📄 License

MIT License © 2025 Yu Jiawei

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

🙏 Acknowledgments

📞 Contact


If this project helped you, please consider giving it a ⭐ on GitHub!