├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── assets ├── loader1.gif ├── loader2.gif └── loader3.gif ├── index.d.ts ├── package-lock.json ├── package.json ├── readme.md └── src ├── index.js └── loader.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: vikrantnegi 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # 10 | issuehunt: # 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p12 6 | *.key 7 | *.mobileprovision 8 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Vikrant Negi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /assets/loader1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrantnegi/react-native-animated-loader/3098f0faff593cfe11d5938f9be538782414e3cd/assets/loader1.gif -------------------------------------------------------------------------------- /assets/loader2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrantnegi/react-native-animated-loader/3098f0faff593cfe11d5938f9be538782414e3cd/assets/loader2.gif -------------------------------------------------------------------------------- /assets/loader3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrantnegi/react-native-animated-loader/3098f0faff593cfe11d5938f9be538782414e3cd/assets/loader3.gif -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export type AnimatedLoaderProps = { 2 | /** 3 | * Controls the visibility of the loader. 4 | * @defaultValue false 5 | */ 6 | visible?: boolean 7 | 8 | /** 9 | * Changes the color of the overlay. 10 | */ 11 | overlayColor?: string 12 | 13 | /** 14 | * The source of animation. Can be referenced as a local asset by a string, or remotely with an object with a uri property, or it can be an actual JS object of an animation, obtained (for example) with something like `require('../path/to/animation.json')`. 15 | */ 16 | source: object | string | { uri: string } 17 | 18 | /** 19 | * The speed the animation will progress. 20 | * @defaultValue 1 21 | */ 22 | speed?: number 23 | 24 | /** 25 | * A boolean flag indicating whether or not the animation should loop. 26 | * @defaultValue true 27 | */ 28 | loop?: boolean 29 | 30 | /** 31 | * Changes animation on show and hide loader's view. 32 | */ 33 | animationType?: any 34 | 35 | /** 36 | * The style to be applied to the Lottie. 37 | */ 38 | animationStyle?: import('react-native').StyleProp< 39 | import('react-native').ViewStyle 40 | > 41 | } 42 | 43 | export default function AnimatedLoader( 44 | props: AnimatedLoaderProps 45 | ): JSX.Element 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-animated-loader", 3 | "version": "1.0.0", 4 | "description": "Useful to show lottie animation spinners in react-native mobile apps", 5 | "main": "src/index.js", 6 | "files": [ 7 | "src" 8 | ], 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "dependencies": { 13 | "prop-types": "^15.6.2" 14 | }, 15 | "peerDependencies": { 16 | "react": "*", 17 | "react-native": ">=0.46", 18 | "lottie-react-native": ">=3.0.0", 19 | "deprecated-react-native-prop-types": "^2.3.0" 20 | }, 21 | "author": "Vikrant Negi", 22 | "license": "MIT", 23 | "keywords": [ 24 | "react-native", 25 | "react-component", 26 | "react-native-loader", 27 | "lottie-react-native", 28 | "react-native-progress", 29 | "lottie", 30 | "modals", 31 | "loaders", 32 | "animations", 33 | "ios", 34 | "android", 35 | "spinners" 36 | ], 37 | "homepage": "https://github.com/vikrantnegi/react-native-animated-loader", 38 | "bugs": { 39 | "url": "https://github.com/vikrantnegi/react-native-animated-loader/issues" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "https://github.com/vikrantnegi/react-native-animated-loader.git" 44 | } 45 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # React Native Animated Loader 2 | 3 | Read more about this package [here](https://www.freecodecamp.org/news/how-to-create-a-beautifully-animated-loader-in-react-native-21da37a8f6b0/). 4 | 5 | [![downloads](https://img.shields.io/npm/dt/react-native-animated-loader.svg)](http://npm-stats.com/~packages/react-native-animated-loader) 6 | [![npm-version](https://img.shields.io/npm/v/react-native-animated-loader.svg)](https://www.npmjs.com/package/react-native-animated-loader) 7 | [![github-tag](https://img.shields.io/github/tag/vikrantnegi/react-native-animated-loader.svg?maxAge=1800)](https://github.com/vikrantnegi/react-native-animated-loader/) 8 | [![license](https://img.shields.io/github/license/vikrantnegi/react-native-animated-loader.svg?maxAge=1800)](https://yarnpkg.com/en/package/react-native-animated-loader) 9 | 10 | A React Native Loader Component which uses Airbnb's [Lottie](https://github.com/react-native-community/lottie-react-native) for beautiful loader animations. 11 | 12 |    13 |    14 | 15 | 16 | 17 | ## Prerequisites 18 | ### Using React Native CLI 19 | This library uses [lottie-react-native](https://github.com/react-native-community/lottie-react-native) to render loader animations. Therefore this library need to be installed and linked to your project before installing this package. 20 | 21 | Follow the official instruction and linking guide [here](https://github.com/react-native-community/lottie-react-native/blob/master/README.md#getting-started). 22 | 23 | ### Using Expo 24 | No need to do anything specific, just install the package itself. Expo already has Lottie library API available and it will take care of the rest. 25 | 26 | ## Install 27 | 28 | ``` 29 | yarn add react-native-animated-loader 30 | ``` 31 | or 32 | ``` 33 | npm install react-native-animated-loader --save 34 | ``` 35 | 36 | ## Usage 37 | ### Class Component 38 | ```jsx 39 | import React from 'react'; 40 | import { StyleSheet,Text } from 'react-native'; 41 | import AnimatedLoader from "react-native-animated-loader"; 42 | 43 | export default class Loader extends React.Component { 44 | constructor(props) { 45 | super(props); 46 | this.state = { visible: false }; 47 | } 48 | 49 | componentDidMount() { 50 | setInterval(() => { 51 | this.setState({ 52 | visible: !this.state.visible 53 | }); 54 | }, 2000); 55 | } 56 | 57 | render() { 58 | const { visible } = this.state; 59 | return ( 60 | 67 | Doing something... 68 | 69 | ); 70 | } 71 | } 72 | 73 | const styles = StyleSheet.create({ 74 | lottie: { 75 | width: 100, 76 | height: 100 77 | } 78 | }); 79 | ``` 80 | ### Functional Component 81 | 82 | ```jsx 83 | import React, {useState, useEffect} from 'react'; 84 | import {StyleSheet, Text} from 'react-native'; 85 | import AnimatedLoader from 'react-native-animated-loader'; 86 | export default function App() { 87 | const [visible, setVisible] = useState(false); 88 | useEffect(() => { 89 | setInterval(() => { 90 | setVisible(!visible); 91 | }, 2000); 92 | }, []); 93 | 94 | return ( 95 | 100 | Doing something... 101 | 102 | ); 103 | } 104 | const styles = StyleSheet.create({ 105 | lottie: { 106 | width: 100, 107 | height: 100, 108 | }, 109 | }); 110 | 111 | ``` 112 | 113 | ### Usage in Expo 114 | [Example for expo projects](https://snack.expo.dev/tTSGEcb5J) 115 | 116 | ### Loader files 117 | 118 | You can find free lottie files for your loaders [here](https://lottiefiles.com/search?q=loader). 119 | 120 | ## Props 121 | 122 | | Prop | Description | Default | 123 | |---|---|---| 124 | |**`source`**| The source of animation. Can be referenced as a local asset by a string, or remotely with an object with a `uri` property, or it can be an actual JS object of an animation, obtained (for example) with something like `require('../path/to/animation.json')`. | [Lottie Object](https://lottiefiles.com/1531-loader) | 125 | |**`visible`**| Controls the visibility of the loader. | `false` | 126 | |**`overlayColor`**| Changes the color of the overlay. | `rgba(255,255,255,0.75)` | 127 | |**`animationStyle`**| The style to be applied to the Lottie. | - | 128 | |**`animationType`**| Changes animation on show and hide loader's view. | `none` | 129 | |**`speed`**| The speed the animation will progress. | `1` | 130 | |**`loop`**| A boolean flag indicating whether or not the animation should loop. | `true` | 131 | 132 | ## Work in Progress 133 | - [x] Add expo example 134 | - [ ] Add ability to render text with animations 135 | - [ ] Add test cases 136 | 137 | ## License 138 | Licensed under the [MIT](https://github.com/vikrantnegi/react-native-animated-loader/blob/master/LICENSE). 139 | 140 | ## Donation 141 | If this project helped you reduce time to develop, please consider buying me a cup of coffee :) 142 | 143 | Buy Me A Coffee 144 | 145 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/E1E6Z0JL) 146 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, View, Modal } from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import LottieAnimation from 'lottie-react-native'; 5 | import { ViewPropTypes } from 'deprecated-react-native-prop-types'; 6 | 7 | export default class AnimatedLoader extends React.PureComponent { 8 | static defaultProps = { 9 | visible: false, 10 | overlayColor: 'rgba(0, 0, 0, 0.25)', 11 | animationType: 'none', 12 | source: require('./loader.json'), 13 | animationStyle: {}, 14 | speed: 1, 15 | loop: true, 16 | }; 17 | 18 | static propTypes = { 19 | visible: PropTypes.bool, 20 | overlayColor: PropTypes.string, 21 | animationType: PropTypes.oneOf(['none', 'slide', 'fade']), 22 | source: PropTypes.object, 23 | animationStyle: ViewPropTypes.style, 24 | speed: PropTypes.number, 25 | loop: PropTypes.bool, 26 | }; 27 | 28 | animation = React.createRef(); 29 | 30 | componentDidMount() { 31 | if (this.animation.current) { 32 | this.animation.current.play(); 33 | } 34 | } 35 | 36 | componentDidUpdate(prevProps) { 37 | const { visible } = this.props; 38 | if (visible !== prevProps.visible) { 39 | if (this.animation.current) { 40 | this.animation.current.play(); 41 | } 42 | } 43 | } 44 | 45 | _renderLottie = () => { 46 | const { source, animationStyle, speed, loop } = this.props; 47 | return ( 48 | 55 | ); 56 | }; 57 | 58 | render() { 59 | const { visible, overlayColor, animationType } = this.props; 60 | 61 | return ( 62 | {}} 68 | > 69 | 70 | {this._renderLottie()} 71 | {this.props.children} 72 | 73 | 74 | ); 75 | } 76 | } 77 | 78 | const styles = StyleSheet.create({ 79 | container: { 80 | flex: 1, 81 | backgroundColor: 'transparent', 82 | position: 'absolute', 83 | top: 0, 84 | bottom: 0, 85 | left: 0, 86 | right: 0, 87 | alignItems: 'center', 88 | justifyContent: 'center', 89 | }, 90 | animationStyle: { 91 | height: '100%', 92 | width: '100%', 93 | }, 94 | }); 95 | -------------------------------------------------------------------------------- /src/loader.json: -------------------------------------------------------------------------------- 1 | {"v":"5.1.7","fr":30,"ip":0,"op":50,"w":80,"h":80,"nm":"loader","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"color01b","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2},"a":{"a":0,"k":[-19,-8.286,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":30,"s":[0,0,100],"e":[100,100,100]},{"t":50}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[80,80],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.266666995778,0.266666995778,0.266666995778,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.294117647059,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-19,-8.286],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":50,"st":30,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"color01a","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":25,"s":[100],"e":[0]},{"t":45}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2},"a":{"a":0,"k":[-19,-8.286,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":25,"s":[0,0,100],"e":[100,100,100]},{"t":45}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[80,80],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.266666995778,0.266666995778,0.266666995778,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.294117647059,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-19,-8.286],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":25,"op":50,"st":25,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"color01","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2},"a":{"a":0,"k":[-19,-8.286,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":0,"s":[100,100,100],"e":[0,0,100]},{"t":20}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[80,80],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.266666995778,0.266666995778,0.266666995778,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.294117647059,0.2,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-19,-8.286],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"color02","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2},"a":{"a":0,"k":[-19,-8.286,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":5,"s":[100,100,100],"e":[0,0,100]},{"t":25}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[80,80],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.266666995778,0.266666995778,0.266666995778,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.380392156863,0.298039215686,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-19,-8.286],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"color03","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[40,40,0],"ix":2},"a":{"a":0,"k":[-19,-8.286,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_1_0p333_0"],"t":10,"s":[100,100,100],"e":[10,10,100]},{"t":30}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[80,80],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.266666995778,0.266666995778,0.266666995778,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.513725490196,0.450980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-19,-8.286],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} --------------------------------------------------------------------------------