
Security News
TypeScript 6.0 Released: The Final JavaScript-Based Version
TypeScript 6.0 introduces new standard APIs, modern default settings, and deprecations as it prepares projects for the upcoming TypeScript 7.0 release.
react-native-ease
Advanced tools
Lightweight declarative animations powered by platform APIs. Uses Core Animation on iOS and Animator on Android — zero JS overhead.
App & Flow is a Montreal-based React Native engineering and consulting studio. We partner with the world’s top companies and are recommended by Expo. Need a hand? Let’s build together. team@appandflow.com
npm install react-native-ease
# or
yarn add react-native-ease
If you're already using react-native-reanimated or React Native's Animated API, this project includes an Agent Skill that scans your codebase for animations that can be replaced with react-native-ease and migrates them automatically.
npx skills add appandflow/react-native-ease
Then invoke the skill in your agent (e.g., /react-native-ease-refactor in Claude Code).
The skill will:
import { EaseView } from 'react-native-ease';
function FadeCard({ visible, children }) {
return (
<EaseView
animate={{ opacity: visible ? 1 : 0 }}
transition={{ type: 'timing', duration: 300 }}
style={styles.card}
>
{children}
</EaseView>
);
}
EaseView works like a regular View — it accepts children, styles, and all standard view props. When values in animate change, it smoothly transitions to the new values using native platform animations.
| Use case | Ease | Reanimated |
|---|---|---|
| Fade/slide/scale on state change | ✅ | |
| Enter/exit animations | ✅ | |
| Gesture-driven animations (pan, pinch) | ✅ | |
| Layout animations (width, height) | ✅ | |
| Complex interpolations & chaining | ✅ |
Timing animations transition from one value to another over a fixed duration with an easing curve.
<EaseView
animate={{ opacity: isVisible ? 1 : 0 }}
transition={{ type: 'timing', duration: 300, easing: 'easeOut' }}
/>
| Parameter | Type | Default | Description |
|---|---|---|---|
duration | number | 300 | Duration in milliseconds |
easing | EasingType | 'easeInOut' | Easing curve (preset name or [x1, y1, x2, y2] cubic bezier) |
loop | string | — | 'repeat' restarts from the beginning, 'reverse' alternates direction |
Available easing curves:
'linear' — constant speed'easeIn' — starts slow, accelerates'easeOut' — starts fast, decelerates'easeInOut' — slow start and end, fast middle[x1, y1, x2, y2] — custom cubic bezier (same as CSS cubic-bezier())Pass a [x1, y1, x2, y2] tuple for custom cubic bezier curves. The values correspond to the two control points of the bezier curve, matching the CSS cubic-bezier() function.
// Standard Material Design easing
<EaseView
animate={{ opacity: isVisible ? 1 : 0 }}
transition={{ type: 'timing', duration: 300, easing: [0.4, 0, 0.2, 1] }}
/>
// Overshoot (y-values can exceed 0–1)
<EaseView
animate={{ scale: active ? 1.2 : 1 }}
transition={{ type: 'timing', duration: 500, easing: [0.68, -0.55, 0.265, 1.55] }}
/>
x-values (x1, x2) must be between 0 and 1. y-values can exceed this range to create overshoot effects.
Spring animations use a physics-based model for natural-feeling motion. Great for interactive elements.
<EaseView
animate={{ translateX: isOpen ? 200 : 0 }}
transition={{ type: 'spring', damping: 15, stiffness: 120, mass: 1 }}
/>
| Parameter | Type | Default | Description |
|---|---|---|---|
damping | number | 15 | Friction — higher values reduce oscillation |
stiffness | number | 120 | Spring constant — higher values mean faster animation |
mass | number | 1 | Mass of the object — higher values mean slower, more momentum |
Spring presets for common feels:
// Snappy (no bounce)
{ type: 'spring', damping: 20, stiffness: 300, mass: 1 }
// Gentle bounce
{ type: 'spring', damping: 12, stiffness: 120, mass: 1 }
// Bouncy
{ type: 'spring', damping: 8, stiffness: 200, mass: 1 }
// Slow and heavy
{ type: 'spring', damping: 20, stiffness: 60, mass: 2 }
Use { type: 'none' } to apply values immediately without animation. Useful for skipping animations in reduced-motion modes or when you need an instant state change.
<EaseView
animate={{ opacity: isVisible ? 1 : 0 }}
transition={{ type: 'none' }}
/>
onTransitionEnd fires immediately with { finished: true }.
borderRadius can be animated just like other properties. It uses hardware-accelerated platform APIs — ViewOutlineProvider + clipToOutline on Android and layer.cornerRadius + layer.masksToBounds on iOS. Unlike RN's style-based borderRadius (which uses a Canvas drawable on Android), this clips children properly and is GPU-accelerated.
<EaseView
animate={{ borderRadius: expanded ? 0 : 16 }}
transition={{ type: 'timing', duration: 300 }}
style={styles.card}
>
<Image source={heroImage} style={styles.image} />
<Text>Content is clipped to rounded corners</Text>
</EaseView>
When borderRadius is in animate, any borderRadius in style is automatically stripped to avoid conflicts.
backgroundColor can be animated using any React Native color value. Colors are converted to native ARGB integers via processColor().
<EaseView
animate={{ backgroundColor: isActive ? '#3B82F6' : '#E5E7EB' }}
transition={{ type: 'timing', duration: 300 }}
style={styles.card}
>
<Text>Tap to change color</Text>
</EaseView>
On Android, background color uses ValueAnimator.ofArgb() (timing only — spring is not supported for colors). On iOS, it uses CAAnimation on the backgroundColor layer key path and supports both timing and spring transitions.
Note: On Android, background color animation uses
ValueAnimator.ofArgb()which only supports timing transitions. Spring transitions forbackgroundColorare not supported on Android and will fall back to timing with the default duration. On iOS, both timing and spring transitions work for background color.
When backgroundColor is in animate, any backgroundColor in style is automatically stripped to avoid conflicts.
All properties are set in the animate prop as flat values (no transform array).
<EaseView
animate={{
opacity: 1, // 0 to 1
translateX: 0, // pixels
translateY: 0, // pixels
scale: 1, // 1 = normal size (shorthand for scaleX + scaleY)
scaleX: 1, // horizontal scale
scaleY: 1, // vertical scale
rotate: 0, // Z-axis rotation in degrees
rotateX: 0, // X-axis rotation in degrees (3D)
rotateY: 0, // Y-axis rotation in degrees (3D)
borderRadius: 0, // pixels (hardware-accelerated, clips children)
backgroundColor: 'transparent', // any RN color value
}}
/>
scale is a shorthand that sets both scaleX and scaleY. When scaleX or scaleY is also specified, it overrides the scale value for that axis.
You can animate any combination of properties simultaneously. All properties share the same transition config.
Timing animations can loop infinitely. Use 'repeat' to restart from the beginning or 'reverse' to alternate direction.
// Pulsing opacity
<EaseView
initialAnimate={{ opacity: 0.3 }}
animate={{ opacity: 1 }}
transition={{ type: 'timing', duration: 1000, easing: 'easeInOut', loop: 'reverse' }}
/>
// Marquee-style scroll
<EaseView
initialAnimate={{ translateX: 0 }}
animate={{ translateX: -300 }}
transition={{ type: 'timing', duration: 3000, easing: 'linear', loop: 'repeat' }}
/>
Loop requires initialAnimate to define the starting value. Spring animations do not support looping.
Use initialAnimate to set starting values. On mount, the view starts at initialAnimate values and animates to animate values.
// Fade in and slide up on mount
<EaseView
initialAnimate={{ opacity: 0, translateY: 20 }}
animate={{ opacity: 1, translateY: 0 }}
transition={{ type: 'spring', damping: 15, stiffness: 120, mass: 1 }}
/>
Without initialAnimate, the view renders at the animate values immediately with no animation on mount.
Animations are interruptible by default. If you change animate values while an animation is running, it smoothly redirects to the new target from wherever it currently is — no jumping or restarting.
// Rapidly toggling this is fine — each toggle smoothly
// redirects the animation from its current position
<EaseView
animate={{ translateX: isLeft ? 0 : 200 }}
transition={{ type: 'spring', damping: 15, stiffness: 120, mass: 1 }}
/>
By default, scale and rotation animate from the view's center. Use transformOrigin to change the pivot point with 0–1 fractions.
// Rotate from top-left corner
<EaseView
animate={{ rotate: isOpen ? 45 : 0 }}
transformOrigin={{ x: 0, y: 0 }}
transition={{ type: 'spring', damping: 12, stiffness: 200, mass: 1 }}
style={styles.card}
/>
// Scale from bottom-right
<EaseView
animate={{ scale: active ? 1.2 : 1 }}
transformOrigin={{ x: 1, y: 1 }}
transition={{ type: 'spring', damping: 15, stiffness: 120, mass: 1 }}
style={styles.card}
/>
| Value | Position |
|---|---|
{ x: 0, y: 0 } | Top-left |
{ x: 0.5, y: 0.5 } | Center (default) |
{ x: 1, y: 1 } | Bottom-right |
EaseView accepts all standard ViewStyle properties. If a property appears in both style and animate, the animated value takes priority and the style value is stripped. A dev warning is logged when this happens.
// opacity in style works because only translateY is animated
<EaseView
animate={{ translateY: moved ? -10 : 0 }}
transition={{ type: 'spring', damping: 15, stiffness: 120, mass: 1 }}
style={{
opacity: 0.9,
backgroundColor: 'white',
borderRadius: 16,
padding: 16,
}}
>
<Text>Notification card</Text>
</EaseView>
// ⚠️ opacity is in both — animate wins, style opacity is stripped, dev warning logged
<EaseView
animate={{ opacity: 1 }}
style={{ opacity: 0.5, backgroundColor: 'white' }}
/>
<EaseView>A View that animates property changes using native platform APIs.
| Prop | Type | Description |
|---|---|---|
animate | AnimateProps | Target values for animated properties |
initialAnimate | AnimateProps | Starting values for enter animations (animates to animate on mount) |
transition | Transition | Animation configuration (timing, spring, or none) |
onTransitionEnd | (event) => void | Called when all animations complete with { finished: boolean } |
transformOrigin | { x?: number; y?: number } | Pivot point for scale/rotation as 0–1 fractions. Default: { x: 0.5, y: 0.5 } (center) |
useHardwareLayer | boolean | Android only — rasterize to GPU texture during animations. See Hardware Layers. Default: false |
style | ViewStyle | Non-animated styles (layout, colors, borders, etc.) |
children | ReactNode | Child elements |
| ...rest | ViewProps | All other standard View props |
AnimateProps| Property | Type | Default | Description |
|---|---|---|---|
opacity | number | 1 | View opacity (0–1) |
translateX | number | 0 | Horizontal translation in pixels |
translateY | number | 0 | Vertical translation in pixels |
scale | number | 1 | Uniform scale factor (shorthand for scaleX + scaleY) |
scaleX | number | 1 | Horizontal scale factor (overrides scale for X axis) |
scaleY | number | 1 | Vertical scale factor (overrides scale for Y axis) |
rotate | number | 0 | Z-axis rotation in degrees |
rotateX | number | 0 | X-axis rotation in degrees (3D) |
rotateY | number | 0 | Y-axis rotation in degrees (3D) |
borderRadius | number | 0 | Border radius in pixels (hardware-accelerated, clips children) |
backgroundColor | ColorValue | 'transparent' | Background color (any RN color value). Timing-only on Android, spring+timing on iOS. |
Properties not specified in animate default to their identity values.
TimingTransition{
type: 'timing';
duration?: number; // default: 300 (ms)
easing?: EasingType; // default: 'easeInOut' — preset name or [x1, y1, x2, y2]
loop?: 'repeat' | 'reverse'; // default: none
}
SpringTransition{
type: 'spring';
damping?: number; // default: 15
stiffness?: number; // default: 120
mass?: number; // default: 1
}
NoneTransition{
type: 'none';
}
Applies values instantly with no animation. onTransitionEnd fires immediately with { finished: true }.
Setting useHardwareLayer rasterizes the view into a GPU texture for the duration of the animation. This means animated property changes (opacity, scale, rotation) are composited on the RenderThread without redrawing the view hierarchy — useful for complex views with many children.
<EaseView animate={{ opacity: isVisible ? 1 : 0 }} useHardwareLayer />
Trade-offs:
translateX/translateY on views with overflowing content.No-op on iOS where Core Animation already composites off the main thread.
EaseView is a native Fabric component. The JS side flattens your animate and transition props into flat native props. When those props change, the native view:
On iOS, this uses CABasicAnimation/CASpringAnimation on CALayer key paths. On Android, this uses ObjectAnimator/SpringAnimation on View properties. No JS thread involvement during the animation.
MIT
Made with create-react-native-library
FAQs
Lightweight declarative animations powered by platform APIs
We found that react-native-ease demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
TypeScript 6.0 introduces new standard APIs, modern default settings, and deprecations as it prepares projects for the upcoming TypeScript 7.0 release.

Security News
/Research
Newly published Trivy Docker images (0.69.4, 0.69.5, and 0.69.6) were found to contain infostealer IOCs and were pushed to Docker Hub without corresponding GitHub releases.

Research
/Security News
The worm-enabled campaign hit @emilgroup and @teale.io, then used an ICP canister to deliver follow-on payloads.