diff --git a/packages/animations/docs/components/AnimatedContainer.md b/packages/animations/docs/components/AnimatedContainer.md
new file mode 100644
index 00000000..12de6d0b
--- /dev/null
+++ b/packages/animations/docs/components/AnimatedContainer.md
@@ -0,0 +1,155 @@
+import { Required } from '@site/src/components'
+
+# AnimatedContainer
+
+This component is built on top of [Reanimated custom animations](https://docs.swmansion.com/react-native-reanimated/docs/api/LayoutAnimations/customAnimations)
+and let us animate the entry and exitFrom of the container, honouring
+the [Reduce Motion] (https://reactnative.dev/docs/accessibilityinfo) preference.
+
+## Example
+
+```jsx
+import { AnimatedContainer } from '@react-native-ama/animations';
+
+;
+```
+
+When the component is mounted, it will animate it from: `from -> to`, and when it is unmounted, it will animate it from: `exitFrom -> to`.
+If the property `exitFrom from` is not specified, it will then play the animation in reverse: `to -> from`.
+
+## Accessibility
+
+For both, enter and exitFrom animation, the component will use a `duration={0}` for each [motion property](../utils/isMotionAnimation) when [Reduce Motion](../hooks/useAMAContext#isreducemotionenabled) option is enabled.
+
+## Props
+
+### `autofocus`
+
+If set to true, wraps the child inside the [AutofocusContainer](./AutofocusContainer)
+
+| Type | Default |
+| ------- | ------- |
+| boolean | false |
+
+### `duration`
+
+The preferred animation duration.
+
+| Type | Default |
+| ------ | ------- |
+| number | 300 |
+
+:::note
+
+The component will use a `duration={0}` for each [motion property](../utils/isMotionAnimation) when [Reduce Motion](../hooks/useAMAContext#isreducemotionenabled) option is enabled.
+
+:::
+
+### `from`
+
+The initial value of the animation.
+
+| Type |
+| ---------------------------------- |
+| ViewStyle \| ReanimatedEntryValues |
+
+This parameter sets the initial values for the [Reanimated custom animations](https://docs.swmansion.com/react-native-reanimated/docs/api/LayoutAnimations/customAnimations).
+In additional to `ViewStyle`, this property also allows access to special values available by Reanimated:
+
+| Value | Description |
+| ------------------- | ------------------------------------------------------------- |
+| targetOriginX | X coordinate of top left corner in parent's coordinate system |
+| targetOriginY | Y coordinate of top left corner in parent's coordinate system |
+| targetWidth | view's width |
+| targetHeight | view's height |
+| targetGlobalOriginX | X coordinate of top left corner in global coordinate system |
+| targetGlobalOriginY | Y coordinate of top left corner in global coordinate system |
+
+#### Example
+
+```jsx
+import { AnimatedContainer } from 'react-native-ama';
+
+;
+```
+
+In this example, `translateY` is assigned the value of the view's height when the container is animated.
+
+### `to`
+
+The final (or initial) value of the animation.
+
+| Type |
+| --------- |
+| ViewStyle |
+
+This value is used for both entering and exiting animation.
+For the entering animation, this is used as the final state; for the exitFrom one, as the initial state.
+
+```jsx
+import { AnimatedContainer } from 'react-native-ama';
+
+;
+```
+
+In this case, the view will fade In when mounted and fade out when unmounted.
+
+### `exitFrom`
+
+The initial value for the unmounting animation.
+
+| Type |
+| --------------------------------- |
+| ViewStyle \| ReanimatedExitValues |
+
+In additional to `ViewStyle` this property also allows to access to special values available by Reanimated:
+
+| Value | Description |
+| -------------------- | ------------------------------------------------------------- |
+| currentOriginX | X coordinate of top left corner in parent's coordinate system |
+| currentOriginY | Y coordinate of top left corner in parent's coordinate system |
+| currentWidth | view's width |
+| currentHeight | view's height |
+| currentGlobalOriginX | X coordinate of top left corner in global coordinate system |
+| currentGlobalOriginY | Y coordinate of top left corner in global coordinate system |
+
+```jsx
+import { AnimatedContainer } from 'react-native-ama';
+
+;
+```
+
+Because in the [from](#from) animation, we did specify the special value **targetHeight** we need to provide a "different" value for the exiting animation
+as that special name does not exist for the exitFrom animation.
+
+:::note
+
+If not specified, the [from](#from) value is used as the final one for the unmounting animation.
+
+:::
+
+### `style`
+
+The container style
+
+| Type |
+| --------- |
+| ViewStyle |
+
+## Related guidelines
+
+- [Animations](../guidelines/animations)
diff --git a/packages/animations/docs/components/_category_.json b/packages/animations/docs/components/_category_.json
new file mode 100644
index 00000000..92f583da
--- /dev/null
+++ b/packages/animations/docs/components/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "Components",
+ "collapsible": true,
+ "collapsed": false
+}
diff --git a/packages/animations/docs/hooks/_category_.json b/packages/animations/docs/hooks/_category_.json
new file mode 100644
index 00000000..15dc8a9e
--- /dev/null
+++ b/packages/animations/docs/hooks/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "Hooks",
+ "collapsible": true,
+ "collapsed": false
+}
diff --git a/packages/animations/docs/hooks/useAnimation.mdx b/packages/animations/docs/hooks/useAnimation.mdx
new file mode 100644
index 00000000..f948526c
--- /dev/null
+++ b/packages/animations/docs/hooks/useAnimation.mdx
@@ -0,0 +1,252 @@
+import ReactPlayer from 'react-player';
+
+# useAnimation
+
+`useAnimation` is a hook that helps create accessible animations by honouring the user [Reduce Motion](/core/hooks/useAMAContext#isreducemotionenabled) preference.
+
+:::note
+
+This hook uses the react-native built-in [Animated API](https://reactnative.dev/docs/animations), [check here](./useReanimatedTiming.md) for accessible animations in Reanimated.
+:::
+
+## Usage
+
+```ts
+import { useAnimation } from 'react-native-ama';
+
+const { animatedStyle, progress, play } = useAnimation({
+ duration,
+ useNativeDriver,
+ from: {},
+ to: {},
+ skipIfReduceMotionEnabled,
+});
+```
+
+| Property | Type | Description |
+|---------------------------|-----------|-----------------------------------------------------------------------------------------------------|
+| duration | number | the animation duration |
+| useNativeDriver | boolean | [Using the native driver](https://reactnative.dev/docs/animations#using-the-native-driver) |
+| from | ViewStyle | the initial state of the animation |
+| to | ViewStyle | the final state of the animation |
+| skipIfReduceMotionEnabled | boolean | _(Optional)_ if true, the animation will be played with duration 0 when `Reduce Motion` is enabled. |
+
+### Returns
+
+| Property | Type | Description |
+|---------------|----------------------------------|--------------------------------------------------|
+| animatedStyle | Object | the animation style to apply at the component |
+| progress | Animated.Value | The Animated.Value used to trigger the animation |
+| play | (toValue = 1) => Animated.timing | Returns the Animated.timing |
+
+## Example
+
+The following animations translate in, with fading, an absolute positioned view:
+
+```ts
+import React, { useRef } from 'react';
+import { Animated, Dimensions, StyleSheet, View } from 'react-native';
+import { Pressable, Text } from 'react-native-ama';
+import { useAccessibleAnimation } from 'react-native-ama';
+
+export const ReduceMotionScreen = () => {
+ const [overlayProgressValue, setOverlayProgressValue] =
+ React.useState(null);
+ const animationProgress = useRef(
+ new Animated.Value(0),
+ ).current;
+ const { play, animatedStyle, progress } = useAccessibleAnimation({
+ duration: 300,
+ useNativeDriver: true,
+ from: {
+ opacity: 0,
+ transform: [{ translateY: 200 }],
+ },
+ to: {
+ opacity: 1,
+ transform: [{ translateY: 0 }],
+ },
+ });
+
+ const overlayStyle = {
+ opacity: overlayProgressValue || 0,
+ };
+
+ const playAnimation = () => {
+ setOverlayProgressValue(progress);
+ play().start();
+ };
+
+ return (
+ <>
+
+
+
+ {overlayProgressValue ? (
+ reverseAnimation()}>
+
+
+ ) : null}
+
+ Content goes here
+
+ >
+ );
+};
+```
+
+This is the result when we play the animation with Reduce Motion off and on:
+
+| Reduce Motion: **off** | Reduce Motion: **on** |
+| ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
+| | | |
+
+When reduce Motion is off, the animation is played as specified; while when is **on** any [motion](../utils/isMotionAnimation.md) animation is played instantaneity (using a duration of 0), while other properties, like opacity, are played as specified.
+
+## Sequential animation
+
+Let's consider the following animation:
+
+
+
+
+The animation is defined as:
+
+```tsx
+const {
+ play: play2,
+ animatedStyle: animatedStyle2,
+ progress: progress2,
+} = useAccessibleAnimation({
+ duration: 300,
+ useNativeDriver: false,
+ from: {
+ opacity: 0,
+ width: 0,
+ left: MAX_LINE_WIDTH / 2,
+ },
+ to: {
+ opacity: 1,
+ width: MAX_LINE_WIDTH,
+ left: theme.padding.big,
+ },
+});
+const { play: play3, animatedStyle: animatedStyle3 } = useAccessibleAnimation({
+ duration: 300,
+ useNativeDriver: false,
+ from: {
+ height: 2,
+ marginTop: -1,
+ },
+ to: {
+ height: 200,
+ marginTop: -100,
+ },
+});
+
+const playAnimation = () => {
+ play2().start(() => {
+ play3().start();
+ });
+};
+```
+
+It's a two-part animation, where the first one the animates the view width and opacity:
+
+```js
+from: {
+ opacity: 0,
+ width: 0,
+ left: MAX_LINE_WIDTH / 2,
+},
+to: {
+ opacity: 1,
+ width: MAX_LINE_WIDTH,
+ left: theme.padding.big,
+}
+```
+
+The second one the height:
+
+```js
+from: {
+ height: 2,
+ marginTop: -1,
+},
+to: {
+ height: 200,
+ marginTop: -100,
+},
+```
+
+Let's play the animation when **reduce motion** is enabled:
+
+
+
+
+
+The animation doesn't look right. The first animation is played correctly, but:
+
+- the width animation is played with a duration of 0s
+- the fade animation is played with a duration of 300ms
+
+After that, the height jumps instantly from **2** to **200**.
+
+### skipIfReduceMotionEnabled
+
+One way to fix the animation is using the `skipIfReduceMotionEnabled` parameter; as this makes all the animations defined to be played instantly:
+
+```ts
+const {
+ play: play2,
+ animatedStyle: animatedStyle2,
+ progress: progress2,
+} = useAccessibleAnimation({
+ duration: 300,
+ useNativeDriver: false,
+ skipIfReduceMotionEnabled: true,
+ from: {
+ opacity: 0,
+ width: 0,
+ left: MAX_LINE_WIDTH / 2,
+ },
+ to: {
+ opacity: 1,
+ width: MAX_LINE_WIDTH,
+ left: theme.padding.big,
+ },
+});
+```
+
+The result is:
+
+
+
+## Related guidelines
+
+- [Animations](../guidelines/animations)
diff --git a/packages/animations/docs/hooks/useAnimationDuration.md b/packages/animations/docs/hooks/useAnimationDuration.md
new file mode 100644
index 00000000..5100e677
--- /dev/null
+++ b/packages/animations/docs/hooks/useAnimationDuration.md
@@ -0,0 +1,55 @@
+# useAnimationDuration
+
+When passing a motion property, returns 0 if [Reduce Motion](../hooks/useAMAContext#isreducemotionenabled) is enabled otherwise the given value.
+
+
+## Usage
+
+```js
+import { useAnimationDuration } from 'react-native-ama';
+
+const { getAnimationDuration } = useAccessibleAnimationDuration();
+```
+
+## getAnimationDuration
+
+### Syntax
+
+```js
+function getAnimationDuration(
+ property: ViewStyle,
+ durationMS: number,
+): WithTimingConfig {}
+```
+
+| Property | Description |
+| ---------- | -------------------------------------------- |
+| property | The property to animate |
+| durationMS | The duration to use if reduced motion is off |
+
+### Example
+
+We can create more accessible animations when using Reanimated:
+
+```ts
+const value = useSharedValue(0);
+
+const animatedStyles = useAnimatedStyle(() => {
+ return {
+ transform: [{ translateX: value.value * 255 }],
+ };
+});
+
+const playAnimation = () => {
+ value.value = withTiming(
+ Math.random(),
+ getAnimationDuration('translateX', 300),
+ );
+};
+```
+
+Because we specified `translateX` as the property we're going to use for the animation, and considering that that property is a [motion animation](../utils/isMotionAnimation.md); `playAnimation` will use a duration of **300ms** when reduce motion is _off_, and duration of **0s** when is on
+
+## Related guidelines
+
+- [Animations](../guidelines/animations)
diff --git a/packages/animations/docs/hooks/useReanimatedTiming.md b/packages/animations/docs/hooks/useReanimatedTiming.md
new file mode 100644
index 00000000..4b7181be
--- /dev/null
+++ b/packages/animations/docs/hooks/useReanimatedTiming.md
@@ -0,0 +1,164 @@
+# useReanimatedTiming
+
+This hooks allow using custom [withTiming](#withtiming) and `withSpring` functions that are reduce motion aware.
+
+## Usage
+
+```js
+import { useReanimatedTiming } from 'react-native-ama';
+
+const { withTiming, withSrping } = useReanimatedTiming();
+```
+
+## Example
+
+```tsx
+import * as React from 'react';
+import { StyleSheet, View } from 'react-native';
+import {
+ ClickableSpan,
+ Span,
+ isMotionAnimation,
+ useAMAContext,
+ useAnimationDuration,
+ useReanimatedTiming,
+} from 'react-native-ama';
+import Animated, {
+ useAnimatedStyle,
+ useSharedValue,
+} from 'react-native-reanimated';
+
+export const ReanimatedReduceMotionScreen = () => {
+ const value = useSharedValue(0);
+ const { withTiming, withSpring } = useReanimatedTiming();
+
+ const animatedStyles = useAnimatedStyle(() => {
+ return {
+ transform: [{ translateX: value.value * 255 }],
+ };
+ });
+
+ const testWithTiming = () => {
+ value.value = withTiming('translateX', Math.random(), { duration: 300 });
+ };
+
+ const testWithSpring = () => {
+ value.value = withSpring('translateX', Math.random());
+ };
+
+ return (
+
+
+ This example shows how to use the{' '}
+ {}}>getAnimationDuration{' '}
+ with Reanimated for a more accessible animations.
+
+
+
+
+ withTiming
+
+
+ withSpring
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ view: {
+ paddingHorizontal: theme.padding.big,
+ },
+ box: {
+ width: 100,
+ height: 100,
+ borderRadius: 20,
+ backgroundColor: theme.color.mixed,
+ },
+ intro: {
+ lineHeight: theme.lineHeight.medium,
+ },
+});
+```
+
+## withTiming
+
+Under the hood calls the
+reanimated [withTiming](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withTiming) function.
+
+If the given `propertyKey` is a motion one and [reduce motion](/core/hooks/useAMAContext#isreducemotionenabled) is enabled, the
+force the duration to be 0, before calling `withTiming`.
+
+### Syntax
+
+```js
+withTiming(
+ propertyKey
+:
+keyof
+ViewStyle,
+ toValue
+:
+number,
+ config
+:
+WithTimingConfig = {},
+ callback ? : AnimationCallback
+)
+;
+```
+
+| Property | Description |
+| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| propertyKey | The animation key that will be used with the `useSharedValue` |
+| toValue | The [target value](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withTiming#tovalue-number--string) parameter passed to the original `withTiming` |
+| config | The [config](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withTiming#options-object) parameter passed to the original `withTiming` |
+| callback | The [callback](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withTiming#callback-functionoptional) parameter passed to the original `withTiming` |
+
+#### Example
+
+```js
+value.value = withTiming('translateX', Math.random(), { duration: 300 });
+```
+
+## withSpring
+
+Under the hood calls the
+reanimated [withSpring](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withSpring) function.
+
+If the given `propertyKey` is a motion one and [reduce motion](/core/hooks/useAMAContext#isreducemotionenabled) is enabled,
+then calls `withTiming` function with duration 0 instead.
+
+### Syntax
+
+```js
+withTiming(
+ propertyKey
+:
+keyof
+ViewStyle,
+ toValue
+:
+number,
+ config ? : WithSpringConfig,
+ callback ? : AnimationCallback,
+)
+;
+```
+
+| Property | Description |
+| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| propertyKey | The animation key that will be used with the `useSharedValue` |
+| toValue | The [target value](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withTiming#tovalue-number--string) parameter passed to the original `withTiming` |
+| config | The [config](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withTiming#options-object) parameter passed to the original `withTiming` |
+| callback | The [callback](https://docs.swmansion.com/react-native-reanimated/docs/api/animations/withTiming#callback-functionoptional) parameter passed to the original `withTiming` |
+
+#### Example
+
+```js
+value.value = withSpring('translateX', Math.random());
+```
+
+## Related guidelines
+
+- [Animations](../guidelines/animations)
diff --git a/packages/animations/docs/utilities/_category_.json b/packages/animations/docs/utilities/_category_.json
new file mode 100644
index 00000000..bd5207f7
--- /dev/null
+++ b/packages/animations/docs/utilities/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "Utilities",
+ "collapsible": true,
+ "collapsed": false
+}
diff --git a/packages/animations/docs/utilities/isMotionAnimation.md b/packages/animations/docs/utilities/isMotionAnimation.md
new file mode 100644
index 00000000..ef8921a1
--- /dev/null
+++ b/packages/animations/docs/utilities/isMotionAnimation.md
@@ -0,0 +1,72 @@
+# isMotionAnimation
+
+`isMotionAnimation` can be used to check if a style key is considered a motion animation, i.e.: `translateX`, `left`, `right`, etc...
+
+## Syntax
+
+```js
+function isMotionAnimation(property: ViewStyle): boolean {}
+```
+
+| Property | Description |
+| -------- | --------------------- |
+| property | The property to check |
+
+## Example
+
+```tsx
+import * as React from 'react';
+import { StyleSheet, View } from 'react-native';
+import {
+ isMotionAnimation,
+ useAMAContext,
+ useAccessibleAnimationDuration,
+} from 'react-native-ama';
+import Animated, {
+ useAnimatedStyle,
+ useSharedValue,
+ withSpring,
+ withTiming,
+} from 'react-native-reanimated';
+
+export const ReanimatedReduceMotionScreen = () => {
+ const { getAnimationDuration } = useAccessibleAnimationDuration();
+ const { isReduceMotionEnabled } = useAMAContext();
+ const value = useSharedValue(0);
+
+ const animatedStyles = useAnimatedStyle(() => {
+ return {
+ transform: [{ translateX: value.value * 255 }],
+ };
+ });
+
+ const testWithSpring = () => {
+ const to = Math.random();
+
+ value.value =
+ isReduceMotionEnabled && isMotionAnimation('translateX')
+ ? withTiming(to, { duration: 0 })
+ : withSpring(to);
+ };
+
+ return (
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ view: {
+ paddingHorizontal: 24,
+ },
+ box: {
+ width: 100,
+ height: 100,
+ borderRadius: 20,
+ backgroundColor: 'red',
+ },
+});
+```